namabotsMascot v2.1Draft · for review
3D · WebGL shader hover · hold still · tap · tap ×3
namabots mascot · v2.1 · draft

Same face. Now it has volume.

v2 keeps v1's locked identity: the cyan gradient body, two white eyes and no mouth. It adds a solid gumdrop body, eyes that move across it, a status light, reactions and a seasonal wardrobe. The product's state machine drives all of it.

Material (whole page)
State
Agent colourway + role prop
Anime emote
Reaction (one-shot)
Wardrobe
01

What changes from v1, and what stays

v1's mascot sheet stays canonical until this draft is approved. v2 changes the shape, the depth and the behaviour. Everything that makes it recognisable stays the same.

Stays (locked in v1)
  • Brand cyan gradient, running diagonally from top-left to bottom-right: #22d3ee → #0891b2
  • Two white eyes are the whole face. No mouth, nose, brows, cheeks or teeth.
  • Emotion comes from eyes, motion, props and status colour.
  • The hero mark and the wordmark "o" stay brand cyan. Agent colours are for agents only.
  • Props sit outside the body and never cover the eyes. No humanoid body, hands or antennae.
  • Rejected and error stay different: rejected slumps with drooping eyes; error uses round eyes and a shake.
Changes in v2
  • Circle → gumdrop. A superellipse with exponent n = 2.4, a 1.11 : 1 width-to-height ratio, and 7% narrower at the top than the base, so it sits heavy and stable.
  • Flat → lit volume. One lighting recipe, shared by the 3D and SVG versions.
  • Eyes move across the body, so the head appears to turn. It can even spin all the way round.
  • Status light and glow. An orb carries the status colour and is always paired with a text label.
  • Reactions (nod, giggle, curious, spin) answer the user without changing the product state.
  • Wardrobe: seasonal outfits under the same rule as props: outside the body, never over the eyes.
  • Two material options for review: glossy Candy, or translucent Jelly (slime).
  • Anime emotes: 14 expressions built from eye shapes and manga marks. Still no mouth. Blush hatching is the one exception to v1's "no cheeks" rule, pending approval.
02

Construction

The body is defined by one equation, so the 3D shader, the SVG and any future app icon draw exactly the same outline. All measurements are in R, the body's unit radius.

03

Light & material

A soft candy shell lit by a key light from the top-left at 35°. The layers below are the shading model. The 3D shader computes them per pixel; the SVG version approximates them with gradients.

Dark surface · ink #060b0f
Light surface · paper #f4fafc
Material options (draft: pick one)
Candy · dark
Jelly · dark
Candy · light
Jelly · light
Candy (current default)
  • Opaque, glossy shell: wrap diffuse, broad sheen, white rim light.
  • Strengths: the crispest at small sizes, and identical on any background.
  • Weakness: on light pages the white rim and broad sheen read as metallic or plastic.
Jelly (slime)
  • Translucent body: the renderer measures thickness through the body. Thin edges are clear, thick parts deep (absorption ×1.25). Opacity ranges 58–92%; the eyes stay solid.
  • Wet surface: a sharp highlight (exponent 160) plus a soft window reflection; no broad sheen.
  • Alive: the outline wobbles harder after hops and taps, and squash springs are looser (damping 8 instead of 14). No bubbles: anything inside the body competes with the eyes.
  • Light shadow: the ground shadow is tinted by light passing through the body.
  • Cost: one extra 28-step march per body pixel in 3D, covered by the same adaptive-resolution rule. Below 30 px it falls back to near-opaque, because translucency muddies tiny avatars.
Dark and light surfaces
  • The character never changes. Body gradient, eyes, lighting and status colours are identical on both surfaces.
  • Pale metal becomes slate ink on light (#e2e8f0 → #64748b): Mira's magnifier, Nila's wrench and the headphone band. Soren's orbit ring turns rose (#ffe4e6 → #e11d48).
  • Glow drops to 80% on light, so the colour tints the paper instead of fogging it. Sleeping z's switch to cyan ink.
  • The ground shadow stays at full strength. On white, the darker lower half and the shadow are what separate the body from the page.
  • Don't place it on cyan or teal surfaces (the body disappears). Use ink, paper, or an agent's own tint at ≤ 10%.
Recipe (shared by both renderers)
  • Base: agent gradient, diagonal TL → BR (the v1 rule)
  • Volume: half-Lambert wrap diffuse, 0.42 + 0.75·d²
  • Candy edge: base hue × Fresnel³ × 0.35, so the edge glows in the body's own colour
  • Rim: cool white × Fresnel³ × 0.35
  • Specular: Blinn, exponent 70, plus a broad sheen at exponent 10 × 0.07
  • Eyes: flat self-lit white, with no glow or halo. They never take shading, so they read at any size and stay graphic, like anime eyes.
  • Glow: a soft halo behind the body in the status colour, 0–45% depending on the state
  • Contact: 28% darker under the body, plus a soft ground shadow that shrinks when it hops
Colour tokens
04

Expressions: the eyes carry everything

There are five eye shapes: pill, crescent, line, round and droop. Gaze, eyelid, eye size, body motion and the status light turn them into eleven states. Every tile below is live; tap one to send that state to the hero.

Anime emotes · 14

Short expressions that play on top of any state: bot.emote("love"). They're built from eight more eye shapes (heart, ><, star, smug, dot, ring, wink, angry) and flat manga marks (blush hatching, sweat, anger mark, tears, gloom lines, sparkles, hearts, surprise lines). There is still no mouth.

Open the Emote Playground → full-screen stage, tap any emote, auto-play reel

05

State machine & interactions

The product sets the state, and the mascot never changes state on its own. People trigger reactions: short one-shots that play on top of the current state and then hand control back. Idle is the hub. Tap a node to preview it.

idle
  • Expression changes always go through a blink: close 90 ms, swap while shut, open 140 ms.
  • The status light swaps in three steps: shrink (90 ms), change colour, then pop back (280 ms, overshoot).
  • Entrances (hop, shake, wave, slump) play once, then settle into that state's loop.
  • Status colour never appears without a matching text label. Sleeping is the only state with no blinks.
Product statusStateEyesBodyLight
Person doesReactionWhat it looks like
Moves the pointer nearbylookEyes follow with a soft limit, tanh(dx/260), so far-away pointers never pin the eyes to the edge
Hovers over itnoticeOne blink; eyes grow ×1.08
Holds still on it for 1.9 scuriousLeans toward the pointer, lifts slightly, eyes ×1.18
Taps itgiggleSquish, crescent eyes for 1.1 s, a quick wobble. Wakes it if it's asleep.
Taps 3× within 1.7 sspinA full 360° turn; the face goes round the back and comes back (an easter egg)
Product accepts a tasknodTwo quick nods: "got it". The state doesn't change.
06

Motion

The same named curves as the namabots title reel. Scripted moves are keyframe tweens that briefly "lock" a property; springs take over again when they finish. Nothing fades in.

TokenValueUsed for
blink90 ms close · 30 hold · 140 ms openEvery 2.2–5.5 s at random; 22% are double blinks. Also used to swap expressions.
saccadespring k 320 · c 30Gaze jumps: idle wandering every 0.8–3.2 s, and the working "reading" scan every 320 ms
squashspring k 420 · c 14Breathing, landings and anticipation. Volume is preserved: x and z scale by 1/√s. Range 0.84–1.12.
breathe±1.4% · 3.2 sAll awake states (sleeping uses ±3% over 4.6 s)
hopcrouch 140 · rise 250 · fall 240 · land 90 msApproved. Lift 0.42 R; stretches to 1.12 on the way up, squashes to 0.86 on landing, then overshoots back.
shake5 keys · 480 msError: tilt and turn in opposite directions, then it settles
wave5 keys · 1.3 sGreeting: a side-to-side wobble with a small hop
light swap90 ms in-out → 280 ms backThe status light shrinks, changes colour, then pops back
battery10 fps while asleep · 0 fps off screenSleeping only needs a slow breath, so it renders less often
reduced motionprefers-reduced-motionA static pose for each state, with no wandering, blinks, entrances or reactions. The hero renders single frames.
07

Agents & wardrobe

Every agent uses the same body. Only the gradient hue and one role prop change. Outfits are seasonal and use the same rule: outside the body, never over the eyes, one at a time. The hero and the "o" in the wordmark stay brand cyan.

Wardrobe
08

Sizes & level of detail

The same component simplifies itself as it gets smaller. Below 30 px it drops the rim, highlight, props, glow and shadow, and keeps the eyes at least 1.6 px wide so the face never disappears.

Working Mira · Ready for you Soren · Asked you something Kato · Approved Kato · Changes requested Nila · Failed check Off hours
  • 16–28 px (favicon, status chips): gradient and eyes only. The status light becomes a solid dot.
  • 30–59 px (lists, avatars): adds volume, glow, the status light and hats. Side props and rim are still off.
  • 60 px and up (cards, hero): the full recipe. Use the 3D hero only on marketing pages and empty states.
09

Tech choice: researched, then built

Requirements: it must look 3D, many mascots must fit on one screen (rosters, status chips), it must stay crisp from 16 px to the hero, run smoothly on mid-range phones, and stay light. Sizes below were measured on 2026-10-04 from the jsDelivr CDN, gzipped.

OptionDownload (gz)Real 3DDozens on screenVerdict
three.js r180~179 KBYesNo: one WebGL context eachOverkill for one rounded shape with eyes. Worth it only if we later need real models, physics or a full scene.
Rive (canvas-lite)~475 KB (JS + WASM)No (2D)YesHas a strong built-in state machine, but every expression must be hand-built in the Rive editor and the runtime is the heaviest here. Revisit if a motion designer joins.
anime.js v4~41 KB (full)No (2D/DOM)YesGood tweening, but a 60-line keyframe engine plus springs covers everything this mascot needs.
Spline runtime~37 KB + scene filesYesNoScenes are authored in Spline's hosted tool, loaded as extra files, and can't be driven state by state as easily.
Canvas 2D (Coucou's approach)0 KBFakedYesProven and light, but each shape is hand-drawn per frame and the hats need their own projection maths. Our SVG tier plays the same role with crisper small sizes.
Custom: SDF shader + SVG (this page)~17.5 KB
SVG 10.9 + 3D 6.6
Yes (ray-marched)Yes (SVG tier)Chosen. The shader draws the real lit 3D body, hats and props for the hero. The SVG component uses the same lighting recipe and the same state machine for everything else. No dependencies.
Two tiers, one brain
  • 3D hero: one canvas running a WebGL1 fragment shader. The body, status light, props and outfits are signed-distance shapes, ray-marched with soft silhouettes.
  • SVG component: <nama-bot>. All instances share one animation loop, pause when off screen, and drop to 10 fps while asleep. Detail drops automatically by size.
  • Shared: the Bot brain (springs, keyframe tweens with locks, blinks, reactions) outputs one pose that both renderers draw.
  • Performance budget: pixel density capped at 1.75; resolution drops automatically if frames exceed 24 ms; falls back to SVG without WebGL; honours reduced motion.
Usage
<!-- anywhere in the app -->
<nama-bot state="working" agent="mira" size="48"></nama-bot>
<nama-bot state="idle" outfit="diya" interactive follow></nama-bot>

// product state → mascot state
el.setAttribute("state", "waiting");   // blinks, light swaps
el.bot.react("nod");                    // task accepted

// hero (marketing / empty states only)
const hero = new NamaHero(canvas, { agent: "brand" });
hero.bot.set("approved");              // hop + crescents
10

Reference: Coucou

We studied Coucou by Louis Raillé, a notch companion whose mascot, Mochi, shows coding-agent status. Its code is MIT-licensed. Its name, the Mochi character, artwork and sounds are all rights reserved (see its LICENSE-ASSETS.md). So we borrowed engineering ideas and deliberately kept the character our own.

Borrowed: techniques (MIT, credited here)
  • Keyframe tweens with locks: a scripted move owns a property until it finishes, then the springs take it back.
  • Indicator swap: shrink, change, then pop back with overshoot (we apply it to the status light).
  • Pointer-follow with a soft limit: tanh-limited gaze, and 22% double blinks.
  • Status glow behind the character, varying in strength by state.
  • Battery care: no rendering when hidden, and a reduced frame rate while asleep.
  • Interaction vocabulary: hover, dwell, tap and multi-tap as separate gestures; a wardrobe as a separate layer from state.
Not taken: the character (all rights reserved)
Mochi (Coucou)namabot v2
BodyWhite/cream, wide 1.30 : 1, n 2.7Cyan gradient gumdrop, 1.11 : 1, n 2.4, tapered
EyesDark ink, many shapes (hearts, stars, spirals)Self-lit white, five shapes, no symbols
Face extrasBlush cheeks; mouth for some movesNone (the v1 rule)
StatusTints the body; pill badge with •••, !, ?Body keeps its agent colour; a glowing orb plus a text label
Signature movesRoll on finish, dizzy spiral, swallowing filesHop on approve, slump on reject, a nod, a full 3D spin
RendererCanvas 2D (Swift, plus a TypeScript port)SDF shader (real 3D) + SVG
11

Do / Don't

Additions to the v1 rules. The v1 rules all still apply.

✓ Do

  • Drive the mascot from real product state, and always show the status in words next to it.
  • Swap expressions through a blink, and the status light through a shrink-and-pop.
  • Keep the hero and wordmark brand cyan. Use agent colours only when you mean that agent.
  • Let it look at the user when it needs them (waiting, question, error, greeting).
  • Use the SVG tier in product UI and the 3D hero only on marketing pages or empty states.

✕ Don't

  • Add a mouth, brows or limbs, even for a single "fun" emote. Blush hatching is the only cheek mark.
  • Use crying or gloomy emotes for real failures or data loss; they're for playful moments only.
  • Cover the eyes with props or outfits (glasses, visors, masks).
  • Loop entrance animations (endless hopping or shaking reads as broken).
  • Use the status light colour as the only signal of state, or tint the body by status.
  • Copy another mascot's look or signature moves. Coucou's Mochi is a reference, not a source.
  • Render more than one 3D hero per page, or use 3D at under 120 px.