# Animation Authoring Blacksite's first production animation path supports skinned glTF 2.0 models (`.gltf` and `.glb`). It normalizes imported rig and clip metadata into generated manifests, keeps authored scene data independent of Bevy's runtime graph/player components, and uses the same controller contract in editor preview, PIE, and standalone builds. ## Import And Placement Place animated sources under `assets/` and refresh or reimport them from the Asset Browser. The registry writes `assets/animations/generated/.animation.ron` beside the existing static mesh artifact. Expanding a model row shows: - skeleton entries with joint count and signature summary; - animation clips with duration and event count; - mesh, material, and texture entries from the static import contract. Skeleton rows are inspect-only. Dragging an animation clip into the viewport creates one `ImportedModel` actor with a stable `ModelRef` and `AnimationControllerDesc` and selects it for immediate inspection. When an imported-model actor is selected, the same drag assigns the clip as a new controller state instead. Assignment is one undoable command and requires an exact skeleton-signature match. Skinned primitive rows are inspect-only because their vertex data requires the source skin hierarchy. Their thumbnails render the complete source scene, and drag/place actions direct authors to place the model or an animation clip instead of creating an invalid detached mesh. ## Controller Inspector The Animation Controller component exposes the selected skeleton, default crossfade, named states, default state, clip, loop, speed, and optional playback range. State IDs are gameplay keys and must be non-empty and unique; labels are presentation only. Component add, remove, reset, copy, paste, and property changes use typed editor history and participate in scene dirty tracking. The Preview section selects a state, plays or pauses it, stops playback, and scrubs within the authored range. Preview requests use the game runtime adapter and do not change the controller, history, or scene dirty state. Entering PIE clears any paused edit-mode scrub so the authored default state can run; leaving PIE clears transient playback while retaining authored data. ## Runtime API Gameplay changes state by sending a validated request through `game::animation`: ```rust game::animation::request_animation_state( world, game::animation::AnimationStateRequest::new(actor, "run").with_crossfade(0.15), )?; ``` An omitted crossfade uses the controller default. Invalid actor or state requests return an error and preserve current playback. If edited controller data cannot rebuild its runtime graph, the old graph is stopped and cleared instead of continuing stale playback. `AnimationGraph`, `AnimationPlayer`, transitions, preview state, and hydrated model roots are runtime-only and never serialize into authored scenes. ## Stable Identity And Moves `ModelRef`, skeleton references, and clip references carry the model registry UUID. Generated artifacts are keyed by that UUID; source paths are cached resolution and repair hints. When one model is moved or renamed on disk, catalog refresh reconciles it by its animation-manifest content hash, preserves the UUID, and regenerates both manifests with the new source path. An identical copy is not treated as a move while the original still exists. Ambiguous content matches intentionally receive a new identity rather than silently binding the wrong asset. Legacy path-only `ModelRef` values remain readable and use their cached path. Reassign or replace a legacy model actor to opt it into stable move resolution. Skeleton compatibility hashes the exact Bevy 0.19 glTF node-name segments and bind poses, including whitespace and slash characters. The readable joint paths shown by the editor are deliberately not used as identity. Animation-manifest schema v1 artifacts must be reimported to generate schema v2 signatures. ## Validation And Format Boundary Interactive diagnostics and `cargo validate-levels` resolve registry UUIDs, generated manifests, stable subasset IDs, source dependencies, default/state IDs, playback ranges, speeds, crossfades, runtime format support, exact source-content fingerprints, and exact rig compatibility. Findings identify the owning actor and controller property and include a repair action. Packaging includes the same source files and generated artifacts checked by validation. FBX remains supported for static model import only. An FBX containing skin deformers or animation stacks emits a blocking diagnostic directing the author to convert it to glTF. Animation v1 does not support one glTF asset containing animation channels under multiple top-level roots, because Bevy creates a separate `AnimationPlayer` for each root. Split those rigs into separate assets or export them beneath one common root. Animation v1 also does not provide implicit retargeting, blend trees, a visual state graph, root motion, IK, or motion matching. See [ADR 0031](../adr/0031-animation-authoring-runtime-contract.md) for the persistent/runtime boundary and [the working implementation plan](../../.cursor/plans/animation_authoring_2026-07-11.plan.md) for acceptance gates.