thedivergentai/godot-2d-animation
Expert patterns for 2D animation in Godot using AnimatedSprite2D and skeletal cutout rigs. Use when implementing sprite frame animations, procedural animation (squash/stretch), cutout bone hierarchies, or frame-perfect timing systems. Trigger keywords: AnimatedSprite2D, SpriteFrames, animation_finished, animation_looped, frame_changed, frame_progress, set_frame_and_progress, cutout animation, skeletal 2D, Bone2D, procedural animation, animation state machine, advance(0).
npx skills add https://github.com/thedivergentai/GD-Agentic-Skills --skill godot-2d-animation
Expert-level guidance for frame-based and skeletal 2D animation in Godot.
kill() on the previous instance before creating a new one.animation_finished for looping animations — The signal only fires on non-looping animations. Use animation_looped instead for loop detection.play() and expect instant state changes — AnimatedSprite2D applies play() on the next process frame. Call advance(0) immediately after play() if you need synchronous property updates (e.g., when changing animation + flip_h simultaneously).frame directly when preserving animation progress — Setting frame resets frame_progress to 0.0. Use set_frame_and_progress(frame, progress) to maintain smooth transitions when swapping animations mid-frame.@onready var anim_sprite — The node lookup getter is surprisingly slow in hot paths like _physics_process(). Always use @onready.> MANDATORY: Read the script for the pattern you are implementing. Inline recipes that duplicated these scripts were removed — the script is the source of truth.
| Scenario | Load | Do NOT Load |
|----------|------|-------------|
| Single character / player | one_frame_sync_fix.gd, animation_state_sync.gd, optional animation_tree_step.gd / tween_lifecycle_manager.gd | multimesh_swarm_anim.gd, gpu_mesh_optimizer.gd (unless fill-rate profiling demands it) |
| Frame events / hitboxes / SFX sync | animation_sync.gd (+ AnimationPlayer method tracks) | Swarm/MultiMesh scripts |
| Squash/stretch game-feel | MANDATORY procedural_squash_stretch.gd | Inline landing-condition snippets in this skill |
| Cutout / IK limbs | skeleton_2d_rig_helper.gd | MultiMesh swarm scripts |
| Shader flash / dissolve on anim | shader_hook.gd | — |
| Thousands of bats/fish/props | multimesh_swarm_anim.gd (+ docs fish tutorial) | Per-entity AnimatedSprite2D / Tween managers |
play() + advance(0) with flip_h / property changes.AnimationNodeStateMachinePlayback.travel().skeleton_2d_rig_helper.gd).| Scenario | Recommended Node | Expert Insight |
|----------|------------------|----------------|
| Isolated, pure frame-by-frame spritesheets | AnimatedSprite2D | Cannot animate non-visual properties or method tracks — escalate to AnimationPlayer when you need those. |
| Cutout animations, non-visual sync, audio/particles | AnimationPlayer | Owns transforms, mesh deformation, method/value tracks. |
| Complex state machines, blending, locomotion | AnimationTree | Logic graph over an AnimationPlayer; use travel() via animation_tree_step.gd. |
| Procedural, dynamic, fire-and-forget UI/fx | Tween | Runtime targets; always go through tween_lifecycle_manager.gd. |
| Swarms of thousands of entities | MultiMeshInstance2D + Shader | Load multimesh_swarm_anim.gd only; skip character sync scripts. |
play + advance(0))When changing animation and sprite properties in the same frame, play() alone applies next process tick — one-frame glitch.
MANDATORY: Read one_frame_sync_fix.gd. Minimal contract:
# After any play() that must match flip/modulate/etc. this frame:
anim.flip_h = dir < 0
anim.play(&"run")
anim.advance(0) # force pose now
Related: animation_looped (loops) vs animation_finished (one-shots); use set_frame_and_progress when swapping skins mid-clip (see AnimatedSprite2D class docs).
Do NOT paste landing snippets into agents. A prior body used an impossible condition (not is_on_floor() and is_on_floor()).
MANDATORY sole source: procedural_squash_stretch.gd — impact squash, velocity stretch, lerp recovery. Pair with godot-characterbody-2d / godot-2d-physics for floor/velocity authority.
tween_lifecycle_manager.gd (never race two Tweens on one property).animation_tree_step.gd (start then travel).skeleton_2d_rig_helper.gd + SkeletonModification2DTwoBoneIK docs.gpu_mesh_optimizer.gd / multimesh_swarm_anim.gd per Do-NOT-Load table.frame/texture on child sprites for hand/face swaps. WHY: transform-only motion is cheap; cel swaps stay art-directable without re-rigging.MeshInstance2D polygons skip transparent texels; pair with gpu_mesh_optimizer.gd.kill() the prior instance (tween_lifecycle_manager.gd).start() before travel() (animation_tree_step.gd).| Topic | Reference / script |
|-------|-------------------|
| Signals / frame events / skin swap | signals-and-frame-events.md |
| Cutout rigs / procedural IK feet | cutout-and-skeletal.md |
| GPU mesh / swarms / memory streaming | expert-techniques.md |
| Frame metadata / spawn offsets | animation_data_extractor.gd |
| Async SpriteFrames VRAM | sprite_sheet_memory_manager.gd |
> Progressive disclosure: open Official Documentation links only when researching a specific API;
> load Related Skills when routing work to a peer domain — do not preload the whole lattice.
play(), advance(), set_frame_and_progress(), and animation_looped vs animation_finished contracts.animation_finished / animation_looped / frame_changed without lifecycle leaks.travel() pathfinding beyond the 2D locomotion basics here.create_tween() snippets..tres SpriteFrames and skin packs for memory-safe multi-instance characters.Take thedivergentai/godot-2d-animation from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.