mascot-stage · git:20260802.24ef542 · 2026-08-02 · sha256 1f1c2b9fd1027da2

mascot-stage git:20260802.24ef542A

Immutable. This exact content is served forever at /api/v1/blob/1f1c2b9fd1027da2.

---
name: mascot-stage
description: Working on LUCID the ninja mascot (desktop/renderer/mascot.ts, immersive stage, P-MASCOT arc, ADR-0251 pivot). Use when touching mascot frames, animation states, activities, stage mounting, or doing visual QA in the preview panel - it encodes the settled art direction, the pixel-frame conventions, and the preview QA workflow.
---

# LUCID the ninja - the mascot stage

First-party skill, authored in-repo (2026-08-01, P-MASCOT.1 session). Supersedes the retired
`threejs-stage` skill (the talking-head + particles direction was killed by the user the same day it
shipped; three.js was removed from the repo with it).

## Art direction (user-set, load-bearing)

- LUCID is a FUN, COOL game character: an original fighting-game-style pixel NINJA. Chibi proportions,
  navy gi, neon-green (#41ff8b) headband/belt/scarf - the brand accent.
- **He does things**: practices kata, throws shuriken, meditates while the agent works; guards while
  the mic listens; gestures while replies speak; hits a victory pose when a turn lands; breathes and
  blinks when idle. The mascot must STAY IN LINE with real session state - never a looping GIF vibe.
- **History**: two 3D face attempts died here ("scary", then "still very bad"). Faces and particle
  humans are OFF the table - pixel-art characters are immune to the uncanny valley by construction.
  Do not resurrect the face without an explicit user ask.
- Original character only - inspired by the fighting-game GENRE, never a copy of an existing fighter.

## Pixel-frame conventions (desktop/renderer/mascot.ts)

- Frames are 20x26 char grids over MASCOT_PALETTE; '.' = transparent. Every frame derives from BASE
  via `rows(BASE, {overrides})` so the character stays on-model - author DIFFS, not new drawings.
- Keep silhouettes readable at small scale: one-pixel outlines ('k'), chunky limbs, high contrast
  between gi (K/D) and accent (G). Test: squint at an 8x scale render.
- Animation = beat tables (frame + ms). Working activities rotate every ~6.5s via `workActivity`.
  The state machine (`stepMascot`) is PURE and tested: victory fires on working->done, victory always
  finishes, speaking > listening > working > idle.
- Painting is nearest-neighbor fillRect at integer scale, DPR-aware, bottom-center anchored. No
  smoothing, no fractional scales - that is what keeps it crisp.

## Layout hazard (live bug, 2026-08-01)

- `.body` is a 5-track grid whose children include the rails AND the right-edge panels (Settings,
  Skills, ...). NEVER `display:none` a `.body` grid child: removal re-slots every later sibling into
  earlier tracks (the center collapses into an `auto` track, Settings lands mid-screen). Collapse IN
  PLACE instead - `width:0; min-width:0; opacity:0; pointer-events:none; overflow:hidden` (with
  `!important` where a resizer sets inline widths). demo-P-AVATAR.1 enforces this with a regex gate.

## Preview QA workflow (sharp edges, learned the hard way)

- The preview panel auto-opens ONLY on a direct write-tool call; `tool.write` from eval does not
  switch pages. Screenshots are cached PER PAGE LOAD - bump the html (version comment) to force a
  reload before a fresh capture.
- Harness pattern: bundle a tiny entry that mounts the mascot with a state-cycling driver, write a
  sibling .js + small .html (the panel inlines relative assets; single files over ~300KB choke it).
- Generated QA bundles under desktop/ need the BUSL header or the license gate fails; delete `_qa_*`
  scaffolding once the user has looked.