Coordinate animations with machines
Use a state machine when events mean different
things in different states. Keep ordinary sequence, parallel, and repeat
programs for animation timing. A machine decides which program owns a run;
playback samples its outputs through Pibbl’s existing scheduler.
import { drive, repeat, useSignal } from "@pibbl/core";import { defineMachine, useMachine } from "@pibbl/core/machines";import { playAnimation } from "@pibbl/core/machines/animation";import { Sprite, type SpriteFrame, type SpriteSheet,} from "@pibbl/core/sprites";import type { WritableSignal } from "@pibbl/core";
type Event = { type: "RUN" } | { type: "STOP" };type Input = { frame: WritableSignal<SpriteFrame>; sheet: SpriteSheet };
const motion = defineMachine<{}, Event, Input>({ initial: "idle", context: () => ({}), states: { idle: { on: { RUN: "running" } }, running: { invoke: { task: playAnimation(({ input }) => repeat(drive(input.frame, input.sheet.animations.walk), { iterations: Infinity, }), ), }, exit: ({ input }) => input.frame.set(input.sheet.frames.standing), on: { STOP: "idle" }, }, },});
function Character({ sheet }: { sheet: SpriteSheet }) { const frame = useSignal(sheet.frames.standing); const actor = useMachine(motion, { input: { frame, sheet } }); return ( <Sprite frame={frame} onClick={() => actor.send({ type: actor.snapshot.get().matches("running") ? "STOP" : "RUN", }) } /> );}A finite program resolves its task after the scheduler delivers completion; the
promise completion can select invoke.onDone. An infinite program lasts until
state exit. The adapter disposes only its owned playback. It does not silently
cancel unrelated animation writers.
State changes do not imply output blending. Concurrent programs writing different signals are independent; conflicting writers still follow the animation runtime’s explicit conflict rules. A frame change does not send a machine event or rebuild machine context.
For a game, keep session states (start, playing, game over) separate from character states (idle, running, rising, falling). Physical contacts send Land and Fall; keyboard input sends Move and Jump. Only grounded states handle Jump. Coin flight and brick debris have their own lifetimes and survive locomotion changes.
A death animation finishing does not make a character alive. Keep the machine in its dead state until session logic explicitly respawns it.
Implementation guidance for agents
Section titled “Implementation guidance for agents”Read the Animation and scheduling companion for ownership, adaptation, failure modes, and verification. Agent start provides the version-selection workflow.
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision 2dccb19. ALPHA — NOT FOR PRODUCTION USE.