Appearance
Prompting an AI to build an animspec host
animspec renders in Node.js — the same spec, signal and seed always produce the same frames. It does not run in a browser: @napi-rs/canvas is a native Node module. So a webpage that uses animspec is two halves, and an AI can build both:
| Half | What it does | Who owns it |
|---|---|---|
| Node host | renders frames with drawSpec (or drives the animspec render command) | this library + the AI's code |
| Browser page | displays the frames and takes the controls (seed, spec, mic, chat) | the AI's code |
Audio decoding, model calls, storage and playback stay with the host too — animspec draws.
What to hand the model
A model can only use what you show it. Three things, in this order:
The vocabulary — generated from the registry, never hand-pasted:
jsimport { select, selectDetailed, buildVocabPrompt, buildJsonSchema } from "animspec"; const subset = select("auto", 0.5, 7); // kit ("auto" or a kit name), breadth 0..1, seed // or ask for primitives by name on top of a kit: // const subset = selectDetailed("minimal", 0.4, 7, ["stickman"]).primitives; const vocabPrompt = buildVocabPrompt(subset); // one line per primitive const schema = buildJsonSchema(subset); // JSON schema for structured outputBrowsing VOCABULARY.md and the gallery helps you choose the kit; the generated prompt is what the model should see.
The public API —
drawSpec,validateAnimSpec, the SignalFrame track (encodeSignalTrack/decodeSignalTrack, and the per-frame readerreadSignalTrackHeader/readSignalFrame/indexSignalTrackSidecar),VOCABULARY_VERSION, and theanimspec rendercommand for pre-rendering.The rules — paste this into every prompt:
textHard rules: - animspec runs in Node.js 22+ only (never import it in the browser). - Always validate model/spectator input with validateAnimSpec before drawing, and surface result.dropped to the user. - Deterministic: the same spec + signal + seed must give identical frames. Seed all randomness from the seed; never use Math.random or Date. - Draw with the palette only (palette.bg / palette.fg / palette.accent). - The host owns: canvas creation, audio → SignalFrame, file writing, playback.
The recipe
text
Build a small host + page:
1. server.js (Node 22+, ESM): import { createCanvas } from "@napi-rs/canvas"
and { drawSpec, validateAnimSpec } from "animspec". Render <describe the
scene> as <W>x<H> frames, seeded with <seed>, using this signal source:
<amplitude from the mic / a track file / a synthetic sweep>. Serve the
frames to the page as <MJPEG / WebSocket / PNG per frame>.
2. index.html: show the stream and these controls: <seed, spec JSON, sliders>.
3. Keep rendering deterministic; validate any user-edited spec and show
result.dropped on the page.
<the hard rules block>Pick a concrete shape from the use cases below, or write your own — the template (use-case-template.md) shows the structure each case file follows, and PRs that add one are welcome (see contributing).
Use cases
The default avatar. When a scene needs a person, reach for stickman: an articulated stick figure that acts (walk, run, jump, punch, kick, fall, dance), points or looks at a target, speaks the frame's label, stands where the host's coords say, and draws a whole crowd from one layer. It is in the core vocabulary, so a model sees it by default. The first three cases below are built on it; figure (silhouettes) and rig (a talking cut-out) remain for their own looks.
| Case | File |
|---|---|
| Live audio-reactive wallpaper (mic → frames) | live-wallpaper.md |
| Kinetic-type landing page | kinetic-type.md |
| Quote / testimonial wall | quote-wall.md |
| Stickman data narrator (points at a chart, speaks the narration) | stickman-narrator.md |
| Stickman scenes from a prompt (model-written clips: fights, dances, skits) | stickman-choreography.md |
| Interactive stickman (keyboard, games, crowds driven by host state) | stickman-interactive.md |
| Talking avatar (rig driven by mic or a track) | talking-avatar.md |
| Chat assistant with an animated presence ("Jarvis") | chat-assistant.md |
| Documentary staging (thought experiments) | documentary-staging.md |
| Spec sandbox (edit JSON → render → dropped report) | spec-sandbox.md |
| Static showcase (pre-rendered loops / CLI PNGs) | static-showcase.md |
What to check in the AI's output
- It did not import
animspecin browser code — the split above holds. - Every path that draws goes through
validateAnimSpec, andresult.droppedis shown. - The seed is a parameter, not a constant buried in the code; the same inputs replay.
- Text layers rely on the shipped fonts (no
font-familythat assumes a machine font). - Anything temporal comes from the signal or the frame index — never the wall clock.