Skip to content

Skeletal Animation

This document describes Three.js's skeletal animation system, which enables realistic character animation through hierarchical bone structures and vertex skinning. The system consists of three primary components: Skeleton hierarchies for defining bone transforms, SkinnedMesh for applying deformations to geometry, and AnimationMixer for controlling animation playback.

For basic 3D object transformation and hierarchy, see Scene Graph & Object3D. For morph target animation (an alternative to skeletal animation), see the geometry system documentation Geometry System. For loading animated models from external formats, see GLTF Import & Export.


Core Architecture

The skeletal animation system operates through a pipeline of transforms: bones define a hierarchy of coordinate spaces, the skeleton computes combined bone matrices, and the skinned mesh applies these matrices to deform vertices on the GPU.

Class Relationships

SVG
100%

Diagram: Core skeletal animation classes and their relationships

Skeleton Hierarchy

Bone Class

The Bone class is a specialized Object3D that serves as a node in a skeletal hierarchy. It contains no additional logic beyond standard transformation properties.

SVG
100%

Diagram: Example bone hierarchy for a humanoid character

PropertyTypeDescription
typestringAlways set to "Bone"
isBonebooleanType flag, always true

All transformation capabilities (position, rotation, scale, matrix operations) are inherited from Object3D.

Skeleton Class

The Skeleton class manages a collection of bones and computes the final transformation matrices needed for vertex skinning.

|--------------|----------------|---------------------------------------------------------------| | bones | Array<Bone> | Flat array of all bones in the skeleton | | boneInverses | Array<Matrix4> | Inverse bind pose matrices for each bone | | boneMatrices | Float32Array | Flattened array of 16 floats per bone for GPU upload |

| boneTexture | DataTexture | Optional texture containing bone matrices for large skeletons |

Key Methods:

SVG
100%

Diagram: Skeleton matrix computation pipeline

SkinnedMesh and Vertex Deformation

SkinnedMesh extends Mesh to add skeletal deformation capabilities. Each vertex is influenced by up to 4 bones, with the final position computed as a weighted blend of bone transformations.

Core Properties

PropertyTypeDescription
skeletonSkeletonThe skeleton controlling this mesh
bindModestringEither AttachedBindMode or DetachedBindMode
bindMatrixMatrix4Transform from mesh space to bind pose space
bindMatrixInverseMatrix4Inverse of bindMatrix

Required Geometry Attributes

AttributeTypeDescription
skinIndexBufferAttributeBone indices (typically 4 per vertex)
skinWeightBufferAttributeBone weights (typically 4 per vertex, normalized)

Skinning Mathematics

The vertex deformation formula implemented in shaders:

transformedPosition = Σ(weight[i] × bone[index[i]] × originalPosition)

For each vertex:

  1. Retrieve 4 bone indices and weights from attributes
  2. For each bone influence, transform the vertex position by that bone's matrix
  3. Multiply by the corresponding weight
  4. Sum all weighted contributions
SVG
100%

Diagram: Multi-bone vertex skinning computation

CPU-Side Methods

SkinnedMesh provides CPU-side methods for computing skinned positions, used primarily for raycasting and bounding volume computation:

These methods read skinIndex and skinWeight attributes and manually compute the weighted blend transformation.

Bind Modes

Bind modes control how the skeleton's bind pose relates to the mesh's coordinate space. This affects the computation of final bone matrices.

AttachedBindMode

Default mode where the mesh and skeleton share the same coordinate space. The skeleton's root bone is typically a child of the mesh.

SVG
100%

Diagram: AttachedBindMode hierarchy

DetachedBindMode

The skeleton exists independently from the mesh. Requires explicit bindMatrix and bindMatrixInverse to transform between spaces.

SVG
100%

Diagram: DetachedBindMode hierarchy

Bind Mode Comparison

AspectAttachedBindModeDetachedBindMode
Skeleton parentChild of SkinnedMeshIndependent in scene
bindMatrix usageIdentity matrixRequired for coordinate transform
Typical use caseCharacter modelsShared skeleton across multiple meshes
Matrix formulamatrixWorld × boneInversebindMatrixInverse × matrixWorld × boneInverse

The bind mode is set via the bind(skeleton, bindMatrix) method src/objects/SkinnedMesh.js120-150

Animation Playback System

The animation system consists of AnimationClip (keyframe data), AnimationMixer (playback controller), and AnimationAction (per-clip playback state).

Architecture

SVG
100%

Diagram: Animation system architecture

AnimationClip Structure

An AnimationClip contains an array of KeyframeTrack objects, each targeting a specific property on a specific object:

SVG
100%

Diagram: AnimationClip composition

Track Types and Property Paths

Track ClassData TypeTypical UseExample Path
VectorKeyframeTrackVector3Position, scale.bones[3].position
QuaternionKeyframeTrackQuaternionRotation.bones[5].quaternion
NumberKeyframeTracknumberMorph weights, scalar props.morphTargetInfluences[0]

Property paths use PropertyBinding syntax to resolve targets on the root object examples/jsm/loaders/GLTFLoader.js3200-3300

AnimationMixer Usage Pattern

// Setup
const mixer = new AnimationMixer(skinnedMesh);
const action = mixer.clipAction(animationClip);
action.play();

// Animation loop
function animate() {
    const delta = clock.getDelta();
    mixer.update(delta);  // Updates all active actions
    renderer.render(scene, camera);
}

The mixer's update(deltaTime) method:

  1. Advances playback time for all active actions
  2. Interpolates keyframe values based on current time
  3. Applies interpolated values to target properties via PropertyBinding
  4. Handles blending between multiple animations

Loading Skeletal Animations

GLTF Loader Integration

The GLTFLoader handles complete skeletal animation import, including skeleton creation, skinning setup, and animation clip construction.

SVG
100%

Diagram: GLTF skeletal animation loading pipeline

Key Loader Methods

MethodPurposeSource
loadSkin(skinIndex)Creates Skeleton from glTF skin definitionexamples/jsm/loaders/GLTFLoader.js2800-2900
loadAnimation(animationIndex)Creates AnimationClip from glTF animationexamples/jsm/loaders/GLTFLoader.js3100-3300
assignFinalMaterial(mesh)Upgrades Mesh to SkinnedMesh if neededexamples/jsm/loaders/GLTFLoader.js2200-2300

The loader automatically:

  • Converts glTF node hierarchy to Bone objects
  • Reads inverseBindMatrices accessor data
  • Creates skinIndex and skinWeight buffer attributes
  • Builds KeyframeTrack objects from animation samplers
  • Resolves animation channel targets to property paths

Exporting Skeletal Animations

GLTF Exporter Integration

The GLTFExporter serializes Three.js skeletal animations back to glTF format.

SVG
100%

Diagram: GLTF skeletal animation export pipeline

Key Exporter Methods

MethodPurposeSource
processSkin(object)Exports skeleton and inverse bind matricesexamples/jsm/exporters/GLTFExporter.js1900-2100
processNode(object)Exports bone transforms to nodes arrayexamples/jsm/exporters/GLTFExporter.js1600-1800
processAnimation(clip)Converts AnimationClip to glTF animationexamples/jsm/exporters/GLTFExporter.js2300-2600

The exporter handles:

  • Building skin definitions with joint indices
  • Writing inverse bind matrices to buffer accessors
  • Converting KeyframeTrack data to glTF samplers
  • Resolving property paths to channel targets
  • Supporting both AttachedBindMode and DetachedBindMode

Performance Considerations

Bone Texture Mode

For skeletons with many bones (>64), Three.js can encode bone matrices into a DataTexture for more efficient GPU upload:

SVG
100%

Diagram: Bone texture optimization for large skeletons

The texture is created automatically when skeleton.update() is called if the bone count exceeds the uniform limit src/objects/Skeleton.js155-200

Weight Normalization

The normalizeSkinWeights() method ensures that skin weights sum to 1.0 for each vertex, preventing visual artifacts:

skinnedMesh.normalizeSkinWeights();  // Call after modifying skinWeight attribute

This iterates through all vertices and normalizes the 4-component weight vectors src/objects/SkinnedMesh.js160-180

Bounding Volume Updates

SkinnedMesh provides methods to compute accurate bounding volumes that account for bone deformations:

These are expensive operations that should be called sparingly, ideally only when the animation significantly changes the mesh extents.