Work / Tic Tac Toe / Wiki / Decisions
2026-09-22-design-peripherals-standardised
Decisioncanonicalverified 2026-09-22
DECISION.2026-09-22.DESIGN-PERIPHERALS-STANDARDISEDDecision
This set adopts the estate-wide design peripherals: one surface folder per
surface, the six-section gallery, the generated breadcrumb and surface switcher,
the closed variant vocabulary, and a single hand-authored shared.css.
Why
Nine products had drifted into two incompatible shapes, and a reader who had learned one set could not navigate another. The UX is deliberately per product; everything around it should not be.
This set was migrated first because it is the smallest, so the pattern could be proven on seven screens before being applied to chitragupt's 269.
Impact
routes.jsadded: the one place a screen is declared. The gallery, the chrome bar and the screenshots sheet all read it, so the screen order cannot disagree with itself any more.- One screen per file. The theme is now a toggle in the chrome bar rather than a second frame — a frame has no URL, so it could not be linked, listed or listed on the screenshots sheet.
- No prose in any screen file. The rationale moved to
.context/wiki/surfaces/*.mdand is rendered beside the screen on demand by the notes drawer, collapsed by default. - The frame is scaled to the viewport. 390×844 plus a chrome bar is taller than a laptop screen, so every screen previously needed scrolling to show its own bottom.
core.css,tokens.cssandlocal.cssfolded into oneshared.css. They carriedGENERATED — DO NOT EDITheaders pointing at a generator that has been deleted; the headers were lies the moment it went.home/index.html→home/start.html— noindex.htmlinside a flow.states/ads.htmlsplit intostore/banner.html,store/banner-empty.htmlandstore/ads-off.html;states/is reserved for 404/500/offline/maintenance.
Two states very nearly lost
Splitting the side-by-side frames, the second frame looked like a dark-theme
duplicate and was dropped. It was not. board.html's second frame was
"Computer is thinking" — the app's only loading state — and
result.html's was the draw outcome. Both were restored from git as
game/board-loading.html and game/draw.html, and result.html became
win.html so the pair is named for what each is.
The lesson is in the standard now: a second frame is only ever a theme when you have read it, and two of three were carrying real content.
Two factual errors corrected
- The wireframes cited
src/lib/ads.ts. Ads live insrc/config/, the interstitial insrc/hooks/. The path has never existed. CLAUDE.mdclaimed banner-only monetisation whileuseInterstitialAd.tsships andsrc/app/game.tsximports it.
One bug in the theme scope
.phone--dark remaps the tokens, but text with no colour class inherits the
computed colour from body, resolved in the light scope — so "Your turn" (and
anything like it) stayed black in a dark frame. .phone now sets
color: var(--ink) itself. A variable remap only reaches declarations that read
the variable; inheritance carries the old value, not the new name.
Status
Active.
Sources
- ~/git/products/CLAUDE.md — the standard
Every project of mine is written down like this.
Read the résumé