Animations are the motion clips (idle, wave, dance, and about 2,000 more) that bring three.ws avatars to life. Browse and preview every clip at three.ws/animations; this page is the developer reference for how the clip collections are organized, how the runtime loads them, and how agents pick which clip to play.
For how FBX, GLB, and clip JSON relate — the formats, the conversions, and the full generate→rig→animate→export chain — see docs/3d-asset-pipeline.md. This page is the runtime registry and agent-slot reference.
The full machine-readable registry is at public/animations/registry.json. Read it first before touching anything animation-related — it catalogues every animation asset in the project, which pipeline owns it, and its current status.
There are 5 animation collections across the codebase. They are separate and use different rigs:
| Collection | Location | Status |
|---|---|---|
| clips | public/animations/clips/*.json |
Active in main runtime |
| presets_robotexpressive | public/animations/robotexpressive.glb |
Legacy, not loaded at runtime |
| lora_pipeline | character-studio/public/lora-assets/animations/ |
character-studio LoRA pipeline only |
| sprite_atlas_pipeline | character-studio/public/sprite-atlas-assets/animations/ |
character-studio sprite atlas only |
| sims_demo | sims-demo/public/AnimationLibrary.glb |
sims-demo character controller only — the sims-demo/ workspace lives outside this repo, so the GLB is not on disk here |
src/app.jsfetches/animations/manifest.jsonon startupsrc/animation-manager.js(AnimationManager) loads each clip frompublic/animations/clips/src/agent-avatar.jsplays clips by resolving slots → clip names viasrc/runtime/animation-slots.js- The UI widget
src/widgets/animation-gallery.jslists all loaded clips
- Drop the FBX into
public/animations/ - Add an entry to
scripts/animations.config.json - Run
node scripts/build-animations.mjs(ornpm run build:animations) — retargets to the Avaturn rig, writes a JSON clip topublic/animations/clips/, and updatesmanifest.json - Update
public/animations/registry.jsonso the new clip is catalogued under theclipscollection - Optionally wire a slot in
src/runtime/animation-slots.jsso the agent plays it automatically
Slots are the fixed vocabulary the agent avatar uses to express emotion/gesture. They resolve to clip names at runtime. Defined in src/runtime/animation-slots.js.
| Slot | Default clip | Notes |
|---|---|---|
idle |
idle |
Always playing |
wave |
reaction |
Maps to reaction, not the wave clip |
nod |
reaction |
|
shake |
angry |
|
think |
pray |
|
celebrate |
celebrate |
|
concern |
defeated |
|
bow |
sitclap |
|
point |
reaction |
|
shrug |
defeated |
|
fidget |
av-waiting |
Real baked idle-fidget loop (was the never-baked Fidget, fixed 2026-07-08) |
dance |
rumba |
Agents can override individual slots via meta.edits.animations.
three.ws/animations is the public browse surface over every clip: the curated studio manifest, the full R2-hosted motion-capture library (GET /api/animations/library, ~2,000 clips), and community-published clips (GET /api/animations/clips?visibility=public).
- Poster thumbnails — every clip has a WebP still of the preview avatar posed mid-motion. Rendered offline by
node scripts/build-animation-thumbnails.mjs(drivesscripts/thumbnail-harness.htmlin headless Chromium through the site's own retarget engine). Curated thumbs are committed atpublic/animations/thumbs/<name>.webp; library thumbs upload to R2 alongside their clips vianpm run mixamo:upload, which publishes each one as the manifest entry'sthumbURL. Added a clip? Re-run the thumbnail script, then re-upload. - Categories — the Mixamo catalog carries no category metadata, so
src/animation-categories.jsderives one per clip from its label (ordered keyword rules; curated clips keep their hand-assignedanimation-presets.jscategory). Covered bytests/animation-categories.test.js, which also asserts <10% of the real library falls into the "More" catch-all. - Live previews — one shared WebGL engine (
src/animations-live-preview.js) serves every card hover and the detail modal: a single renderer + preview avatar; the canvas moves into whichever card is previewing. Nothing 3D loads until the first hover. - Deep links —
?clip=<id>opens a clip's detail modal directly;q,cat,filter, andsortround-trip through the URL so filtered views are shareable.
waveclip unreachable — thewaveclip is in the manifest but no agent slot or hint points to it. Thewaveslot maps toreactioninstead.- Dead animation hints — skill-emitted hints
gesture,inspect,present,sign,curiosity,patiencehave no matching clip or slot; they silently no-op on Avaturn models. (src/agent-avatar.js)
Resolved (see public/animations/registry.json → resolved_issues): the fidget slot no longer points at the never-baked Fidget clip — it maps to the real av-waiting loop (2026-07-08); and the 6 formerly-orphaned source FBX (Cover To Stand, Goalkeeper Scoop, Jumping Down ×3, Removing Driver) are now entries in scripts/animations.config.json and built into the manifest.
- 3D asset pipeline: the full generate, rig, animate, export chain
- Animation Studio: author and preview clips in the browser
- 3D Viewer: how clips play back in the viewer and embeds
- Clip Director: gesture slots used for trade reaction cards