One rig, one animation, any character — four ways to run it
This is a test bed for the FocusTown avatar system: Lego-style characters (any hair × face × top × bottom × accessory, any skin/hair colour, any seat pose, either facing) that all play the same idle animations (breathing, blinking, page turn / typing) with no per-combination work. Every page below uses the same parts, the same rig definition and the same procedural animation code; only the runtime differs. Use the identical control panel on each page to compare them.
A · PixiJS rig recommended
Spine-like bones/slots/skin in ~300 lines of TypeScript on PixiJS v8 (MIT). Live procedural animation, runtime tint, one WebGL canvas for the whole room, and a "bake to sprite sheet" button for the pre-render path.
OpenA2 · DOM rig
Same rig rendered as plain HTML <img> layers with CSS matrices. No canvas at all; name tags and
CSS come for free; accessories are inline SVG recoloured by a CSS variable (the vector route).
B · Lottie (generated)
The animation is sampled into a standard Lottie JSON in the browser and played by dotlottie-web (WASM) or lottie-web (SVG), both MIT. Download the file and open it in Glaxnimate.
OpenC · DragonBones (generated)
The rig exported as DragonBones 5.5 skeleton + atlas and played by the abandoned-but-MIT DragonBones runtime on PixiJS v5. Works, but shows why it is not a good base in 2026.
OpenWhat is shared (the "artist template")
src/shared/rig.ts defines 11 bones (root → hips → torso → head / arms → hands, legs, prop) and
15 slots in draw order (legs, back arm, body, prop, back hand, head skin, hair, face, blink, accessory, front
arm, front hand). poses.ts holds three seat poses as per-bone rotation overrides plus a prop. anim.ts
is the animation: pure functions of time — breathing is a sine on the torso, blinking a seeded schedule, the page turn a
bump on the front arm with a texture swap. Nothing in there names a drawing, which is what makes it part-agnostic and
pose-agnostic at once.
The parts are Kenney's CC0 "Toon Characters 1" cut-outs, run through tools/build-assets.mjs, which does what
an artist's export step would do: split each head into skin / hair / features layers by palette colour, whiten the
skin and hair layers so a multiply tint gives any palette colour, split arms into sleeve/skin, detect the eye whites and draw
a closed-eyelid overlay for blinking. That pipeline is the answer to "how do we avoid redundancy": the artist draws each
part once on the shared template; colours, poses and animations are applied by code.
Comparison (measured on this build)
| A · PixiJS rig | A2 · DOM rig | B · Lottie | C · DragonBones | |
|---|---|---|---|---|
| Animation source | live code (procedural) | live code (procedural) | keyframes generated from the same code | keyframes generated from the same code |
| Part swap at runtime | set a texture | set an img.src | regenerate file (or dotLottie image slots) | regenerate skeleton/atlas (or slot display swap) |
| Skin / hair tint | GPU multiply tint | SVG filter / CSS variable (vector) | pre-tinted at export (no raster tint in Lottie) | pre-tinted at export (slot colour also possible) |
| Mirroring | root matrix | root matrix | root layer scale −100 | scale.x = −1 |
| Room of 10 | one canvas, one draw list | 150 transformed elements | 10 canvases (WASM) or 10 SVG trees | one canvas |
| Pre-render path | built in (bake button) | headless browser | any Lottie→video tool | runtime extract |
| Artist can open the motion in a tool | no (it is code) | no | yes — Glaxnimate / LottieFiles | only the discontinued editor |
| JS shipped for the page (uncompressed) | ≈ 470 KB | ≈ 20 KB | ≈ 380 KB + 1.2 MB WASM | ≈ 640 KB (Pixi v5 + runtime) |
| Licence / cost | MIT, $0 | $0 | MIT, $0 (Glaxnimate GPL, free) | MIT, $0 — unmaintained |
| Maintenance risk | low (Pixi active) | none | low (players active) | high (no releases since 2022) |
What is not here, and why
Spine and Rive were the two strongest editor-based candidates in the research, but neither
can be demonstrated for free: Spine's runtimes are only licensed to owners of a Spine Editor licence ($69 per user), and
Rive's free plan cannot export .riv files since October 2025 ($9/month). Option A is deliberately built as
a Spine-shaped data model so that, if a licence is bought later, spine-pixi-v8 drops into the same canvas.
How to read the demo
- Change hair/face/top/bottom independently — the animation never changes, the parts just slot in.
- Switch the pose: the same character sits differently; the same hair/face/top follow.
- Pick skin and hair colours: the same white-based layers are tinted; the blink overlay follows the skin colour.
- Turn on room mode and watch the fps counter on a phone — that is the real budget (≥10 avatars per room).
- On the Pixi page press "Bake": that is the "pre-rendered later" decision, made in one click from the same rig.
Assets: Kenney "Toon Characters 1" (CC0) · props drawn as SVG for this demo · source in test/demo
(/srv/projects/focustown) · docs in test/docs.