euca-animation) attaches an animator to an entity: it plays a clip by
index, blends between states with an AnimStateMachine, or overlays a one-shot MontagePlayer. Clips
themselves come from glTF files loaded into an AnimationLibrary. The pose model — animators, state
machines, montages — is headless and mutates entities synchronously; what needs a host are the two
inputs: a real glTF file to load clips from, and the AnimationLibrary resource to store
them in. This page walks the model end to end; every command is real and runnable against a
local server, with output captured from one.
Load a clip — and meet two gates
/animation/load reads a glTF file and adds its clips and skeleton to the AnimationLibrary. There
are two gates, in order. First, the file must exist — the minimal server has no character assets,
so a typical path fails at load:
AnimationLibrary
resource. The minimal server installs only events and the rules system, so the store step returns
{"ok":false,"error":"AnimationLibrary resource not initialized"}, and the clip list stays empty:
.glb and registers an AnimationLibrary, the same load returns
{"ok":true,"meshes":1,"skeleton":true,"animations":["idle","run"]}, and /animation/list enumerates
each clip’s index, name, duration, and channel count.
Play, blend, and overlay on an entity
The animator side is pure component logic — it doesn’t need the library to attach, so it works on the bare server against any spawned entity. Spawn one:clip is a numeric index into the library (default 0), with speed and
loop. The animator is attached immediately:
{"ok":false,"message":"Entity 999 not found"}.
Behavior and gotchas
The things you only find out by running it:- Loading has two distinct failure modes. A missing/bad path fails at the glTF read
(
No such file or directory); a valid file with noAnimationLibraryregistered fails at the store (AnimationLibrary resource not initialized). The clip list is empty in both cases — they are not the same gate. clipis a numeric index, not a clip name./animation/play, the state-machine states, and the montage all reference clips by their integer position in the library, not by string. Index0is the default forplay.- Attaching an animator needs only an entity, not the library.
play,state-machine,montage, andstopall succeed on the bare server (they insert components on an entity) — the clip they point at simply doesn’t resolve to pose data until a real library is loaded and a render host skins it. - No
/stepto attach. The component is inserted on the call; the per-tickanimation_evaluatepipeline (state machine → sample → crossfade → montage → root motion) runs when the host steps and renders. montageis idempotent on re-trigger. A second montage on an entity that already has aMontagePlayerre-plays into the existing player rather than stacking a new one.
Endpoints
Status
- Shipped & headless — the animator, state-machine, and montage component model (all verified on the bare server), plus crossfade blending, blend spaces, two-bone and FABRIK IK, look-at constraints, root motion, and animation events.
- Host-dependent — clip loading needs both a real glTF file and a registered
AnimationLibrary; the minimal example server has neither, so/animation/loadfails and/animation/listis empty. Producing the on-screen skinned mesh from the evaluatedBoneTransformsis the render host’s job. - Render caveat — skinned characters currently receive shadows but do not cast them: the shadow depth pass draws only the static cascade batches, so a posed skinned mesh isn’t written into the shadow map. Proper skinned shadow casting needs GPU compute skinning and is not yet wired.
Animation endpoints
Load, play, state-machine, and montage endpoints, with request and response schemas.