XState animation metadata format
VGAI Reference 0.3
Planned versioned generated-schema truth covering Native XState animation state machines and blend trees, Masked and additive animation layers.
planned · generated · immutable Reference 0.3
Lifecycle and constraints
Detailed constraints will publish with the generated or reviewed entry.
Runnable Learn material
- Build the Solo Combat Loop
- Technical Artist
- Animation, blending, masks, retargeting, IK, and attachments
- Game Animation Sample
- Third-Person Action
Generated format inventory
Inventory only — AC-REF-002 is not passed. Valid parser-verified examples, narrative guidance, complete cross-field/runtime constraints, and version history remain deferred. This page must not be treated as a complete format contract.
Source: packages/engine/src/animation/xstate-animation-meta.ts ·
57 branch-sensitive field records ·
38 source-described.
StateAnimationMeta · state-meta · 57 fields
| Field / branch | Type | Required | Default | Constraints | Description |
|---|---|---|---|---|---|
# $ | anyOf (2) | yes | none | none | Missing source description |
# $anyOf[0] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.clipanyOf[0] | string | yes | none | {"minLength":1} | Single clip to play while this XState state is active |
# $.loopanyOf[0] | boolean | yes | true | none | Loop the clip (THREE.LoopRepeat) vs play once (THREE.LoopOnce, clamped on last frame) |
# $.speedanyOf[0] | number | yes | 1 | {"exclusiveMinimum":0} | Playback speed multiplier (AnimationAction.timeScale) |
# $.crossfadeanyOf[0] | object | no | none | {"additionalProperties":false} | Blend-in/out/crossfade timing for entering this state |
# $.crossfade.durationanyOf[0] | number | yes | 0 | {"minimum":0} | Seconds to blend from the previously active clip into this state on entry, applied via native `AnimationAction.crossFadeTo`/`fadeIn` (E2). 0 = instant activation, no fade. |
# $.crossfade.warpanyOf[0] | boolean | yes | false | none | Passed through to AnimationAction.crossFadeTo's `warp` param — linearly warps timeScale across the two clips during the blend so differing clip lengths line up. Default false. |
# $.layeranyOf[0] | string | no | none | {"minLength":1} | Composition layer name; omitted means the single base layer |
# $.weightanyOf[0] | number | no | none | {"minimum":0,"maximum":1} | Layer weight multiplier from 0 to 1; defaults to 1 |
# $.blendModeanyOf[0] | enum (2) | no | none | {"enum":["override","additive"]} | Native Three normal/override or additive action blending; defaults to override |
# $.boneMaskanyOf[0] | object | no | none | {"additionalProperties":false} | Optional include/exclude filter applied to every clip track in this state |
# $.boneMask.includeanyOf[0] | array | no | none | {"minItems":1} | Bone/object names whose complete descendant subtrees are retained |
# $.boneMask.include[]anyOf[0] | string | yes | none | {"minLength":1} | Missing source description |
# $.boneMask.excludeanyOf[0] | array | no | none | {"minItems":1} | Bone/object names whose complete descendant subtrees are removed |
# $.boneMask.exclude[]anyOf[0] | string | yes | none | {"minLength":1} | Missing source description |
# $anyOf[1] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTreeanyOf[1] | oneOf (3) | yes | none | none | Multiple clips blended by a live context/selector-driven parameter |
# $.blendTreeanyOf[1] oneOf[0] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.typeanyOf[1] oneOf[0] | const "1D" | yes | none | {"const":"1D"} | Interpolates linearly between sorted children by threshold |
# $.blendTree.parameteranyOf[1] oneOf[0] | string | yes | none | {"minLength":1} | Context/selector value driving the blend |
# $.blendTree.childrenanyOf[1] oneOf[0] | array | yes | none | {"minItems":2} | Missing source description |
# $.blendTree.children[]anyOf[1] oneOf[0] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.children[].clipanyOf[1] oneOf[0] | string | yes | none | {"minLength":1} | Animation clip name this child plays |
# $.blendTree.children[].thresholdanyOf[1] oneOf[0] | number | yes | none | none | 1D/2D blend position on the primary parameter axis |
# $.blendTree.children[].thresholdYanyOf[1] oneOf[0] | number | no | none | none | 2D blend position on the secondary parameter axis (2D blend trees only) |
# $.blendTree.children[].weightanyOf[1] oneOf[0] | number | no | none | {"minimum":0} | Explicit weight for "direct" blend trees (ignored by 1D/2D) |
# $.blendTreeanyOf[1] oneOf[1] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.typeanyOf[1] oneOf[1] | const "2D" | yes | none | {"const":"2D"} | Inverse-distance-weights children by (parameter, parameterY) position |
# $.blendTree.parameteranyOf[1] oneOf[1] | string | yes | none | {"minLength":1} | Primary axis context/selector value |
# $.blendTree.parameterYanyOf[1] oneOf[1] | string | yes | none | {"minLength":1} | Secondary axis context/selector value |
# $.blendTree.childrenanyOf[1] oneOf[1] | array | yes | none | {"minItems":1} | Missing source description |
# $.blendTree.children[]anyOf[1] oneOf[1] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.children[].clipanyOf[1] oneOf[1] | string | yes | none | {"minLength":1} | Animation clip name this child plays |
# $.blendTree.children[].thresholdanyOf[1] oneOf[1] | number | yes | none | none | 1D/2D blend position on the primary parameter axis |
# $.blendTree.children[].thresholdYanyOf[1] oneOf[1] | number | yes | none | none | Missing source description |
# $.blendTree.children[].weightanyOf[1] oneOf[1] | number | no | none | {"minimum":0} | Explicit weight for "direct" blend trees (ignored by 1D/2D) |
# $.blendTreeanyOf[1] oneOf[2] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.typeanyOf[1] oneOf[2] | const "direct" | yes | none | {"const":"direct"} | Each child has an explicit weight, normalized to sum to 1 |
# $.blendTree.parameteranyOf[1] oneOf[2] | string | yes | "" | none | Missing source description |
# $.blendTree.childrenanyOf[1] oneOf[2] | array | yes | none | {"minItems":1} | Missing source description |
# $.blendTree.children[]anyOf[1] oneOf[2] | object | yes | none | {"additionalProperties":false} | Missing source description |
# $.blendTree.children[].clipanyOf[1] oneOf[2] | string | yes | none | {"minLength":1} | Animation clip name this child plays |
# $.blendTree.children[].thresholdanyOf[1] oneOf[2] | number | yes | none | none | 1D/2D blend position on the primary parameter axis |
# $.blendTree.children[].thresholdYanyOf[1] oneOf[2] | number | no | none | none | 2D blend position on the secondary parameter axis (2D blend trees only) |
# $.blendTree.children[].weightanyOf[1] oneOf[2] | number | yes | none | {"minimum":0} | Missing source description |
# $.crossfadeanyOf[1] | object | no | none | {"additionalProperties":false} | Blend-in/out/crossfade timing for entering this state |
# $.crossfade.durationanyOf[1] | number | yes | 0 | {"minimum":0} | Seconds to blend from the previously active clip into this state on entry, applied via native `AnimationAction.crossFadeTo`/`fadeIn` (E2). 0 = instant activation, no fade. |
# $.crossfade.warpanyOf[1] | boolean | yes | false | none | Passed through to AnimationAction.crossFadeTo's `warp` param — linearly warps timeScale across the two clips during the blend so differing clip lengths line up. Default false. |
# $.layeranyOf[1] | string | no | none | {"minLength":1} | Composition layer name; omitted means the single base layer |
# $.weightanyOf[1] | number | no | none | {"minimum":0,"maximum":1} | Layer weight multiplier from 0 to 1; defaults to 1 |
# $.blendModeanyOf[1] | enum (2) | no | none | {"enum":["override","additive"]} | Native Three normal/override or additive action blending; defaults to override |
# $.boneMaskanyOf[1] | object | no | none | {"additionalProperties":false} | Optional include/exclude filter applied to every clip track in this state |
# $.boneMask.includeanyOf[1] | array | no | none | {"minItems":1} | Bone/object names whose complete descendant subtrees are retained |
# $.boneMask.include[]anyOf[1] | string | yes | none | {"minLength":1} | Missing source description |
# $.boneMask.excludeanyOf[1] | array | no | none | {"minItems":1} | Bone/object names whose complete descendant subtrees are removed |
# $.boneMask.exclude[]anyOf[1] | string | yes | none | {"minLength":1} | Missing source description |