12 KiB
Requirements Document
Introduction
This feature adds animation playback support for imported GLB/GLTF model assets in the browser-based 3D scene editor. Animations embedded in GLB/GLTF files are already detected and stored in ModelAssetMetadata.animationNames during import. This slice surfaces those animation names in the editor UI, allows authors to configure a default animation clip per model instance, wires playAnimation and stopAnimation actions into the existing Trigger → Action → Target interaction system, drives playback in the runtime via three.js AnimationMixer, and persists all animation settings through save/load with a schema version bump and migration.
The scope is deliberately narrow: no timeline editor, no blend trees, no cross-fade authoring. The goal is a minimal, explicit, and correct first pass.
Glossary
- AnimationClip: A named animation track embedded in a GLB/GLTF file, identified by its string name as stored in
ModelAssetMetadata.animationNames. - AnimationMixer: The three.js
AnimationMixerobject that drivesAnimationClipplayback on a scene object. - ModelInstance: A placed scene instance of an imported model asset, stored in
SceneDocument.modelInstances, separate from entities. - ModelAssetMetadata: Canonical metadata extracted from a GLB/GLTF file at import time, including
animationNames: string[]. - InteractionLink: A typed Trigger → Action → Target record stored in
SceneDocument.interactionLinks. - PlayAnimationAction: A new
InteractionActiontype that targets a model instance and names a clip to play. - StopAnimationAction: A new
InteractionActiontype that targets a model instance and stops its active animation. - RuntimeAnimationState: Per-instance runtime state tracking the active
AnimationMixerand currentAnimationAction. - Document: The canonical editor state (
SceneDocument), independent of three.js scene graph objects. - Runner: The browser runtime that loads and plays scenes.
- Command: An undoable state transition applied to the Document.
Requirements
Requirement 1: Animation Metadata Availability
User Story: As an author, I want to see which animation clips are available on an imported model, so that I can make informed decisions when configuring animation playback.
Acceptance Criteria
- THE
ModelAssetMetadataSHALL contain ananimationNamesfield of typestring[]that lists every animation clip name extracted from the imported GLB/GLTF file. - WHEN a GLB/GLTF file containing zero named animations is imported, THE
ModelAssetMetadataSHALL store an emptyanimationNamesarray. - WHEN a GLB/GLTF file containing one or more animations is imported, THE
ModelAssetMetadataSHALL store each animation name exactly once, sorted lexicographically. - WHEN an animation clip has an empty or whitespace-only name, THE importer SHALL substitute a fallback name of the form
"Animation N"where N is the one-based index of the clip. - THE
migrateSceneDocumentfunction SHALL correctly read and validate theanimationNamesfield when loading documents of version 12 or later.
Requirement 2: Model Instance Animation Configuration
User Story: As an author, I want to configure a default animation clip and autoplay setting on a model instance, so that the model plays the right animation when the scene starts.
Acceptance Criteria
- THE
ModelInstancedocument type SHALL include an optionalanimationClipNamefield of typestring | undefinedthat names the clip to play by default. - THE
ModelInstancedocument type SHALL include an optionalanimationAutoplayfield of typeboolean | undefinedthat controls whether the clip starts playing automatically when the runner loads the scene. - WHEN
animationClipNameis set to a non-empty string, THE Runner SHALL use that clip name to look up theAnimationClipin the loaded GLTF animations array. - WHEN
animationClipNameisundefinedor empty, THE Runner SHALL not start any animation automatically for that model instance. - WHEN
animationAutoplayistrueandanimationClipNameis set, THE Runner SHALL begin playing the named clip immediately when the scene loads, looping continuously. - WHEN
animationAutoplayisfalseorundefined, THE Runner SHALL not autoplay any animation for that model instance on scene load. - THE
createModelInstancefactory function SHALL acceptanimationClipNameandanimationAutoplayas optional fields and include them in the returnedModelInstance. - THE
cloneModelInstancefunction SHALL copyanimationClipNameandanimationAutoplayfaithfully. - THE
areModelInstancesEqualfunction SHALL includeanimationClipNameandanimationAutoplayin its equality check.
Requirement 3: Interaction System — Play Animation Action
User Story: As an author, I want to wire a trigger to play a specific animation clip on a model instance, so that animations can be activated by player interaction or zone entry.
Acceptance Criteria
- THE
InteractionActionunion SHALL include aPlayAnimationActiontype with fieldstype: "playAnimation",targetModelInstanceId: string, andclipName: string. - WHEN a
playAnimationaction is dispatched, THE Runner SHALL locate the model instance bytargetModelInstanceIdand start playing the clip namedclipName, looping continuously. - WHEN a
playAnimationaction targets a model instance whose loaded asset does not contain a clip matchingclipName, THE Runner SHALL log a warning and take no further action. - WHEN a
playAnimationaction targets a model instance that is not present in the runtime scene, THE Runner SHALL log a warning and take no further action. - THE
createPlayAnimationInteractionLinkfactory function SHALL validate thatsourceEntityId,targetModelInstanceId, andclipNameare all non-empty strings. - THE
RuntimeInteractionDispatcherinterface SHALL include aplayAnimation(instanceId: string, clipName: string, link: InteractionLink): voidmethod.
Requirement 4: Interaction System — Stop Animation Action
User Story: As an author, I want to wire a trigger to stop the animation on a model instance, so that animations can be halted by player interaction or zone exit.
Acceptance Criteria
- THE
InteractionActionunion SHALL include aStopAnimationActiontype with fieldstype: "stopAnimation"andtargetModelInstanceId: string. - WHEN a
stopAnimationaction is dispatched, THE Runner SHALL locate the model instance bytargetModelInstanceIdand stop any currently playing animation, leaving the model in its stopped pose. - WHEN a
stopAnimationaction targets a model instance with no active animation, THE Runner SHALL take no action and produce no error. - WHEN a
stopAnimationaction targets a model instance that is not present in the runtime scene, THE Runner SHALL log a warning and take no further action. - THE
createStopAnimationInteractionLinkfactory function SHALL validate thatsourceEntityIdandtargetModelInstanceIdare both non-empty strings. - THE
RuntimeInteractionDispatcherinterface SHALL include astopAnimation(instanceId: string, link: InteractionLink): voidmethod.
Requirement 5: Runtime Animation Playback
User Story: As a player, I want model animations to play smoothly in the runner, so that the scene feels alive and responsive.
Acceptance Criteria
- WHEN the Runner loads a scene, THE
RuntimeHostSHALL create oneAnimationMixerper model instance that has a loaded GLTF asset with at least one animation clip. - WHEN the Runner's per-frame
renderloop executes, THERuntimeHostSHALL callmixer.update(dt)for every activeAnimationMixer, wheredtis the elapsed time in seconds since the previous frame. - WHEN a model instance is removed from the scene or the scene is reloaded, THE
RuntimeHostSHALL stop and dispose of the associatedAnimationMixer. - WHEN
animationAutoplayistrueandanimationClipNameis set on a model instance, THERuntimeHostSHALL start the named clip playing on scene load before the first rendered frame. - WHEN a
playAnimationaction is dispatched for a model instance that already has an active animation, THERuntimeHostSHALL stop the current animation and start the new clip. - THE
RuntimeModelInstanceruntime data type SHALL includeanimationClipName: string | undefinedandanimationAutoplay: boolean | undefinedso the runner can act on them without re-reading the document.
Requirement 6: Inspector UI — Animation Configuration
User Story: As an author, I want to configure animation settings on a selected model instance in the inspector panel, so that I can set up autoplay and default clips without editing JSON.
Acceptance Criteria
- WHEN a model instance is selected and its asset has at least one animation clip, THE Inspector SHALL display an animation section showing the list of available clip names from
ModelAssetMetadata.animationNames. - WHEN a model instance is selected and its asset has zero animation clips, THE Inspector SHALL not display an animation section.
- WHEN the author selects a clip name from the animation section, THE Inspector SHALL dispatch an
UpsertModelInstanceCommandthat setsanimationClipNameon the model instance. - WHEN the author toggles the autoplay checkbox, THE Inspector SHALL dispatch an
UpsertModelInstanceCommandthat setsanimationAutoplayon the model instance. - WHEN the author clears the clip selection, THE Inspector SHALL dispatch an
UpsertModelInstanceCommandthat setsanimationClipNametoundefined. - THE Inspector animation section SHALL reflect the current
animationClipNameandanimationAutoplayvalues from the selected model instance.
Requirement 7: Interaction Link UI — Animation Actions
User Story: As an author, I want to create play/stop animation interaction links in the interaction panel, so that I can connect triggers to animation actions.
Acceptance Criteria
- WHEN the author creates a new interaction link and selects the
playAnimationaction type, THE Interaction Panel SHALL display fields for selecting the target model instance and entering or selecting the clip name. - WHEN the author creates a new interaction link and selects the
stopAnimationaction type, THE Interaction Panel SHALL display a field for selecting the target model instance. - WHEN the author saves a
playAnimationlink, THE Panel SHALL dispatch anUpsertInteractionLinkCommandwith a validPlayAnimationAction. - WHEN the author saves a
stopAnimationlink, THE Panel SHALL dispatch anUpsertInteractionLinkCommandwith a validStopAnimationAction. - WHEN an existing
playAnimationorstopAnimationlink is displayed in the interaction panel, THE Panel SHALL show the resolved model instance name and clip name.
Requirement 8: Persistence — Schema Migration
User Story: As an author, I want my scenes to load correctly after the animation feature is added, so that existing work is not lost.
Acceptance Criteria
- THE
SCENE_DOCUMENT_VERSIONconstant SHALL be incremented to12to reflect the addition of animation fields. - WHEN
migrateSceneDocumentreads a document at version11, THE migration SHALL produce a valid version-12document withanimationClipName: undefinedandanimationAutoplay: undefinedon every existing model instance. - WHEN
migrateSceneDocumentreads a document at version12, THE migration SHALL read and validateanimationClipNameandanimationAutoplayon each model instance, acceptingundefinedor valid string/boolean values respectively. - WHEN
migrateSceneDocumentreads a document at version12containing aplayAnimationorstopAnimationinteraction link, THE migration SHALL read and validate the action fields correctly. - THE
migrateSceneDocumentfunction SHALL reject a version-12document where aplayAnimationaction has an emptyclipNamestring. - THE serialization round-trip (serialize then deserialize) SHALL produce a document equal to the original for any valid version-
12document containing animation fields.