A limb is T-posed, or a bone never moves
One arm hangs out sideways while the rest of the body animates, a socket is missing on the target rig, or the whole character deforms as if it were authored on somebody else's skeleton.
Checks: missing-bones ·
required-bones ·
frozen-bone ·
bind-pose
Why it happens
A bone can fail in four ways that all look alike in the engine: it is absent from the skeleton, it is present but carries no keys, it carries keys that never move it, or it moves relative to a bind pose that was not this rig's. A presence-only check passes the third case, and a motion-only check passes a socket that is meant to be static. What separates them is a declaration: which bones the clip is supposed to animate, and which must simply exist.
What AnimSmith measures
The synthetic walk below is declared to animate both arms. arm_l is keyed at
five identical values, and arm_r never reached the file at all. The report
plays back the exact frames the checks judged, so the still arm is visible in
the pose grid rather than inferred from the message.
Open the interactive report to scrub
the cycle and watch the left arm stay where it started; it opens on the
frozen-bone finding that names it.
What the finding looks like
$ animsmith --config examples/walk-frozen-arm.animsmith.toml lint examples/assets/walk-frozen-arm.glb
examples/assets/walk-frozen-arm.glb:
error[missing-bones] clip 'walk_frozen_arm' bone 'arm_r': required bone does not exist in the skeleton
error[frozen-bone] clip 'walk_frozen_arm' bone 'arm_l': required bone rotates only 0.00° over the clip (floor 1.00°) — frozen/T-posed limb or a wrong-source slice (measured 0.0000, expected 1.0000)
note[constant-track] clip 'walk_frozen_arm' bone 'arm_l': rotation track has 5 keys but never moves — export bloat
coverage[bind-pose] insufficient_rotation_evidence ×1 (scopes: first_frame_rest_delta; subjects: walk_frozen_arm): only 1 usable first-frame rotation track(s); at least three are required
2 error(s), 0 warning(s), 1 note(s), 1 coverage gap(s), 0 available prediction facet(s), 0 required-unavailable prediction facet(s) # exits 1
Without the declaration only the mechanical note survives. Nothing in the file says the arms were supposed to move, so nothing in the file can be wrong about it:
$ animsmith lint examples/assets/walk-frozen-arm.glb
examples/assets/walk-frozen-arm.glb:
note[constant-track] clip 'walk_frozen_arm' bone 'arm_l': rotation track has 5 keys but never moves — export bloat
coverage[bind-pose] insufficient_rotation_evidence ×1 (scopes: first_frame_rest_delta; subjects: walk_frozen_arm): only 1 usable first-frame rotation track(s); at least three are required
0 error(s), 0 warning(s), 1 note(s), 1 coverage gap(s), 0 available prediction facet(s), 0 required-unavailable prediction facet(s) # exits 0
What to do
- Declare what the clip must animate.
animates_bonesturns a silently static limb into a failing gate. It matches bone names, not rig roles, so it needs no profile. - Declare what must merely exist. Sockets, IK targets and mask bones are
intentionally static, so they belong in
[rig] required_bonesrather than in a per-clip motion rule. - Missing bone: repair the source rig. AnimSmith does not create bones, rename an export, or retarget a rig. Fix the export skeleton in the DCC and re-export.
- Keyed but frozen: find the slice that dropped it. A masked-out channel, a wrong-source slice, or a bake that never ran leaves keys that go nowhere.
- Wide bind deviation: check which rig it was authored against. A clip whose first frame is far from this skeleton's rest pose was almost certainly authored against a different bind and will deform incorrectly when retargeted onto this one.
Who fixes it: the artist repairs the source rig. AnimSmith reports structural absence, declared motion that never happened, and a first frame far from rest; target binding, Avatar/Skeleton setup and masks are engine work. The gate closes when a re-export meets the structural contract and the required bones visibly move on the target character.
Config
# Bones this clip must animate. Both checks match names, not roles.
[clips.walk_frozen_arm]
animates_bones = ["arm_l", "arm_r"]
[rig]
# Bones that must exist even though nothing is expected to move them.
required_bones = ["root", "weapon_socket", "ik_hand_l"]
[checks.frozen-bone]
# Real motion moves required bones tens of degrees; the default floor catches
# a truly static bone without flagging subtle idle sway.
min_rotation_deg = 1.0
Precise contract: the four rig-integrity failures, and what each one refuses to guess
Four related rig-integrity failures, in increasing subtlety:
-
A structural rig bone is absent or ambiguous. Runtime sockets, IK targets, mask bones, and attachment points can be intentionally static, so they do not belong in a per-clip motion rule. Put their exact names in
[rig] required_bones = ["weapon_socket", "ik_hand_l"].required-bonespasses a present static bone, errors for a missing name, and refuses to guess if duplicate skeleton names make the declaration ambiguous. It also reports an empty or absent skeleton as unable to meet a nonempty structural contract. This check does not create bones, rename an export, retarget a rig, or validate engine-side socket use: repair the source rig in the DCC and re-export. -
A declared bone is missing entirely. Bones the clip is declared to animate (via
animates_bonesin the config) must exist in the skeleton and carry at least one keyframed track. Themissing-bonescheck catches slices that accidentally dropped a channel — leaving a limb static — and exports against the wrong rig. -
A bone has keys but never moves. A required bone whose rotation never exceeds a floor is frozen: a T-posed limb, a wrong-source slice, or a masked-out channel that a presence-only check would pass. Real motion moves required bones tens of degrees; the
frozen-bonecheck's default 1° floor catches truly static bones without flagging subtle idle sway. -
The clip was authored against a different bind. A clip whose first frame deviates wildly from the skeleton's rest pose was almost certainly authored against a different bind — wrong seed rig, wrong export skeleton — and will deform incorrectly when retargeted onto this one. Small deviations are normal (few clips start exactly at rest); the
bind-posecheck fires only on a large mean deviation across the animated bones.
The checks' prerequisites, configuration keys and gap semantics are listed with every other check in the built-in check reference.