Mascots#
A mascot (msc_…) is a character in your workspace. It has a name, a status (generating, ready or failed), a source (prompt, image or svg), and a current version. Every change (a generation, rebuild, edit, variant, recolor or a spec you upload) adds a version, so nothing is overwritten; restoring an old version just points the mascot back at it.
The mascot object summarises its current drawing: the palette tokens, the parts (id, parent, alternate states, whether it rotates), its saved animations, a versioned preview_url and the bundle_url the player loads. Pass ?include=spec to get the full drawing as well.
{
"id": "msc_…", "object": "mascot", "name": "Mothley", "status": "ready", "source": "prompt",
"public": false, "fidelity": null, "needs_review": false,
"version": { "id": "ver_…", "kind": "generate", "label": "Generated", … },
"palette": [{ "name": "wing", "color": "#8B7CF6" }, …],
"parts": [{ "id": "body", "parent": null, "states": [], "rotates": false }, …],
"animations": [{ "id": "anm_…", "name": "idle", "source": "preset", … }, { "name": "wave", … }],
"preview_url": "/api/v1/mascots/msc_…/preview?v=ver_…",
"bundle_url": "/api/v1/mascots/msc_…/bundle"
}Rigs#
The drawing behind a mascot is a MascotSpec: vector parts in a hierarchy. Each part is an SVG fragment drawn at its rest pose, with a pivot (the joint it turns around), optional rotate limits in degrees, a draw order, and alternate drawings called states (eyes open/closed, a mouth smile/o). Children inherit their parent's motion, so an arm swings with the torso it hangs from.
Colours are palette tokens: the SVG says fill="$fur", and the palette says what fur is. That is why a recolor is instant and free, and why the player can recolor at runtime.
The generator and the rebuilder check their own rigs before they hand one back: every submission is validated, rendered, and checked for joint gaps and weak joints, and the renders go back to the model as images until it passes.
Animations#
An animation (anm_…) is a saved AnimationClip: keyframed tracks on parts (rotate, translate, scale, opacity, state) plus procedural modifiers (breathing, blinks, spring follow-through on tails and antennae). Clips move parts around their pivots, so the drawing itself never changes.
| Kind | source | How | Cost |
|---|---|---|---|
| Preset | preset | One of 15 motions, fitted to this rig on the spot. | Free, instant |
| From words | prompt | The Animator agent choreographs a motion you describe. | 20 credits, a job |
| From video | prompt | The Animator watches sampled frames of a reference clip and performs it. | 20 credits, a job |
| Hand-authored | custom | You send an AnimationClip; it is validated against the rig. | Free, instant |
Every new mascot starts with idle and wave saved, so embeds and exports work the moment it is ready. Anywhere the API takes an animation reference (exports, scenes, canvases, previews) you can pass an animation id, an animation name, or a preset id; presets are always available even when not saved.
Canvases#
A canvas (cnv_…) is a state machine over a mascot's animations. States play clips; transitions fire when inputs change (booleans, numbers, or one-shot triggers) and blend the poses over a fraction of a second. Your app sets inputs like thinking = true and the mascot does the rest. Start from a template (chatbot, ai_agent, onboarding) or send your own graph. Canvases are free and travel in the player bundle. See Interactive canvases.
Jobs#
Anything slow is a job (job_…). The request that starts one returns immediately (202) with the job; the result lands on the job and on the mascot when it finishes.
Lifecycle#
queued ──► running ──► succeeded
├──► failed (error says why; credits are refunded)
└──► canceled (POST /jobs/{id}/cancel; credits are refunded)Types#
| type | Started by | result |
|---|---|---|
generate | POST /mascots with prompt | mascot_id, version_id, rig_ok, summary |
reconstruct | POST /mascots with upload_id / image_url | … plus fidelity, needs_review, compare_url |
edit | POST /mascots/{id}/edit | version_id, summary |
variant | POST /mascots/{id}/variants | version_id, summary |
animate | POST /mascots/{id}/animations (prompt or video), /animations/batch | animation_id, animation, summary |
export | POST /mascots/{id}/exports | file (id, mime, bytes, url) |
scene | POST /mascots/{id}/scenes | svg, png files, summary |
suggest | POST /mascots/{id}/suggestions (waits for you) | suggestions |
analyze | POST /analyze | brand summary, tone, 3 mascot concepts |
Waiting#
- Long-poll:
GET /jobs/{id}?wait=60holds the request until the job finishes or the wait (max 120 s) runs out. - Stream:
GET /jobs/{id}/eventsis server-sent events. It replays history (resume with?after=<seq>orLast-Event-ID), then streams live, and closes afterfinished. - Push: a webhook gets
job.succeeded,job.failedorjob.canceled.
Events#
| event | Carries |
|---|---|
queued | The job was accepted. |
started | A worker picked it up. |
progress | text: a short note from the agent ("Placing joints…"). |
tool_call | tool: the agent started a tool call (drawing, patching, reviewing). |
tool_input_delta | tool, delta: streamed tool input, e.g. the spec as it is written. |
tool_result | tool, is_error, summary. |
draft | spec, rig_ok (and fidelity for rebuilds): a complete draft you can render. |
draft_clip | clip: a draft motion from the Animator. |
usage | cost_usd so far and token counts. |
finished | status, error. The stream closes after this. |
Every event has a seq (1, 2, 3… per job) and an at timestamp. Every job reports cost_usd, the model spend so far.
Credits#
Credits pay for model work, at a fixed price per action. A new character is 80 credits, a rebuild 120, a custom motion 20, a chat edit 40. Presets, recolors, canvases, previews, embeds and exports are always free. The Free plan includes 200 credits a month.
A job holds its price when it starts and gets it back if it fails or is canceled. Without enough credits the request is refused up front with 402 insufficient_credits, before any work starts. Full table: Credits & limits.