Design system

How the app looks the way it looks: tokens, block colours, terrain themes, entity art and skins. The authority for styling lives in two places: styles/theme.css (the shared palette, breakpoints, typography, radii, shadows and the v-* height variants) and src/style.css (Tailwind entry, app-specific tokens, entity art, [data-*] selectors, browser quirks). styles/global.css holds the base element styles; everything lives inside this app, there is no separate design package. The .agent/ folder's color-sweep.md keeps the same information for contributors.

The token system

Tailwind v4 @theme declares semantic tokens; components use semantic classes, never raw palette colours:

GroupTokens
Accentprimary, primary-hover/-active, primary-light, primary-dark
Surfacessurface, surface-raised (+ -hover/-active)
Contentcontent, content-raised, content-masked
Bordersborder, border-masked
Statussuccess, warning, error, info

App-specific additions in src/style.css:

Block chrome

BlockShell (see Blocks) is the single source of block chrome: the clipart body, the top notch and bottom nub, the variant map and the drag-over colour swap. Block colours are solid 80% or washed 60% opacity with a 4 px backdrop blur; 70/50 was tried first and looked muddy when containers nested, so the values are what they are on purpose. --block-height is the shared height so every block, including the Start head, aligns.

Terrain themes

A level names a theme per block kind through looks; the theme is an identifier, never a class. src/terrain.css maps each data-terrain + data-kind pair to a colour token and a procedural texture, with the rule that ground and wall of a theme are different images (different frequency, seed, scale or offset), never the same image. The art direction:

Textures are tileable (stitchTiles noise or <pattern> shapes), large (72-160 px), and every cell paints from the same origin, so tiles stay perfectly square and aligned. The --tex-block grain is shared by the block bodies and the cheese so entities read as part of the same world.

Entity art rules

Flat art only: filled shapes, no strokes, outlines or gradients. Friendly and non-violent by design (a game for all ages). The mouse, cheese, lava and hole are described in detail on The playground.

Skins

data-player-skin='blue' | 'pink' overrides --color-player, so it works on <html> (the live game, set by lib/skin.ts) and on any element (the picker options render a preview mouse in each skin). The choice persists in localStorage under bunplate:player-skin.

Responsive scale

Sizing scales with the viewport instead of breakpoint jumps: clamp() for block padding and text, the v-* custom variants (v-xs through v-3xl) for spacing, a fixed clamp() height for the palette (it must not grow or shrink between levels), and explicit per-breakpoint widths for the level's left column so the palette keeps its width even while its blocks are hidden during a delete drag.

Next: Persistence.