"Ragdoll a scripted-rig NPC with pure engine physics"
You want an NPC to crumple / faint / get hit without authoring collapse animation clips. Per-bone C# posing looks tempting and then explodes (see setbonetransform-silently-noop). Limbs float disconnected while the torso ragdolls (see bone-name-dot-to-underscore).
Ragdoll for a scripted-rig character is engine physics, not clip authoring and not SetBoneTransform.
You put a PhysicsShapeList + PhysicsJointList in the vmdl (capsule per major bone + joints). Sandbox.ModelPhysics builds one physics body per bone, simulates them, and writes results back onto the SkinnedModelRenderer's bones.
1. Author physics nodes in the vmdl
Copy schema from citizen prefabs:
addons/citizen/Assets/models/citizen/prefabs/citizen_physics{shape,joint}list.vmdl_prefabTwo nodes under RootNode children:
PhysicsShapeList→ children = capsules (PhysicsShapeCapsule)PhysicsJointList→ children = joints
Capsule fields: parent_bone, surface_prop="flesh", collision_tags="solid", radius, point0, point1 (capsule axis in the bone's local frame). For bones that run down local +X: point0 ≈ [r/2,0,0] … point1 ≈ [len−r/2,0,0].
Joints name bodies by bone name via parent_body / child_body:
PhysicsJointConical(ballsocket) — spine/neck/head/shoulder/hip
(enable_swing_limit/swing_limit, twist limits,friction)PhysicsJointRevolute(hinge) — elbows & knees
(enable_limit/min_angle/max_angle)
anchor_origin = pivot in the parent body's local frame = child bone head ≈ [parent_len, 0, 0].
Every joint's parent and child must have a shape or the body floats disconnected — give the neck a body; it bridges chest→head.
Units: physics shape coords are in the same unit as mesh+bones BEFORE ModelModifier_ScaleAndMirror. For a meters→cm FBX lane that means centimetres; the vmdl's ModelModifier_ScaleAndMirror 0.3937 scales physics with mesh+anims. Citizen proof: radius 10.0 = 10 cm pelvis capsule alongside the same 0.3937 modifier. Do not pre-scale capsules to inches.
Bone names in physics KV3: sanitize Blender .L/.R → _L/_R — see bone-name-dot-to-underscore.
2. Toggle at runtime
var physics = Components.GetOrCreate<ModelPhysics>();
physics.Renderer = skinned; // SkinnedModelRenderer
physics.Model = skinned.Model; // same physics-bearing vmdl
physics.Enabled = true;
physics.MotionEnabled = true;
// shove
foreach (var body in physics.PhysicsGroup.Bodies)
body.ApplyImpulse(impulse);
// stand back up
physics.Destroy(); // bone control returns to Sequence next frame
// snap root to pelvis body rest (Bodies[0].Position), typically x/y onlyMembers ModelPhysics.{Renderer,Model,MotionEnabled,Enabled,PhysicsGroup} and PhysicsBody.ApplyImpulse / Position resolve under dotnet build. Note: the type may not enumerate via reflection GetTypes() (native registration) — trust the compiler.
Radii as a fraction of each bone's length (+ abs clamps) scale with proportions better than hardcoded human dims. Generous swing/twist limits with identity anchor_angles can read as a crumple while you tune axes. (needs verification) for your exact bone-length table — copy citizen, then tune.
ModelPhysics is the engine's bind between ModelDoc physics bodies and a skinned pose. Once capsules/joints exist on the compiled model, enabling the component hands bone control to the physics world and writes simulated transforms back each tick — which is exactly what a ragdoll is. Collapse clips become unnecessary; SetBoneTransform never enters the picture.