---
title: "Pitfalls: animation & rigs"
slug: /workflows/pitfalls-animation/
markdown: /workflows/pitfalls-animation.md
section: pitfalls
tier: 2
summary: "One driver per Animator, culled poses, masks."
sources: ['pitfalls/animation.md']
canonical: https://unityworkflowlibrary.dev/workflows/pitfalls-animation/
read_first: /read-first.md
---

> Read first, on every prompt: [non-destructive rules](/read-first.md).

# Pitfalls: animation & rigs

> One driver per Animator, culled poses, masks.

Generalized pitfalls from shipped and active projects. Record your own project's traps the same way: [Keeping a project pitfall file](/workflows/pitfall-file/). All entries LOCKED evidence. Status: locked (empirical, seen in shipped/active projects).

- **ONE-LOCOMOTION-DRIVER — two scripts writing the same Animator parameters stack silently.** Why: no ownership of the parameter set. Check: one component owns each Animator parameter; grep for every `SetFloat/SetBool` on it. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (ONE-LOCOMOTION-DRIVER): Creature prefabs ran an old driver in LateUpdate and a new one in Update; the later write won, so tuning the new driver changed nothing.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **REGENERATE-CONTROLLERS-IN-PLACE — rebuilding an AnimatorController with delete+create gives it a new GUID and breaks every prefab reference.** Why: references are by GUID. Check: generators clear and refill the existing asset; a test asserts the GUID is unchanged. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (REGENERATE-CONTROLLERS-IN-PLACE): A generator deleted and recreated controllers; prefabs lost their controller.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **CULLED-ANIMATORS-DO-NOT-POSE — with `CullUpdateTransforms` an off-screen Animator writes no bones, so headless/off-camera checks read rest pose.** Why: the correct runtime culling mode skips transform writes when not visible. Check: verify animation with the subject in view, or temporarily set `AlwaysAnimate` in the test only. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (CULLED-ANIMATORS-DO-NOT-POSE): Verification of animation from a script saw no bone motion for creatures outside the view.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **VERIFY-MOTION-NOT-PARAMETERS — "parameters are live" is not "the character animates".** Why: the check read inputs, not the pose. Check: assert bone transforms change across frames (or a still from a running clip). See also FEATURE-DUE-DILIGENCE. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (VERIFY-MOTION-NOT-PARAMETERS): A handoff passed because layer weights and parameters changed while the rig stood frozen.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **DISCARDED-ROOT-MOTION-SWAYS — discarding root motion with the default humanoid root reference leaves a rigid stride-frequency counter-sway.** Why: the clip's root motion was baked into the body instead of the root. Check: set the clip's root transform bake options (rotation/Y/XZ "Bake Into Pose" with the right basis) when root motion is discarded. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (DISCARDED-ROOT-MOTION-SWAYS): Walking characters swayed side to side at stride frequency.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **ANIM-SPEED-FROM-OBSERVED-VELOCITY — on networked clients, drive locomotion speed from the observed transform velocity, not a replicated command.** Why: the replicated intent and the interpolated position disagree in time. Check: client animation speed = smoothed delta position of the drawn transform. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (ANIM-SPEED-FROM-OBSERVED-VELOCITY): Interpolated units kept running after the server stopped them (or slid before the anim started).
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **REPLICATE-CAUSES-NOT-EFFECTS — replicate gameplay signals (state flags, target), never look direction, layer weights, clip times or bones.** Why: effects are deterministic from causes. Check: ghost/NetworkVariable fields on animated units are only gameplay signals. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (REPLICATE-CAUSES-NOT-EFFECTS): Bandwidth and jitter from replicating presentation values that each client can derive.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **ONE-SHOTS-ARE-EDGE-TRIGGERS — fire attack/one-shot triggers on the rising edge of a replicated flag, priming the baseline on first sight.** Why: level-triggered firing and stale triggers. Check: holds use bools, one-shots use triggers set on edge only; first observation primes without firing. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (ONE-SHOTS-ARE-EDGE-TRIGGERS): Units spawned mid-fight played a false attack, and triggers left set looped attacks forever.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **HUMANOID-MASKS-ON-OPTIMIZED-SKELETONS-ARE-EMPTY — on optimized (flattened) skeletons, humanoid body-part masks bake to zero bones.** Why: only transform-based avatar masks survive optimization. Check: use transform avatar masks with optimized skeletons. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (HUMANOID-MASKS-ON-OPTIMIZED-SKELETONS-ARE-EMPTY): Masked layers did nothing / meshes vanished.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **NO-REBIND-ON-MODULAR-RIGS — `Animator.Rebind` on a modular optimized rig snaps each attached SkinnedMeshRenderer to its raw import bind.** Why: rebind re-resolved bindings against the import pose. Check: never call Rebind on modular characters; rebuild the character instead. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (NO-REBIND-ON-MODULAR-RIGS): Modular arms and weapons detached/deformed after a rebind.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **THROTTLE-SKINNED-SPAWNS — instantiating many skinned characters in one frame can stall or crash the GPU driver.** Why: skin/skeleton init cost landed in one frame. Check: cap new skinned instances per frame (single digits) and queue the rest. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (THROTTLE-SKINNED-SPAWNS): A wave spawning dozens of skinned units in one frame caused a GPU timeout/device loss.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **PREVIEW-GRAPH-MUST-STAY-ALIVE — destroying a PlayableGraph/AnimationMode preview snaps a humanoid back to rest pose.** Why: the pose exists only while the graph samples. Check: keep the graph alive through the capture; re-sample after domain reload. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (PREVIEW-GRAPH-MUST-STAY-ALIVE): Editor stills captured a T-pose because the preview graph was disposed before capture (DontSave previews also die on recompile).
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **IMPORT-SCALE-LEAKS-INTO-THE-AVATAR — an avatar created while the model had a wrong import scale keeps that scale's units.** Why: `CreateFromThisModel` captured positions at the old scale. Check: fix scale first, then (re)create the avatar; compare a known bone length. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (IMPORT-SCALE-LEAKS-INTO-THE-AVATAR): After fixing a model's import scale, the humanoid description still stored inch-scale offsets; animations played distorted.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

- **SKIN-HAT-GEOMETRY-TO-THE-HEAD — nearest-bone auto-skinning assigns wide head attachments (caps, brims, horns) to the shoulders.** Why: nearest-segment binding picks clavicle/upper-arm for verts at shoulder width. Check: weight extra-cranial geometry 100% to the head; normalizing total height must exclude it. Status: locked (empirical, seen in shipped/active projects).

> **Why this rule exists** (SKIN-HAT-GEOMETRY-TO-THE-HEAD): Arm animation squashed a wide hat.
> *Source: Pitfall log of a shipped or active Unity project, generalized.*

