~4 min read

Animation — AnimationPlayer and AnimationTree

AnimationLibrary, state machine, blend spaces, root motion.

AnimationPlayer — the main node

AnimationPlayer holds an AnimationLibrary with a set of Animation resources and plays them. A unique Godot feature — you can animate any property of any node (or even a resource), not just Transform and Material:

  • Transform (position, rotation, scale)
  • Any property (sprite alpha, visible, numbers, colors)
  • Shader uniforms — via the property path material:shader_parameter/threshold
  • Method calls (call a function on a timer in a track)
  • Audio (start an AudioStreamPlayer)
  • Nested animations of other AnimationPlayers
Player (Node3D)
├── Skeleton3D
│   └── MeshInstance3D
└── AnimationPlayer        ← all clips here: Idle, Run, Jump, Attack
$AnimationPlayer.play("Run")
$AnimationPlayer.play("Jump", -1, 1.2)   # blend_time=-1, speed=1.2
$AnimationPlayer.speed_scale = 0.5        # all clips slowed to half speed
$AnimationPlayer.stop()
$AnimationPlayer.seek(0.5, true)          # jump to 0.5 s

# End-of-animation signal
$AnimationPlayer.animation_finished.connect(_on_anim_done)
Web

A GSAP / Framer Motion timeline: you describe tracks on element properties with keyframes, and time drives the animation.

Unity

The Unity Animation Window has the same feel of recording tracks along a timeline. But the Unity Animator Controller is a separate state-machine asset. In Godot its equivalent is AnimationTree, and it’s bound to a single AnimationPlayer.

Recording animation in the editor

  1. Select the AnimationPlayer in the scene → the Animation editor appears at the bottom.
  2. The “Animation” button → New → a name.
  3. Enable the red dot (Recording) → change any property in the Inspector → a keyframe is created automatically at the current point on the timeline.
  4. Scrub the timeline → change it again → a second keyframe.

Tracks can also be added manually via “Add Track”.

AnimationTree — state machine and blend space

For complex animation (locomotion, transitions), use AnimationTree — a separate node that reads animations from the linked AnimationPlayer and processes them through a node graph:

Player (Node3D)
├── AnimationPlayer
└── AnimationTree         ← root: AnimationNodeStateMachine
                              tree_root points to the root graph
                              anim_player points to the AnimationPlayer

The root graph of an AnimationTree is an AnimationNode. Types:

  • AnimationNodeStateMachine — an FSM with states and transitions.
  • AnimationNodeBlendTree — a graph for blending.
  • AnimationNodeBlendSpace1D — 1D parametric blending (for example, speed 0..6 ↔ Idle ↔ Walk ↔ Run).
  • AnimationNodeBlendSpace2D — 2D (for example, strafe_x, forward_y for 8-directional movement).
  • AnimationNodeAdd2/3 — additive pose blending.
  • AnimationNodeOneShot — a single playback on top (for example, a “shoot” over a walk).
  • AnimationNodeTimeScale / TimeSeek.

States via StateMachine

@onready var anim_tree: AnimationTree = $AnimationTree
@onready var state_machine = anim_tree["parameters/playback"]  # AnimationNodeStateMachinePlayback

func _ready() -> void:
    anim_tree.active = true

func _process(delta: float) -> void:
    var speed = velocity.length()
    anim_tree["parameters/Move/blend_position"] = speed  # 1D blend space

    if Input.is_action_just_pressed("jump"):
        state_machine.travel("Jump")  # smart transition through the graph (A* path finding)

travel("StateName") is the headline feature of Godot’s StateMachine: it finds a short path through the transitions. Want to go from Idle to Land? If there’s no direct arrow, Godot will find Idle → Run → Land and traverse it.

parameters is a dictionary

AnimationTree exposes all of the graph’s configurable parameters via string subscript notation. anim_tree["parameters/Locomotion/blend_position"] is a path in the graph. For frequent access, you can cache the path in a var path = "parameters/...": constant.

Root Motion

If the skeleton moves in the animation (“a step forward”), by default the AnimationPlayer does not move the GameObject. It only changes poses. To translate the skeleton’s displacement into actual node movement:

  1. On the AnimationTree, set root_motion_track — the path to the root bone (Skeleton3D:Hips).
  2. In the script, read anim_tree.get_root_motion_position() and apply it to the node:
func _physics_process(delta: float) -> void:
    var motion = anim_tree.get_root_motion_position()
    velocity = transform.basis * motion / delta
    move_and_slide()

When not to use root motion: classic FPS games/platformers where speed is computed by logic. It’s used for cinematic movements, grapples, and finishers.

Skeleton3D, Bones, Bone Attachment

Skeleton3D is a hierarchy of bones. It’s applied to the skinning of a MeshInstance3D via a Skin resource.

BoneAttachment3D is a node that follows a bone. You attach weapons and accessories to it:

Player
├── Skeleton3D
│   ├── MeshInstance3D (skinned)
│   └── BoneAttachment3D (bone_name = "RightHand")
│       └── Sword (Node3D + MeshInstance3D)

IK — Inverse Kinematics

In 4.6, IK returned in the form of solver nodes inside Skeleton3D (nodes inheriting from SkeletonModifier3D):

  • TwoBoneIK3D — two links (an arm/leg) with a target position.
  • FABRIK3D — Forward And Backward Reaching IK (multiple links).
  • CCDIK3D — Cyclic Coordinate Descent.
  • ChainIK3D, SplineIK3D, JacobianIK3D, IterateIK3D — additional solvers for special cases.

Applied via SkeletonModifier3D nodes attached to Skeleton3D. Example: a character’s hand reaches for a door handle during interaction.

Importing animation

Sources:

  • glTF 2.0 — the recommended format for 3D models with animation. It exports perfectly from Blender.
  • FBX — native import since 4.3 via ufbx (no external FBX2glTF).
  • Mixamo animations — better via glTF; FBX also works with retargeting.

On import, Godot creates a scene (a .tscn equivalent) with Skeleton3D + AnimationPlayer + AnimationLibrary. Import settings (scale factor, animation library mapping) are in the Import dock.

For retargeting (transferring an animation from one skeleton to another), use a Skeleton Profile (SkeletonProfileHumanoid is built in).

Animation Events / Method Tracks

The Godot equivalent of a Unity Animation Event is a Method Track: a track that calls a method on a node at a given moment. In the Animation editor: Add Track → Call Method Track → select a node → a keyframe stores the method name and parameters in its payload:

# This method can be triggered from a Method Track in the "Walk" animation
func on_footstep() -> void:
    $StepSound.play()

In the next chapter — UI.