Plan — phased execution
State: open/active · Genre: plan
Phases are ordered by leverage. Phase 1 items are independent, small, and individually PR-able. Later phases depend on Phase 0’s law being in place. Drift numbers reference SURVEY.md §3.
Phase 0 — Make it true, make it law
Section titled “Phase 0 — Make it true, make it law”- Rewrite
packages/ts/ui/docs/design-system.mdin place to match shippedtokens.css: both tiers, all 94 tokens, the 25-token contract, five themes, all axes, bridge direction--ui-* ← --d-*(drift 1, 15). - Mint D-DLNG-design-language recording identity, the four planes, and the six laws (PROPOSAL.md §4).
- Mint S-0010-design-language-consumption —
applies_tothe live app/product rings; names the allowed escape hatches (frozen apps, Obsidian plugin, shell-less static surfaces). - Answer PROPOSAL.md §6 open questions and record the answers in D-DLNG.
Phase 1 — Close the wiring gaps (inside the system)
Section titled “Phase 1 — Close the wiring gaps (inside the system)”-
shell.css:bodyfont becomesvar(--d-font-sans); size becomesvar(--d-density-font); delete the hard-coded stack (drift 2, 3). - Define or fix the four undefined token references: add
--d-status-dangeras an alias of--d-status-error(or fix call sites), and resolve--d-bg-secondary/--d-bg-primary/--d-border-primaryin the agent-pants experience (drift 4). - Retire the
shell.cssalias vocabulary; migrate the 12 call sites to--d-*(drift 5). - Icon policy: replace the 2 shipped heroicons uses (
DSidebar, app-frame layout theme toggle); add@iconify-json/lucideto@determined/ui’s own manifest; sweep stories (drift 9). - Graph experience: theme from
useDTheme()instead ofmatchMedia; stop stampingdata-theme="light|dark"(rename the attribute or pass the prop) (drift 6, 7). -
json-canvas-vue+obsidian-md+panes: document the--d-*bridge as the canonical theming path in-shell; leave standalone fallbacks (drift 6). -
suspendersproduct: add@determined/uito itsextends(drift 12). -
dataVizPalette: either derive from the active theme (accent-anchored, per the dataviz projection below) or delete it until needed; reconcile with pumice’s sibling when pumice adopts (drift 8). - Update
app.config.tscomment/values andexplorations.cssidiom to the post-bridge world (drift 10). - Record the Windows radius/density detachment as intended or fix it (drift 14).
- The layer declares no
ssr. Rendering mode is the app’s decision, so a consumer that states nossrof its own is no longer flipped to SPA by the layer merge. - The layer stops imposing itself on consumers: its stories and tests no longer land in a consumer’s type program, and it no longer pushes its own CSS at one.
-
@determined/uihas anexportsmap: named subpaths for the config,semantics,components/*,composables/*andcss/*. It ends with a"./*": "./*"catch-all, so deep imports still resolve rather than failing — the codebase currently uses none. The map documents the intended surface; it does not yet enforce it. T-XIFP-design-language-ui-subpath-exports.
Phase 2 — Theming descent, formalized
Section titled “Phase 2 — Theming descent, formalized”- Generalize vault-hue → product-hue: a product declares a hue and its
chrome takes the tint, the way a focused vault does. The identity
family is
--d-hueand its siblings; the vault tokens remain as aliases. - Theme-authoring guide: how a solution registers a preset, with the
sdfrecipe written down as the public path. - The theme set:
platinum-ii,instrumentandcarbidebecome built-ins, joining the existing presets — eight themes in the picker. - Rail appearance axis —
flat,washed,chassis— with a rail row in the lab’s Live Controls. - Status grounds:
--d-status-*-washand--d-status-*-edge, so a callout or an error strip has a themed ground and not a fixed pale hex. The absence of these is what stranded an adopting app in light mode. - Platinum refinement pass — the “modern update” against the OmniGraffle
stance. Platinum II is the modern update and is now the default, which
the layer expresses by absence: the
:rootand.darkseeds carry its values. Platinum keeps its own complete seed blocks and becomes an opt-in preset, the classic. Validated against the screenshot corpus, recaptured in place so the diff is the before and after. One seam is unverified: the sunken main pane in dark renders only in the app-frame shell, so it is checked by the cascade test and has never been seen. - The
UButtonsoft/ghost boundary is drawn as an explicit written allowance in the spec, not as a new coveringDButtonintent (drift 13). At a call sitevariant="ghost"and neutralvariant="soft"are violations; a non-neutral status colour combined withsoftorghostis the one allowance. Recorded as debt to withdraw whenDButtongrows an emphasis axis. - One styling idiom per layer, written down (drift 11): the ui layer uses
Tailwind arbitrary-value token utilities, app-frame uses BEM with
scoped CSS reading
var(--d-*). Code moved between layers is restyled to the destination idiom in the same change, so a move is deliberate.
Phase 3 — Adoption, ring by ring (live surfaces only)
Section titled “Phase 3 — Adoption, ring by ring (live surfaces only)”Order: stack-closest first. Each adoption is the same mechanical recipe:
extend @determined/ui → the --ui-* ← --d-* bridge restyles stock U*
components for free → replace raw palette literals with tokens/D*
opportunistically.
-
apps/zoo: upgrade Nuxt UI v3 → v4, extend the layer. -
apps/agentpants: extends the layer; deadtheme.cssdeleted,useThemecollapsed intouseDTheme. Its palette-class debt burns down separately under T-APNC-design-language-agentpants-palette-burndown; runbun scripts/guard-raw-palette.ts --countsfor the current figure. -
apps/pumice: extends the layer. -
solutions/augmented/learn_web+vimit_prototype. -
solutions/augmented/apps/augmented_web: bespokevariables.cssrewritten as a one-way alias bridge onto the layer, then its 964 hex literals burned down to--d-*and the colour-mode preference flipped to'system'(T-AM3S-design-language-augmented-web-hex-burndown). Largest single migration in the ring.
The ring is closed: every live surface extends the layer. augmented_web has now been looked at in both modes, once a toolchain pin made it build again, and the two defects that first look found are fixed. agentpants still carries its palette-class debt.
- pumice palette classes and
dark:variants burned down to 7 survivors (from 1051). Functional colours at enforce(0). The inverted chips moved onto the layer’s new--d-bg-inverted/--d-text-invertedpair, and the pomodoro pips onto--p-phase-*, pumice’s own phase projection. The 7 left are domain amber: the rating-star ladder owned byuiSemantics’ratingAccent, and the streak counter, held raw so a streak is not given--d-status-warning’s meaning. T-APNC-design-language-agentpants-palette-burndown covers agentpants debt; the guard baseline is the count’s source of truth. - Version convergence rides along: Nuxt UI ~4.10, vue-router 5, bun
everywhere (ontological-legacy exempt as frozen donor). Queued:
T-JDUB-design-language-version-convergence. Partly done: Nuxt UI
~4.10 and vue-router 5 shipped. Every app now pins the layer’s
~4.10.0, and zoo and pumice pin bun to1.4.2. augmented_web and learn_web do not yet declare bun in package.json. A repo-level guard holds the Nuxt UI and vue-router lines.
Phase 4 — Projections (the family face beyond Nuxt)
Section titled “Phase 4 — Projections (the family face beyond Nuxt)”- Starlight skin: a
customCssfile projects the default seed tokens (light + dark, not a named theme) ontosites/df-docsand the library doc sites, through thesite-templateseam (D-0010). T-DUEF-design-language-starlight-skin. - Report templates (
etareview reports) render with a palette projected from the default seed tokens. T-J8MT-design-language-report-palette. - Legacy
INDEX_HTMLdashboard: dies with D-0018; no investment. - Marketing/static (
augmented_dot_com): optional, lowest priority — a small tokens CSS if/when touched. - Data-viz projection: a generated categorical/ramp palette per theme
(feeds
dataVizPalette, echarts themes, graph-canvas palettes). Queued: T-B48W-design-language-dataviz-projection. Partly done: the per-theme categorical and ramp tokens ship,useVizPalette()reads them, graph-canvas derives its palette from them, and pumice’s localdataVizPaletteis gone. No echarts theme is generated yet — one pumice chart calls the composable directly, and the polish experience’s three charts still map colours by hand.
Verification and governance (ongoing)
Section titled “Verification and governance (ongoing)”- Every visual change verified in-browser with the existing screenshot
convention (
<area>-<state>-<light|dark>.png); the lab page and Storybook are the living reference. - Every PR that changes pixels carries before/after screenshot pairs
(light + dark) in its description, captured from the affected surface.
Docs-only PRs are exempt.
The repo is private, so
raw.githubusercontent.comURLs neither render nor open in PR bodies — reference committed screenshots asgithub.com/…/blob/<branch>/<path>links, lean on the Files-changed rich image diffs (update committed screenshots in place so the diff IS the before/after), and use web-editor attachment uploads for inline images. - The visual pass is a standing step on any change that moves colour, not
a one-off. A static check cannot see a semantic colour error: the token
resolves, nothing is undefined, the suite is green, and the colour is
still wrong. Three classes of defect have been caught only by looking.
Ink tokens painted as background fills —
--d-text-mutedand--d-text-secondaryhold near-identical values in both modes, so they read opposite ways against opposite grounds, and a secondary button that receded in light became the loudest thing on screen in dark. Decorative tints mapped onto semantic status tokens — cards tinted only to tell two rows apart landed on--d-status-warning-wash, so a folder card claimed to be warning about something and rendered brown on a dark ground. And an accent hardcoded to one value in both themes, beside three routes rendering their list below the fold so the pane painted empty. - A capture driver per ring. zoo, pumice and agentpants carry
capture-appearance.e2e.ts; augmented_web carriescapture-adoption.e2e.ts. pumice works and covers multiple areas with light/dark variants. zoo and augmented_web have stale corpora — environmental colour drift means neither can show a genuine design change. -
scripts/guard-raw-palette.ts— repo tooling, per root CLAUDE.md, not ansolutions/ontologicalgate. It carries all four shapes the task named (hex,keyword,functional-colour,palette-class) plusundeclared-token, and runs on a per-ring ratchet baseline; run it with--countsfor the current ring and file totals. Token composition such asoklch(… var(--d-hue))is not flagged. T-J04U-design-language-no-raw-palette-check. -
bun install --frozen-lockfilesucceeds in zoo, pumice and agentpants. Each is still its own bun workspace root with its own lockfile, so the failure mode can return the next time a manifest moves without its lockfile; the lockfiles are currently in step with their manifests. -
root:checkandroot:testdeclare the inputs they actually read, so the affected-task query covers a change confined tosolutions/ontological. The blind spot was task-level selection only — GitHub’sci.ymlselects by PROJECT, androot’s source is., so CI always covered that tree;just ciand hand-typedmoon run --affecteddid not.solutions/ontologicalstill declares nocheck/testtask of its own, which is why the root tasks have to carry it. - LIBRARIES.md entry for
@determined/uinames it the design-language home (D-DLNG-design-language).