Blacksite/.cursor/plans/animation_authoring_2026-07-11.plan.md

6.2 KiB

Skeletal Animation Import, Preview, And Authoring

Historical plan — not current implementation guidance. Use the documentation index for current behavior and architecture.

Working implementation plan for Gitea issue #46. This is the minimum production animation loop required by the M7 content-production milestone.

Status

Implementation and production acceptance are complete. The persistent/runtime contract, generated manifest, stable model/clip identity, runtime adapter, browser drag workflow, typed inspector, and headless validation are implemented. Live acceptance covers import, placement, preview, scrub, save/reload hydration, PIE playback, source relocation, development packaging, and standalone runtime playback with the committed RobotExpressive fixture.

Outcome

An author can import a supported skinned model, inspect its skeleton and clips, place an animated actor, preview and scrub a clip without dirtying the scene, save a small named state set, and drive the same state changes in PIE and a packaged game. Missing content and skeleton mismatches fail with owner-attributed repair guidance before packaging.

Format Policy

  • Animation authoring v1 supports glTF 2.0 (.gltf and .glb) through Bevy's native scene, skinning, and animation assets.
  • FBX remains supported for the existing static mesh import path. An FBX containing animation stacks or skin deformers is not a supported animated source and must produce a blocking, actionable diagnostic.
  • Animated FBX support cannot be enabled until the loader constructs the source hierarchy, Bevy skinned-mesh bindings, and AnimationClip assets. Metadata counts alone do not qualify as support.

Architecture

  • The asset registry UUID remains the parent model identity. A generated animation manifest under assets/animations/generated/ records the source fingerprint, skeleton signatures, stable clip sub-asset IDs, clip metadata, and animation events.
  • shared::AnimationControllerDesc is reflected and serializable. It references imported skeletons and clips through stable EditorAssetRef values and owns one layer of named states, a default state, playback range/loop/speed, and default crossfade duration.
  • game owns the runtime adapter. It waits for the model WorldAssetRoot instance to become ready, attaches transient animation graph/player state, and exposes a request API for changing an actor's named state.
  • editor owns import presentation, clip/skeleton shelves, drag assignment/placement, inspector controls, and non-dirty preview/scrubbing. Preview uses the runtime adapter rather than a separate interpretation of the authored contract.
  • scene and package validation resolve the same manifests and stable references used by editor and runtime hydration.

Authoritative Data

The generated manifest is keyed by the model's stable registry UUID and includes:

  • schema version and source path/fingerprint;
  • scenes and exact skeleton signatures;
  • stable skeleton and clip sub-asset IDs;
  • clip label, source index, duration, target skeleton signature, and event markers;
  • import diagnostics, including unsupported animated FBX content.

An exact skeleton signature is a deterministic hash of normalized ordered joint target paths and bind-pose structure. Retargeting v1 accepts only an exact signature match. No implicit joint-name, humanoid, or proportional remapping is allowed.

Implementation Sequence

  1. Add the versioned animation manifest schema, stable sub-asset identity rules, glTF extraction, FBX blocking diagnostics, and focused importer tests.
  2. Add AnimationControllerDesc, named state/event types, registration, migration defaults, actor validation, history snapshots, scene round-trip coverage, and runtime-only strip policy.
  3. Replace broad imported-model child cleanup with a dedicated generated instance root, then hydrate the ready scene instance into a transient graph/player and implement the game state-request API.
  4. Extend Asset Browser model shelves with skeleton and clip rows, compatibility status, preview, scrub/range/loop controls, and clip drag placement or assignment.
  5. Add the typed Animation Controller inspector, undoable state edits, PIE pause/stop reconciliation, owner-attributed project validation, and package dependency collection.
  6. Commit a small redistributable animated GLB and sample scene, then run import, round-trip, headless, live editor/PIE, and packaged-runtime acceptance.

Acceptance Gates

  • A committed skinned GLB and its clips import, preview, save, hydrate, and play in PIE and a packaged runtime.
  • Moving or renaming the source inside the project preserves controller clip references through the registry UUID and stable sub-asset IDs.
  • Missing manifests/clips and mismatched skeleton signatures produce actor/property-attributed diagnostics with a concrete repair action.
  • Gameplay can request a valid named state through the public game API; invalid requests leave the current state intact and report a diagnostic.
  • Preview follows the authored loop/range/speed settings, stops cleanly, and never mutates the scene descriptor, history, or dirty state.
  • Generated graph/player/instance components never serialize into authored scenes, and model rehydration never deletes authored hierarchy children.
  • Animated or skinned FBX content blocks animation import with a diagnostic that explains the glTF v1 requirement.
  • Focused importer, validation, hydration, request-API, and editor operator tests pass alongside workspace tests, cargo validate-levels, package validation, and live smoke testing.

Deliberate Boundaries

  • V1 provides one animation layer with named states, one default state, and a default crossfade. It does not include a visual state graph, blend trees, transition-condition authoring, inverse kinematics, motion matching, or root-motion extraction.
  • Event markers are normalized data and runtime notifications; V1 has no timeline scripting system.
  • Retargeting is exact signature match only.
  • FBX static mesh import remains available, but animated FBX conversion is separate loader work and cannot silently fall back to bind-pose or metadata-only playback.