Skip to content

apps/client/src/theme ​

The game's design tokens, one source of truth for how every interface looks: a Material-like theme in theme.ts, typed, without React or the DOM but for the one call that puts it in a page.

Token groupIn theme.tsCSS custom propertiesWhat
PalettePALETTE--foi-color-<role> (primary, on-primary, primary-container, surface-high, text-medium…)The primary (the main menu's orange) with its hover, deep shade, container and the colours on them; a secondary and a tertiary; the background and five surface levels; the panels over the game; text at high, medium and disabled emphasis (and the menus' warm text); outlines; error, warning, success, info with their containers
TypeTYPE--foi-type-<step> (the font shorthand), -size, -line, -weight, -trackingDisplay, headline, title (lg, md, sm), body (lg, md, sm), label (lg, md, sm), all in Changa (--foi-font-family)
SpacingSPACE--foi-space-0 … --foi-space-100, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64 px
RadiiRADIUS--foi-radius-xs to --foi-radius-full4, 6, 10, 16, 24 px (xs, sm, md, lg, xl) and a pill (full)
ElevationELEVATION--foi-elevation-0 … --foi-elevation-5Shadows on a dark ground, from flat to a dialog
MotionMOTION--foi-duration-<name> (instant, short, medium, long), --foi-easing-<name> (standard, emphasized, decelerate, accelerate)How long a change takes and how it eases
LayersLAYER--foi-z-<layer> (base, sticky, menu, popover, dialog, toast, tooltip)The z-index of each layer
Focus--foi-focus-ringThe ring a control shows when the keyboard reaches it

themeVariables() names every token, themeCss() writes them on :root, and installTheme(document) puts that style sheet first in the page; ui/mount.tsx calls it before any tree is drawn. Everything else derives from it:

  • the web UI's components (../ui/kit, kit.css) and the game pages (../ui/browse.css) use the --foi-* properties alone;
  • the overlay's tokens (--ui-fg, --ui-accent… on #ui, ../ui/overlay.css) and the menus' (--menu-hot, --menu-fg…, ../ui/menu.css) are aliases of them, so older rules keep working;
  • the in-game GUI drawn in the scene (../gui/theme.ts' COLOURS) takes the palette's values.

So a colour changed in PALETTE recolours the game pages, the overlay, the menus and the game's own panels at once (theme.test.ts holds the GUI to the palette). A new token is a field here first, then its use; never a colour written into a component's CSS.