Three.js From Zero · Article s3-10
The Full Character Rig
The Full Character Rig
Season 3 finale. Every technique from S3-01 through S3-09 stacked into one character: skeleton with morphs (S3-01, S3-02), blend tree for locomotion (S3-03), IK for hand-reach and foot-plant (S3-04), procedural secondary motion (S3-05), physics-driven hit reactions (S3-06), motion-matched clip selection (S3-07), pipeline-imported animations (S3-08), facial-capture driving (S3-09).
The demo is a character cycling through four states — idle, walk, reach (IK), hit (physics). You can see which layer contributes to which bone. It's a complete game-ready character loop in one HTML file.
The rig pipeline in one picture
Per frame, for each bone, in order:
1. BASE POSE ← AnimationMixer output (keyframe or blend tree)
2. + FACIAL ← morph targets (camera or preset)
3. + IK OVERRIDE ← hand-reach, foot-plant (specific bones only)
4. + PROCEDURAL ← spring-damper (tail, breath, head-bob)
5. = RENDERED POSE
When RAGDOLL state is active:
Skip 1-4; read bone positions directly from physics bodies.
On BLEND state: lerp ragdoll pose → animated pose over ~1s.
Every layer owns specific bones or specific channels (rotation vs translation vs scale). Conflicts resolved by order — later layers override earlier ones.
Layer ownership matrix
| Bone group | Owner (by state) |
|---|---|
| Spine, pelvis, legs | Mixer (locomotion blend tree) |
| Feet | IK (foot plant on terrain) overrides mixer |
| Arms & hands | Mixer (default) OR IK (if reach target set) |
| Fingers | Mixer for gestures, IK for grabbing props |
| Head, neck | Mixer + spring damper (head-bob) + look-at (target-attention) |
| Face (morphs) | Facial capture driver or preset |
| Tail, hair, cloak | Procedural (spring-damper / Verlet) |
The evaluation loop
function updateCharacter(dt) {
// 1. Physics state transitions
if (wantsRagdoll) {
state = 'ragdoll';
seedBodiesFromBones();
mixer.stopAllAction();
return;
}
if (state === 'ragdoll') {
syncBonesFromBodies();
if (ragdollSettled()) startBlendBack();
return;
}
if (state === 'blending') {
mixer.update(dt);
lerpBonesFromCapturedRagdoll(blendProgress);
if (blendProgress >= 1) state = 'anim';
return;
}
// state === 'anim' — the normal pipeline
// 2. Locomotion blend tree — sets most bones
updateLocomotionBlend(speed, strafe);
mixer.update(dt);
// 3. Facial — runs independently, only affects head morphs
updateFacialCapture(dt);
// 4. IK — runs AFTER mixer, overrides specific bones
if (reachTarget) solveArmIK(reachTarget);
solveFootIK();
updateLookAt(focusTarget);
// 5. Procedural — runs LAST, adds secondary motion
updateBreathing(t);
updateTailSpring(dt);
updateHeadBob(dt);
}
State machine driving the rig
ANIM ──[take damage]────→ RAGDOLL ──[settled]──→ BLENDING ──[done]──→ ANIM
│ ↑
├──[reach button]─→ starts IK on arm, keeps ANIM ─┘
├──[move input]──→ updates locomotion axis
└──[face cam on]─→ starts FacialCapture driver
Only RAGDOLL takes over fully. All other "modes" (reaching, walking, smiling) are additive layers on top of ANIM. That's what makes the rig flexible — the character keeps walking while reaching while smiling while getting tail-wagged.
Order matters
The evaluation order above is the canonical pipeline. A common bug is running procedural before IK — the spring stores a target based on pre-IK pose, then IK moves the arm, and next frame the spring yanks the arm back. Layers must run in the order you want them composed.
Networked characters
S2-08 multiplayer meets S3 rigs. Don't serialize every bone every frame — too heavy. Send input + state:
{
pos: [x, y, z],
rot: [yaw],
state: 'anim',
locomotion: { speed: 0.7, strafe: 0.0 },
reachTarget: null,
facialBlendshapes: [52 × int8], // quantized to save bandwidth
ragdollImpulse: null,
}
Remote clients reconstruct the full pose from these inputs. ~50 bytes per character per tick. Scales to 100 networked characters easily.
Performance — what costs what
| Layer | Cost per character |
|---|---|
| Mixer update | ~0.1 ms |
| Foot IK (2 legs, CCDIK) | ~0.3 ms |
| Arm IK (two-bone) | ~0.1 ms |
| Procedural tail (10 joints) | ~0.05 ms |
| Ragdoll physics (Rapier, 10 bodies) | ~0.2 ms |
| FacialCapture (MediaPipe) | ~15 ms (runs separately, not per-character) |
For 60fps, ~0.8 ms per character all-in. Budget: 30+ fully-rigged characters at 60 fps per frame budget (excluding rendering).
Common first-time integration bugs
- IK pops when blend-back ends. IK target frame of reference changed (ragdoll → anim). Transition target smoothly.
- Foot slides when turning. Foot IK is solving per-frame but your root motion doesn't match blend-tree output. Apply root-motion delta consistently.
- Head-bob fights IK neck-look. Spring target for head-bob includes IK rotation → spring fights itself. Give head-bob its own bone (or run BEFORE look-at IK).
- Character flickers between clips at low speed. Blend tree is swapping Idle ↔ Walk too aggressively. Add hysteresis (different thresholds for enter vs exit).
- Facial capture pose interferes with "cutscene" face animation. During cutscenes, disable the cam driver. Layer-based authority.
- Ragdoll activates during a critical action (jump). Add invincibility frames or exit-conditions from dynamic states.
What you just built
Starting from S3-01's cylinder-with-bones, you now have the full real-time 3D character stack. This is what you'd ship in:
- A browser-based MMO or social app
- A WebGL game
- A virtual-avatar video chat
- An AR/VR experience (S2-05, S2-06)
- A 3D customer-support chatbot with live lip sync
- A motion-capture demo / portfolio site
Every piece is standards-based, runs in any modern browser, and doesn't require a game engine. You can build shippable products with only what Season 3 teaches.
Exercises — integration challenges
- Record & playback: serialize a character's state every 100ms to JSON, replay exactly on reload. Tests that all layers deterministically compose.
- Multi-character scene: 10 copies of the rig in one scene, all animating. Find the performance breaking point on your machine.
- Mix + match pipelines: pull Mixamo clips (S3-08), drive face with MediaPipe (S3-09), physics hits from S2-03. Confirm layers stay consistent.
What's next — Season 4
Graphics Deep Dive. PBR from the math up. Advanced lighting, shadow techniques, SSR, volumetric fog, subsurface scattering, hair, ocean, NPR. PhD-level rendering with working demos.