Builds a skeleton over bones (§85-validated: non-empty, no duplicate
bone, every entry a Bone) with inverseBindMatrices (16 finite
floats per bone; identity per bone when omitted).
The bone array is copied (so later edits to the caller's array cannot silently re-skin a mesh); the matrices are held by reference, like geometry attributes — they are bind-pose data a loader hands over whole.
OptionalinverseBindMatrices: Float32Array<ArrayBufferLike>ReadonlybonesThe joints, in joint-index order. Insertion order is the ABI (§33): entry
i is what joints[4 * v + k] === i refers to, for every vertex v.
ReadonlyinverseOne column-major inverse bind matrix per bone — 16 floats each, index-parallel with Skeleton.bones. Bind-pose data authored with the rig; the engine never writes into it. Defaults to the identity per bone, which is correct for a rig whose bind pose is the rest pose of its nodes expressed in the skin root's frame.
ReadonlyjointThe palette: 16 floats per bone, rewritten in place by every
Skeleton.update. palette[i] = inverse(skinRootWorld) · bones[i].worldMatrix · inverseBind[i] — exactly what a skinned vertex
stage consumes, in the layout uniformMatrix4fv uploads.
Identity per bone until the first update, so a palette uploaded before
one draws the bind pose rather than garbage.
Number of joints — bones.length, named for the palette's consumers.
Rewrites Skeleton.jointMatrices from the bones' current world
matrices, relative to skinRoot — the mesh node whose worldMatrix the
vertex stage applies after the palette, so the palette must be expressed
in its frame:
palette[i] = inverse(skinRootWorld) · bones[i].worldMatrix · inverseBind[i]
Deterministic (§33): bones are visited in insertion order, the two
products associate left-to-right, and world matrices come from worldOf
when provided, otherwise from the same resolveWorldTransform every other
node uses — version-cached, so after the frame's resolve pass each read is
a few comparisons. Allocates nothing (§7b: module scratch).
worldOf is how §43 interpolation reaches the palette without writing
interpolated poses back into node.transform (§42): the render list
supplies a provider that composes interpolated local poses the same way
node world matrices are composed. The provider is used for both the
skin root and every bone. The palette itself is never lerped — local
poses interpolate, then this product runs. A returned matrix is copied
immediately, so the provider may reuse one scratch across calls.
Degenerate input follows the engine's transform policy rather than
throwing on a per-frame path (§85, Matrix4.invert): a skinRoot whose
world matrix is exactly singular (a zero scale somewhere up its chain) has
no inverse, invert() leaves its input unchanged, and the palette that
frame is well-defined arithmetic over a wrong matrix — finite, visible,
and gone the moment the scale is. Nothing is written anywhere else.
A rig: an ordered set of Bones, their inverse bind matrices, and the joint-matrix palette derived from them every frame (§54; RFC 0003 §1b).
Joint index = position in Skeleton.bones — the ABI (§33)
A geometry's
jointsattribute indexes this array, a §17 skeletal-joint track addresses a bone asbones.<i>.transform.<channel>, and Skeleton.update walks it in insertion order. Reordering the array is therefore re-skinning the mesh; the array isreadonlyso it cannot happen by accident.The palette is derived state, never an authority input (§42; RFC 0003 §4)
updatereads bone world matrices (resolved, or a caller-suppliedworldOfthat composes interpolated poses) and writes only into Skeleton.jointMatrices; nothing reads the palette back into a transform. This is §43's "render interpolation never feeds back into physics state" applied one level down, and it is what keeps a ragdoll's §19"blended"bones ordinary nodes with ordinary authorities.Not a
Node, not a componentA skeleton is shared state about nodes — several meshes may skin against one rig — so it is a plain object referenced by
Mesh.skeleton(§54), exactly as aBufferGeometryis referenced byRenderable.geometry. In a §79 document it is written inline on the mesh as bone ids plus the inverse bind matrices (intra-file references are by id, §79), and resolved against the reloaded bones on first read — see@fourjs/render'sMesh.