bevy-animation
Skill29 starsChanged 11 days agoMITView on GitHub
Use when wiring `AnimationPlayer` + `AnimationGraphHandle`, building an `AnimationGraph` from glTF clips, blending state-driven animations with `AnimationTransitions::play`, isolating body parts with `AnimationMask`, firing gameplay sync via `#[derive(AnimationEvent)]` + `On<E>` observers, tweening with `AnimatableCurve` / `EaseFunction` / `CubicSegment::new_bezier_easing` from `bevy::curve`, or applying the 12 Basic Principles of Animation to 3D characters in Bevy 0.20.
In this repository34 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- bevy-a11ySkill
- bevy-assetsSkill
- bevy-audioSkill
- bevy-camerasSkill
- bevy-captureSkill
- bevy-cargo-featuresSkill
- bevy-core-conceptsSkill
- bevy-custom-assetsSkill
- bevy-diagnostics-profilingSkill
- bevy-ecs-componentsSkill
- bevy-ecs-queriesSkill
- bevy-ecs-systemsSkill
- bevy-fluentSkill
- bevy-input-actionsSkill
- bevy-migration-0-17-to-0-18Skill
- bevy-migration-0-18-to-0-19Skill
- bevy-migration-0-19-to-0-20Skill
- bevy-pbr-materialsSkill
- bevy-physicsSkill
- bevy-portingSkill
- bevy-renderingSkill
- bevy-save-loadSkill
- bevySkill
- bevy-testingSkill
- bevy-uiSkill
- bevy-vfxSkill
- bevy-voxel-dataSkill
- bevy-voxel-pipelineSkill
- bevy-voxel-runtimeSkill
- bevy-wasm-webgpuSkill
- similarity-rsSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 139
gltf_animationis on by default: No opt-in needed unless you ran default-features = false. - Very specific: line 146
Out of scope in 0.20 core animation: No built-in IK, no KHR_animation_pointer (still unsupported by bevy_gltf 0.20.1), particles are …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Bevy 0.20 — Animation (graphs, blending, events, 12 principles)
When to use this skill
- Loading a glTF clip and playing it on a character:
AnimationPlayer+AnimationGraphHandle. - Cross-fading between idle / walk / run via
AnimationTransitions::play(player, node, Duration). - Building an
AnimationGraphin code: blend nodes, additive nodes, weights,AnimationMask. - Triggering gameplay events from a clip timeline (footsteps, hitbox activation, VFX cues) with
#[derive(AnimationEvent)]+clip.add_event_to_target(...)+On<MyEvent>observers. - Procedural tweening without an
AnimationClip— sampling aCurveper frame viaEasingCurve+EaseFunctionorCubicSegment::new_bezier_easing. - Applying the 12 Basic Principles of Animation (Thomas & Johnston, 1981) to a Bevy character.
- Importing a Blender rig and finding bones aren't animated — usually the
Namerequirement forAnimationTargetId::from_name. - Fixing
bevy::math::curve/bevy::math::cubic_splinesimport errors after upgrading to 0.20.
Canonical end-to-end pattern
Verified against bevy = "0.20" — cargo check clean in bevy-skills-tester/examples/bevy_animation.rs.
use bevy::{
animation::{
animated_field,
animation_curves::{AnimatableCurve, AnimatableKeyframeCurve},
AnimationEvent, AnimationTargetId,
},
prelude::*,
};
use core::time::Duration;
#[derive(AnimationEvent, Clone)]
struct FootstepEvent { foot: u8 }
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut clips: ResMut<Assets<AnimationClip>>,
mut graphs: ResMut<Assets<AnimationGraph>>,
) {
// 1. Load a glTF clip
let walk: Handle<AnimationClip> =
asset_server.load("models/character.glb#Animation0");
// 2. Build a tiny procedural clip with a sample curve + an event
let bone = AnimationTargetId::from_name(&Name::new("Hips"));
let tween = AnimatableKeyframeCurve::new([
(0.0_f32, Vec3::ZERO),
(0.5, Vec3::new(0.0, 1.0, 0.0)),
(1.0, Vec3::ZERO),
]).expect("strictly-increasing times");
let curve = AnimatableCurve::new(animated_field!(Transform::translation), tween);
let mut proc = AnimationClip::default();
proc.add_curve_to_target(bone, curve);
proc.add_event(0.5, FootstepEvent { foot: 0 });
let proc = clips.add(proc);
// 3. Compose a graph: root → walk + additive(proc, mask=group 0 excluded)
const MASK_GROUP_0_BIT: u64 = 1 << 0;
let mut graph = AnimationGraph::new();
let root = graph.root;
let _walk_node = graph.add_clip(walk, 1.0, root);
let additive = graph.add_additive_blend(0.5, root);
let _proc_node = graph.add_clip_with_mask(proc, MASK_GROUP_0_BIT, 1.0, additive);
// 4. Spawn the player entity (bones come from the loaded glTF scene)
commands.spawn((
Name::new("AnimationRoot"),
AnimationPlayer::default(),
AnimationGraphHandle(graphs.add(graph)),
AnimationTransitions::new(),
));
}
fn start(mut q: Query<(&mut AnimationTransitions, &mut AnimationPlayer), Added<AnimationPlayer>>) {
use bevy::animation::{graph::AnimationNodeIndex, RepeatAnimation};
for (mut tx, mut player) in &mut q {
tx.play(&mut player, AnimationNodeIndex::new(1), Duration::from_millis(250))
.set_repeat(RepeatAnimation::Forever);
}
}
fn on_footstep(trigger: On<FootstepEvent>) {
let foot = trigger.foot; // On<E> derefs to &E
let _entity = trigger.trigger().target; // AnimationEventTrigger::target
let _ = foot;
}
fn main() {
App::new()
.add_plugins(DefaultPlugins) // gltf_animation is a default feature
.add_systems(Startup, setup)
.add_systems(Update, start)
.add_observer(on_footstep)
.run();
}Topics
| Topic | Reference |
Building blend / additive graphs, AnimationMask, hot-swap | references/animation-graph.md |
Blender → glTF → Bevy import: Name, axis, multi-clip, morph targets, unsupported extensions | references/gltf-import.md |
Procedural animation in Update vs FixedUpdate, root-motion extraction | references/procedural-animation.md |
Idle / walk / run blending; AnimationTransitions::play + Bevy States integration | references/state-machines.md |
#[derive(AnimationEvent)], add_event_to_target, On<E> observer wiring | references/animation-events.md |
AnimatableCurve, EasingCurve, EaseFunction, cubic-bezier, UnevenSampleAutoCurve | references/curves-and-tweening.md |
AnimationPlayer cost, skin buffers, graph complexity, runtime graph swaps | references/performance.md |
| Principles — Slow In/Out, Timing, Anticipation → easing + duration | references/principles-easing-and-timing.md |
Principles — Squash & Stretch, Arc, Exaggeration → Transform keyframes | references/principles-transform-keyframes.md |
| Principles — Staging, Follow Through, Secondary Action → graph layering + masks | references/principles-graph-layering.md |
| Principles — Straight-Ahead vs Pose-to-Pose, Solid Drawing, Appeal → upstream authoring | references/principles-authoring.md |
The 12 Basic Principles of Animation
The four principles-*.md references group Thomas & Johnston's twelve principles by which Bevy primitive they actually exercise. Quick map:
- Easing & Timing — Slow In/Out, Timing, Anticipation map to
EaseFunction/EasingCurve/CubicSegment::new_bezier_easingand clip duration +ActiveAnimation::set_speed. - Transform keyframes — Squash & Stretch, Arc, Exaggeration are
AnimatableKeyframeCurveoverTransform::scale/::translationviaanimated_field!. - Graph layering — Staging, Follow Through & Overlapping Action, Secondary Action are
AnimationGraph::add_additive_blend+AnimationMaskgroup isolation. - Authoring — Straight-Ahead vs Pose-to-Pose, Solid Drawing, Appeal live in your DCC tool (Blender, Maya). Bevy plays whatever you authored.
Gotchas
- 0.20: curves moved to
bevy_curve.bevy::math::curve::{EasingCurve, EaseFunction}andbevy::math::cubic_splines::CubicSegmentare nowbevy::curve::{EasingCurve, EaseFunction}andbevy::curve::cubic_splines::CubicSegment.bevy::preludestill re-exports them, so most code only needs theuselines fixed. Signatures are unchanged (EasingCurve::new(start, end, ease_fn),CubicSegment::new_bezier_easing(p1, p2)). - 0.19:
AnimationTargetIdhash algorithm changed. Different joint hierarchies no longer collide. Regenerate any serialized target IDs; IDs computed at runtime withfrom_name/from_iterare fine. - 0.19: morph targets live in
Mesh.GltfAssetLabel::MorphTargetis gone;MeshMorphWeightscan reference an entity withMorphWeightsinstead of being auto-copied. Seereferences/gltf-import.md. - 0.20: observers lost the bundle generic.
On<E>is unchanged forAnimationEvents. Lifecycle observers on bone entities areOn<Add<AnimatedBy>>, notOn<Add, AnimatedBy>. - 0.17 → 0.18 split.
AnimationTarget { id, player }no longer exists. It's two components on each bone entity:AnimationTargetId(Uuid)+AnimatedBy(Entity). The glTF loader spawns these for you. gltf_animationis on by default. No opt-in needed unless you randefault-features = false.AnimationTransitions::play_with_transitiondoes NOT exist. The only method isplay(&mut self, player, node, Duration) -> &mut ActiveAnimation. Chain.set_repeat(RepeatAnimation::Forever)/.set_speed(f32)on the returned value.animated_field!andAnimatableCurveare not in the prelude. Import frombevy::animation::{animated_field, animation_curves::{AnimatableCurve, AnimatableKeyframeCurve}}.On<AnimationEvent>is not anEntityEventobserver.On<E>derefs to&E. The firing entity istrigger.trigger().target(AnimationEventTrigger::target)..target()/.entityare not available.Nameis required on bone entities forAnimationTargetId::from_name(&Name)to resolve. The glTF loader sets this; hand-built skeletons must too. Since 0.20Name::newfrom&strneeds'static; useStringfor runtime names.AnimationMaskbit polarity. A set bit means that node will not animate targets in that group. Register a bone viagraph.add_target_to_mask_group(target_id, group_u32). To restrict a node to one group, set every bit except that group's.- Schedule. Animation systems run in
PostUpdateinside theAnimationSystemsset (a unit set in 0.20), beforeTransformSystems::Propagate. Procedural systems that also writeTransformshould run inUpdateor order explicitly againstAnimationSystems. - Out of scope in 0.20 core animation. No built-in IK, no
KHR_animation_pointer(still unsupported bybevy_gltf0.20.1), particles are separate — seereferences/gltf-import.md.
See also
bevy-migration-0-19-to-0-20— thebevy_curvesplit and observer generic change in full.bevy-cameras— camera animation (panning, dolly, focus follow) uses the sameEaseFunction/EasingCurvetoolkit.bevy-core-concepts—UpdatevsFixedUpdatechoice for procedural animation; seeprocedural-animation.md.bevy-ecs-systems— observer wiring patterns (On<E>,add_observer) used forAnimationEvents.bevy-pbr-materials— material-parameter animation viaAnimatableCurvetargetingStandardMaterialfields.bevy-custom-assets—AssetLoaderpatterns if you serialiseAnimationGraphto RON and load it as an asset.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

