MaestroFor agentsDesign systemSource

Design system

The Workshop Notebook. A warm-paper workbench for reading, judging and correcting the design of a game. Every token, every named rule and every shared component, rendered by the system itself.

Colours

Ledger Paperpaper#f7f3e9 oklch(0.965 0.014 88)dark #1c1913
Deskground#efe9dc oklch(0.935 0.018 86)dark #13100b
Leafraised#fcfaf4 oklch(0.985 0.008 88)dark #26221c
Bister Inkink#2c221b oklch(0.260 0.020 55)dark #e7e2d9
Pressed Inkink-hover#1b130d oklch(0.195 0.018 58)dark #faf6ef
Sepiamuted#6e625a oklch(0.505 0.020 58)dark #9a9289
Hairlineline#d8d2c7 oklch(0.865 0.016 82)dark #36312a
Strokeline-strong#8e8279 oklch(0.615 0.020 62)dark #81776d
Kiln Rustfocus#9c470d oklch(0.500 0.130 48)dark #d78958
Rust Inkfocus-ink#fbf8f2 oklch(0.980 0.008 88)dark #17130e
Alarmdanger#a72629 oklch(0.480 0.165 25)dark #e67a73

data-1 … data-8 · inside diagrams and legends only, never in the chrome

Type scale

displayThe page title, once per screen. Literata. Literata 600 · 1.75rem / 1.15
Vael Crypt
headlineSection headings: the tool's own words, so Fira Sans. A page title is the game's word and stays Literata. Fira Sans 600 · 1.25rem / 1.3
The ash well
titlePanel headings and group titles. Fira Sans. Fira Sans 600 · 1.125rem / 1.35
Types in this game
bodyEverything the tool says: cells, fields, buttons, navigation. Fira Sans 400 · 0.875rem / 1.5
105 quests, 12 shown, sorted by level
proseThe game's own writing. Literata, capped at 68ch. Literata 400 · 0.95rem / 1.6
The well does not give back what is thrown into it. Vael knows this, and still they go down: once a year, with the rope measured and a dead name in the mouth.
labelColumn headers, rail headings, metadata keys. Sentence case. Fira Sans 600 · 0.75rem / 1.2
Requires
monoSlugs, keys, pointers, versions. Anything copyable. ui-monospace 400 · 0.78rem / 1.4
requires_ability: "mothwing_cloak"

Elevation

restingA panel separated from the ground. Static surfaces.0 1px 2px rgba(94, 72, 55, 0.12)
liftedSomething the user opened: the game switcher, a menu, a panel over the canvas.0 2px 9px rgba(94, 72, 55, 0.14)
floatingA surface over the whole page. At most once per screen.0 10px 30px rgba(94, 72, 55, 0.18)

Shared components

Primary Button

The single most likely action on a screen. Ink on paper, never accent-filled.

Ghost Button

Every secondary action. No fill until hover.

Text Input

Leaf fill on paper, rust border on focus. No glow.

Filter Chips

Exactly one selected per group. The selected chip is the only place the accent fills anything.

Game Switcher

Always present inside a game. Marks the current game with weight and aria-current, never with colour.

Read-Only Notice

States the limitation where the missing button would be, rather than leaving it to be inferred.

Read-only, written by the agent

Prose Block

The game's own writing, in the serif, capped at 68ch.

The well does not give back what is thrown into it. Vael knows this, and still they go down: once a year, with the rope measured and a dead name in the mouth.

Breadcrumb

Says where you are as well as where you came from. Replaces every one-off back link.

Negative States

Empty, loading and refused in one shape. No box, no stripe, capped at 62ch. Loading appears only after 200ms.

Nothing here yetThis game has no saved views. An agent writes one over MCP.
Loading…Shown only after 200ms, so a fast answer never flashes.
That did not loadThe server answered 500 for this catalogue.

Catalogue Table

The signature surface. Uniform 36px rows, serif names with the slug inline, named absences, tabular numbers, scrolling in its own container rather than squeezing.

QuestZoneRequiresLevel
The ash well ash-wellVael CryptMothwing cloak12
Shadow market shadow-marketno zoneno requirement4

Page Header

One row, one order, on every screen: wordmark, game switcher, destinations, spacer, account, sign out.

MaestroHollow Reach ▾ivan

Scales

Spacing

  • xs 4px
  • sm 8px
  • md 12px
  • lg 16px
  • xl 24px
  • xxl 32px
  • xxxl 40px
  • gutter 24px
  • rail 280px
  • page-max 1440px

Radius

  • sm 3px
  • md 5px
  • pill 999px

Density

  • header-height 48px
  • breadcrumb-height 32px
  • row-height 36px
  • row-compact 28px
  • control-height 32px
  • prose-measure 68ch
  • state-measure 62ch

Motion

  • ease-out-quart cubic-bezier(0.25, 1, 0.5, 1)
  • duration-state 120ms
  • duration-disclosure 180ms

Breakpoints

  • narrow 780px
  • rail-folds 1100px
  • table-min 720px

Named rules

  • The Two Exemptions Rule. The chrome is achromatic. Exactly two chromatic tokens exist outside the data palette, accent and danger, and a third is admitted only against this test: not 'would a colour help' but 'is there a fact on screen that nothing else says'.
  • The Ink Button Rule. The primary button is ink on paper. A button filled with the accent is forbidden.
  • The Two Grounds Rule. ground is darker than paper on purpose. The diagram lies on the desk; the reading panels are sheets on top of it.
  • The Two Voices Rule. The tool speaks sans, the game speaks serif. If it would survive the game shipping, it is serif.
  • The Rendered Prose Rule. A longtext value is the game's own writing and is markdown: a screen renders it and never shows the source. Two shapes, and the room decides which: a block in the Prose role, capped at the measure, where there is a column for it, and one clipped line in a 36-pixel row, with the whole of it on the thing's own page. The rendering is the server's, from the one renderer this product has, and it reaches the browser only on the browser's own route.
  • The Band Rule. A screen made of bands is a stack of peers: one section each, one Headline heading each, separated by xxxl and by a 1px line rule above every heading after the first. Nothing is ranked under a band by type size, because no two adjacent roles are far enough apart to say so, and nothing is ranked by face, because a face change means a change of owner. Two bands may stand side by side at 1200px and above, and only when they encode the same unit and are read against each other; the pair shares one grid measurement, and falls back to one column when either side has no rows.
  • The No Uppercase Rule. Labels are sentence case with light tracking. All-caps labels are the admin-panel tell.
  • The Copyable Is Mono Rule. If a value is a machine identifier a person might paste, it is monospace.
  • The Warm Shadow Rule. On the light ground every shadow is rgba(94, 72, 55, ...), the paper's own brown, and pure black is forbidden. On the dark ground it inverts: a warm shadow on a near-black desk is a rust halo rather than depth, so the dark set's three are black at .4, .45 and .5. The rule said "forbidden everywhere" for a whole build while the product and this page both did the opposite.
  • The Earned Elevation Rule. A shadow answers a question about stacking, never about importance.
  • The Named Absence Rule. Nothing is blank because a value is missing. Absent gets a word, empty gets a different word.
  • The Drawn Boolean Rule. A yes or a no is a mark and not a word: a check in data-5 for true, a cross in danger for false, the em dash of a Named Absence where there is no value. Three states, three shapes, and the shape alone carries the meaning — the hue is the second thing that says it, which is what keeps the column legible without colour. The word stays as the cell's accessible name. The mark is centred under the heading that names it in a column and sits beside its label on a thing's own page. The two marks are two paths rather than an icon set: the shipped font subset carries no check, and two shapes do not justify a library.
  • The Shadow Boundary Rule. An element selector in the global stylesheet does not reach inside a component's shadow root, and custom properties do. No component writes a bare button rule of its own; every one adopts the shared control stylesheet written in terms of var(--...).
  • The Never Hidden Rule. Navigation is never hidden without being moved somewhere reachable. Below 780px the destinations join the game switcher's menu; exactly one of the two carries them at any width.

Do and don't

Do

  • Do set every game-owned word in Literata and every tool-owned word in Fira Sans.
  • Do keep rows at 36px and lists dense.
  • Do tint every shadow on the light ground with rgba(94, 72, 55, ...), and let the dark ground use black.
  • Do name absences in words: 'no zone', 'never reviewed', 'no requirement'.
  • Do state read-only where the missing action would be.
  • Do mark the current item with weight and aria-current.
  • Do cap prose at 68ch.
  • Do build every repeated pattern once, as a shared component.
  • Do cap prose at 68ch, and nothing else.
  • Do let wide content scroll inside its own container so the page never scrolls sideways.
  • Do put a breadcrumb on every screen inside a game, and delete the back links it replaces.

Don't

  • Don't build the generic admin panel: no icon sidebar, no card grid of counters.
  • Don't reach for the dark blue SaaS dashboard.
  • Don't borrow GitHub's chrome.
  • Don't bury content the way the ad-choked game wiki does.
  • Don't produce the empty beautiful landing page.
  • Don't use #000 or #fff anywhere, including in a shadow.
  • Don't fill a button, a badge or a header with the accent.
  • Don't use border-left or border-right above 1px as a coloured stripe.
  • Don't set a label in all caps.
  • Don't nest a panel inside a panel.
  • Don't leave a cell blank when the value is absent.
  • Don't animate layout properties, and never use bounce or elastic easing.
  • Don't add a modal before an inline alternative has been ruled out in writing.
  • Don't put a measure meant for prose on the page.
  • Don't hide navigation at a breakpoint without moving it somewhere.
  • Don't write a bare element selector for a control inside a component and expect the global stylesheet to have styled it.

Generated from docs/design.md and docs/design-tokens.json by docs/design-system.mjs