The dashboard's design system
commission serve renders the observer view: the pages a human opens to see what
their agents are doing and what needs them. This page says what its design is,
what it borrows, and — more usefully — what it deliberately does not.
Everything visual here is generated from site/src/styles/tokens.css into
src/server/tokens.ts by bun run generate:tokens, and tests/design.test.ts
fails if the two have drifted. There is no second place to change a colour.
Three systems, not two
site/README.md opens by splitting the marketing site in two: / uses a
product system, /technical and /design use a documentary one. The
dashboard is a third case, and the split is the same kind of argument.
| surface | system | read |
|---|---|---|
/ (the landing page) | product | once, by someone deciding |
/technical, /design, /blog | documentary | once, carefully, in order |
commission serve | operational | many times a day, by owner |
A landing page has to stop somebody scrolling. A reference page has to be readable end to end. An operational page has to be instantly legible to somebody who has already seen it two hundred times — which is a different job from either, and it is the one the dashboard is designed for.
The consequences follow from that sentence:
- Nothing is a reward for arriving. No entrance animation, no loop, no
stage, no scroll indicator. All of them are first-impression devices, and by
the third visit of the day they are a tax.
tests/design.test.tsasserts the stylesheet contains no@keyframesand noanimationat all. - Nothing is larger than it has to be. The type scale is the site’s, and it
stops at
--t-h1(32px); the four display steps above it are unavailable to this surface. The page title is--t-h2(26px), because the project name is already in the bar above and in the tab strip below. - Whitespace is not automatically an upgrade. A reader here is scanning for the exception, and every row pushed below the fold is a row they have to scroll to find. Space is spent where it separates kinds of thing and reclaimed everywhere else.
- Colour is state. See below.
What carries over from the landing page
The colour identity, the type scale, the 4px spacing rhythm, the 4px/2px radii,
the chip and badge treatment, the two designed themes, and the confidence to
use a saturated brand colour at all. The site’s mono micro-label — uppercase,
0.09em, faint — is the section heading here, exactly as it is on
/technical: it marks what a block is and never carries the argument.
What does not, and why
Named with reasons in CLASSIFICATION in scripts/generate-tokens.ts, which
throws on a token it has not been told about — so a value added to the site
cannot leak into an operational tool because nobody looked. The headline
exclusions:
| excluded | why |
|---|---|
--c-stage* | a dark ground that ignores the reader’s theme; a tool honours it |
--glow-* | the hero aura — decoration with no state to report |
--t-display* | a 92px condensed headline on a page read daily is shouting |
--c-grad-* | gradient text is a landing device; a heading read daily should be ink |
--dur-loop, --dur-entrance, --reveal-step | nothing here should arrive late or move on its own |
--shadow-brand | a coloured glow would compete with the status colours |
--space-section | 4.5rem is a scrolling page’s pace; the operational scale is --sp-*, on the same 4px step |
Colour means a state in the task graph
The site’s rule, and it binds harder here because a person is triaging. Commission has five statuses; the site names four semantic colours. The mapping, and the one extension:
| colour | means |
|---|---|
--c-accent | links, in_progress |
--c-ok | done, criteria met, evidence present |
--c-warn | blocked (derived), a gate not yet satisfied |
--c-refusal | cancelled, a refusal, a divergence |
--c-brand-violet | a person is needed — in_review, and the two judgement controls |
--c-brand | the wordmark, and nothing else |
Violet is the extension and it is the surface’s one idea. in_review is the
state that means a human has to look, and the approve and answer controls are
where a human looks. Giving them one colour makes the write surface findable
and makes the read-only boundary visible rather than merely true: a violet
chip is a task waiting on a person, and a violet control is the only place
in the whole view where a person can act on one. Nothing else is violet.
--c-brand appears exactly once, as the mark in the wordmark. A dashboard that
painted its brand across the chrome would be spending attention it needs
for state.
Colour is never the only signal. A dot always travels with its word. Where
a row’s status chip is suppressed, it is because the section heading above it
is that word for every row underneath — IN REVIEW over three rows beats
three chips saying “in review”, and the dot is aria-hidden so assistive
technology gets the heading instead.
Constraints that are features
These are not incidental and must survive any future work here.
- Server-rendered, no client JS beyond native elements.
<details>and<form>are the whole interaction budget. That is why this view works over SSH on a bad connection, and it is worth more than any animation.tests/web-inbox.test.tsasserts the page ships no<script>and noon*attribute. - The stylesheet is inline and self-contained. No stylesheet link, no font
file, no CDN — asserted by
tests/design.test.ts. The fonts are named (IBM Plex Sans / Mono, falling back to the system UI face), not shipped: a single-file binary serving three webfonts would be a heavier page over exactly the connection this view exists for. The type scale is what carries over; the face is a bonus where it is installed. - Every route is a GET except four. The judgement routes under
/p/:slug/inboxare the only mutations, they live in their own sub-app, and the route table is asserted. commission servenever readssite/. The tokens are compiled in.
Themes
Two designed themes, following prefers-color-scheme. There is no toggle,
and that is a consequence of constraint 1 rather than an oversight: a toggle
without client JS means a route that writes a cookie, and the read-only
boundary is worth more than a toggle. It is on the list in
docs/design/dashboard-beta.md.
Verifying a change
bun run generate:tokens # after any change to the site's tokens
bun test tests/design.test.ts # drift, colour literals, spectacle, scale
bun run scripts/shoot-dashboard.ts .screenshots/dashboardThe last one seeds a scratch database with real commands, serves it, and photographs every page at 390px and 1440px in both themes, reporting page height and failing on horizontal overflow. Read the heights: on this surface a page that got taller for the same content is a regression.
This page is docs/design/dashboard.md in the Commission
repository, rendered in place — the site keeps no copy of it. The repository is private, so there is no edit link to follow.