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

108 lines
6.2 KiB
Markdown

# Skeletal Animation Import, Preview, And Authoring
> **Historical plan — not current implementation guidance.** Use the [documentation index](../../docs/README.md) for current behavior and architecture.
Working implementation plan for Gitea issue
[`#46`](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/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.