Skip to content

Drive an animation blend tree

quick start Beginner ⏱ 6 min vgai 0.1.0

Prerequisites: Installed vgai and run the editor

What you'll learn

  • See an XState blend-tree state mix idle → walk → run by speed
  • Recognize how gameplay drives animation by sending XState events
  • Know where the blend tree math and the animation binding live

What you'll build: A look at the third-person character — its locomotion blend driven by a speed value sent into an XState machine.

Walkthrough — Drive an animation blend tree · generated by site/media/lessons/tierc-batch.lesson.ts (4 steps)

The third-person character animates through an ordinary XState machine: its locomotion state declares a meta.animation.blendTree whose output is mixed from a few inputs (speed, grounded) gameplay code sends into the machine each frame. You never play clips by hand; you send events, XState decides the state, and the blend tree inside that state’s meta.animation blends.

  1. Open a scene with an animated character. The scene is already open — if you followed the link above, the third-person scene is loaded and rendering (in the local dev editor: VGAI_PROJECT=examples/third-person-action npm run dev).

    The third-person scene loaded
    A character whose locomotion is driven by an XState machine.
  2. Enter play mode — the XState machine drives the character. bindXStateAnimation ticks the bound THREE.AnimationMixer each frame from the animation phase. At rest, speed is ~0, so the machine’s locomotion blend tree outputs the idle pose (from the idle state).

    The character idle in play mode
    speed ≈ 0 → the idle state, or the blend tree's idle end, is active.
  3. Drive with W — the blend tree mixes idle → walk → run by speed. The character controller computes a horizontal speed and sends it into the actor:

    // third-person/components.ts — gameplay drives animation, not the reverse
    this.animActor?.send({
    type: 'UPDATE',
    speed: horizontalSpeed * ANIM_SPEED_SCALE,
    grounded: nowGrounded,
    });
    this.animBinding?.tick(dt);

    UPDATE assigns speed/grounded into the machine’s context; an always-guarded eventless transition then moves between the idle state and the locomotion state based on speed, and inside locomotion the 1D blend tree (keyed on the same speed context value) blends its walk and run clips by proximity. So across the two states you see idle → walk → run. No clip names appear in the gameplay code.

    The character running while moving
    Higher speed → the blend tree shifts toward run.
  4. Stop play mode. Press Stop (or Escape).

Recap

New functionality

  • Watched an XState blend-tree state mix idle → walk → run
  • Saw gameplay drive animation by sending XState events

New concepts & skills

  • A blend tree mixes clips from a live context value — you send events, not clips
  • bindXStateAnimation ticks the mixer (and live blend-tree weights) from the animation phase
  • speed and grounded are UPDATE-event fields the third-person controller sends each frame

Next lesson → Manual: XState animation binding

On Your Own!

Extend what you built:

  • Open xstate-animation-binding.ts and find where a state's meta.animation selects the blend
  • Trigger the airborne state by jumping (the controller sends { type: 'JUMP' })
  • Change ANIM_SPEED_SCALE and observe the walk→run threshold shift