Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bevy 0.19.0 animation profile

Use this page for the exact bevy / 0.19.0 / gltf-asset-loader profiles. Revision 1 owns animation-label addressability. Revision 2 owns the unit/effective-scale prediction substrate and its version-pinned load settings. Revision 3 is the current slice for animation/channel gate support and the separately versioned rich addressability-rule bundle. All three accept glTF JSON and GLB only; none applies to a later Bevy release.

What Bevy expects

Bevy loads glTF subassets through typed labels. In 0.19.0, GltfAssetLabel::Animation(index) formats as Animation{index}. An animation name is separate optional metadata, not part of that typed selector. Runtime playback still requires the relevant animation feature/settings, loaded assets, an AnimationPlayer, targets, and an animation graph or equivalent application setup.

The frozen profile also records that animation target ids are derived from name paths. Revision 3's separately versioned rich addressability bundle emits bounded predictions for those paths, named-map winners, scene/skin labels, and the optional default-scene route. It does not emit graph templates, extension support, or proof that a runtime asset exists.

AnimSmith checks and thresholds

Check idExact boundaryBevy-facing use
engine-addressabilityno numeric tolerance; exactly one Animation{i} facet per completely inventoried source animationPredicts the canonical typed label spelling from source order. Partial inventory produces one unsuppressible required-unavailable inventory facet.
engine-unit-scaleexact revision-2 profile facts and settings; no tolerance and no content findingEmits exact 1:1 glTF-metre to Bevy world-length-unit mapping plus distinct loader-scene, primitive-child, and selected-source-node affine classifications. Missing required evidence is unsuppressible required-unavailable.
engine-track-supportexact revision-3 gate settings and bounded same-load animation/channel inventory; no content findingEmits only negative gate outcomes for source animation/channel rows, or required-unavailable evidence when inventory is incomplete or both gates allow loading. Extensions, other constructs, and positive runtime survival are outside this slice.
engine-addressability (rich V2)exact revision-3 Bevy addressability-rule bundle; no numeric tolerance or content findingEmits typed scene, default-scene, skin/IBM, named-map, and target path/UUID projections beside the unchanged Animation{i} facets. Incomplete, unreachable, multiply reachable, feature-disabled, or colliding work is required-unavailable.
rest-world-scaleselected node factor 1.0 ± 0.0001 inclusiveFinds authored inherited scale at attachment/IK nodes; it does not predict Bevy's imported result.
scale-keyscomponent range greater than 1e-4Finds animated scale before runtime transform propagation.
non-uniform-scalerelative spread greater than 1e-4Flags possible shear/attachment/physics consequences in composed transforms.
loop-closure0.01 m and 1.0°Checks declared loops before graph playback.
in-placeXZ speed at least 0.5 m/s counts as travellingMakes gameplay versus animation movement ownership explicit.

The rest of the check catalog is unchanged by the profile.

For scale, #267 owns the measurement domains and #268 owns the selected-node finding. The #155 import-advice work has no Bevy payload. Static placement baking #224 and skinned rest/bind reparameterization #269 remain separate from selector generation.

Configure and generate selectors

[engine]
profile = "bevy"
profile_revision = 1
engine_version = "0.19.0"
importer = "gltf-asset-loader"

[runtime_nodes]
selectors = ["weapon_socket", "ik_*_target"]

[checks.rest-world-scale]
expected_uniform_scale = 1.0
uniform_scale_tolerance = 0.0001
animsmith --config bevy.animsmith.toml lint --select engine-addressability character.glb
animsmith --config bevy.animsmith.toml generate addressability character.glb

The standalone addressability inventory retains source animation/channel indices, optional names, raw targets/accessors, and dependency closure. The optional Bevy section uses the same existing check. Named, unnamed, and duplicate-named animations remain distinct because source index is the authority. The selector can change when animation array order changes.

Bevy revision 1 has no settings vocabulary, so [engine.settings] and clip engine settings are invalid. generate import-advice is not a Bevy settings generator.

For unit/effective-scale prediction, select revision 2 and declare the two required environment facts. Defaults are retained with their origin; list them explicitly only when the load differs:

[engine]
profile = "bevy"
profile_revision = 2
engine_version = "0.19.0"
importer = "gltf-asset-loader"

[engine.settings]
extension_handler_environment = "bare_empty" # or "bevy_pbr_stock_0_19"
bevy_animation_feature = true
rotate_scene_entity = false # default
rotate_meshes = false       # default
load_meshes = "nonempty"    # default; or "empty"
load_animations = true      # default

[runtime_nodes]
selectors = ["weapon_socket", "ik_*_target"]
animsmith --config examples/bevy-v2.animsmith.toml lint \
  --select engine-unit-scale character.glb --format json

The handler environment is closed to an empty registry or exactly Bevy 0.19's stock PBR handler. Arbitrary application handlers are not approximated. With load_meshes = "empty", the rule reports each otherwise-created primitive child as suppressed while retaining the source-node entity semantics.

Revision 3: animation/channel gate support

Revision 3 preserves the revision-2 Bevy tuple and adds the narrow engine-track-support check. The only new settings are the document-scoped bevy_animation_feature and load_animations, each recorded with its explicit/default origin:

[engine]
profile = "bevy"
profile_revision = 3
engine_version = "0.19.0"
importer = "gltf-asset-loader"

[engine.settings]
extension_handler_environment = "bare_empty" # or "bevy_pbr_stock_0_19"
bevy_animation_feature = true
load_animations = true

The compiled bevy_animation feature gate has precedence over load_animations. A disabled feature gate therefore predicts a negative drop even when load_animations = true; with the feature enabled, a false load_animations setting predicts the corresponding loader drop. These are negative importer outcomes, not content findings. If both gates allow loading, the result is a stable required-unavailable runtime-survival state because AnimSmith does not execute Bevy or inspect its runtime asset.

The rule inventories raw source animation rows and independent per-animation channel rows from the same load. Complete-empty source animation inventory is not applicable. Partial or unavailable animation/channel coverage emits exactly one subjectless, unsuppressible inventory required_prediction_unavailable facet and no retained-prefix prediction; bounded N+1 evidence is therefore distinguishable from a complete result. Extensions, unsupported constructs, target survival, graph wiring, and other positive runtime claims remain outside revision 3. Current output-v19 carries its immutable V5 provenance unchanged; the output-v17 and output-v16 readers and the revision-2/V4 output-v15 reader remain preserved.

Revision 3 rich addressability

The rich standalone contract is the immutable urn:animsmith:schema:gltf-addressability:2; see gltf-addressability-v2.schema.json. It is selected only for the exact revision-3 tuple and preserves the V1 gltf-animation-addressability:1 inventory as a nested animation domain. The adapter runs one engine-addressability evaluation and does not create a second lifecycle.

The separately versioned authority pins Bevy tag v0.19.0, commit c6f634ca9f406d68ba5109d921247b654cb42c10, bevy_gltf 0.19.0, locked gltf 1.4.1, and the label, loader, node-path, AnimationTargetId, feature, and root Cargo.lock sources. The isolated readback probe's committed lock is the graph authority: every Bevy 0.19 release crate in that lock is 0.19.0 (independently-versioned helpers such as bevy_mikktspace retain their own version); its lock guard rejects internal Bevy patch drift. It requires explicit target pointer width (bits32 or bits64) because Bevy hashes path segment lengths using the target pointer width; AnimSmith never uses the host width. Missing bevy_animation or disabled load_animations is typed unavailable, not runtime success.

Scene{i} is emitted for every declared source scene. Gltf.default_scene is only a route to the selected existing Scene{i}: there is no DefaultScene label and no fabricated Scene0. Every source skin eagerly gets Skin{i}/InverseBindMatrices, including unreferenced skins, with Bevy's identity fallback when inverse-bind data is absent. Skin{i} is created when any source node references it during the all-source-node construction pass; source skin indices, never collected-vector position, are authoritative. Explicit skin.skeleton remains source evidence only because Bevy ignores it; scene-instantiated SkinnedMesh attachment is outside this static slice.

Named scene/animation/skin maps are separate from typed labels and are source-order last-write-wins; skin winners follow lazily created skins in first-reference order. Target rows are per unique source animation target node with contributing animation/channel identities. Authored names or GltfNode{source_index} fallbacks form the path, excluding the scene world-root. A target path/UUID is published only when complete hierarchy, reachability, closure, feature/settings, and collision evidence exists.

The report carries an independent target_coverage projection alongside the retained target rows. It is complete when the unique-target domain is exhaustively represented by complete raw node/scene/path and animation/channel evidence, including an empty domain; incomplete evidence makes it required_unavailable. It also becomes required_unavailable with target_domain_truncated when more than 4,096 targets exist, or with projection_bounds_exceeded when a new rich projection exceeds its aggregate structural/text budget.

Each new rich projection scene/node/skin/attachment/path/target/map domain is capped at 4,096 rows, with aggregate projection structural references at 65,536 and dynamic projection text at 1 MiB. The sealed V1 animation inventory and CheckEvaluation scopes retain their own bounds. One name/path segment is capped at 1,024 UTF-8 bytes, a path at 4,096 bytes and 256 segments, and a report at 256 MiB. The explicit target-coverage projection reports target_domain_truncated at the target row ceiling and projection_bounds_exceeded for other rich-projection budget exhaustion; readback rejects N+1 collections and contradictory states. This is prediction evidence only and does not certify Bevy loading, spawning, target survival, graph wiring, or playback.

If the shared check's core per-file facet budget would be exceeded, V2 exposes one subjectless engine-addressability:facet-budget scope with facet_budget_exceeded rather than a misleading retained-facet prefix. This is compaction within the same check lifecycle, not an additional check.

Common failures and fixes

SymptomEvidence to inspectCorrect owner
Code loads the wrong animation after a source editgenerated source index and Animation{i} selectorRegenerate the manifest and update the code/asset contract; a numeric typed label is not stable across reordering.
Selector exists but nothing playsdependency closure, Bevy loader settings/features, AnimationPlayer, graph and targetsFix runtime loading/graph wiring; the selector prediction does not prove existence.
Duplicate names collide in application lookupsource names and distinct indicesUse typed index labels or define an application-owned name policy.
Attachment or IK target is scaled/shearedrest-world-scale path, ancestry, affine classRepair source hierarchy or supported rest/bind scale; validate the composed Bevy transform at runtime.
Clip loops or movement ownership disagree with gameplayloop checks, in-place, root-motion-speedFix source/contract and graph/controller behavior.

Scale and unit workflow

glTF defines all linear distances in metres. Revision 2 proves that one glTF metre-valued length reaches one Bevy world-space length unit with no loader scale conversion; it deliberately does not claim a universal application, physics, or gameplay metre convention. Treat the format mapping and the application's world convention as two separate authorities. Inherited scale still multiplies descendant attachment, IK, and collision offsets, authored animation translations, and root travel in the composed transform hierarchy.

Use scale whole-document only when every represented glTF length is wrong. Use scale rest-bind when geometry is already correct and one skinned hierarchy carries a declared compensating uniform scale. Use static transform baking only for unskinned placement. None of these operations proves Bevy scene spawning, target-id paths, attachment behavior, physics/collision scale, root motion, animation-graph wiring, or visual playback.

Before: a selected weapon node has a world affine classification that includes uniform factor 0.01. After rest/bind: AnimSmith proves preserved geometry and joint trajectories under the reparameterized hierarchy. Then load the emitted asset in the exact Bevy application, validate the caller-owned WorldAssetRoot and ancestors that are outside importer output, resolve the typed label, attach the prop, and exercise the graph and physics setup. See Scaling safely.