Design System
Dirework's design tokens, the dw-* utility layer, and shared UI primitives.
Dirework ships a small, generated design system so the web app, the docs site, and the OBS overlays all speak the same visual language. The source of truth is a single JSON file; everything else is generated from it.
Source of truth
design-system/
tokens.json # canonical tokens — edit this
scripts/generate.ts # bun script that emits per-platform outputs
README.md # full reference
components/ # markdown catalog (one .md per primitive)Regenerate the outputs from the repo root:
bun run tokensThis writes one committed file:
| Output | Consumed by |
|---|---|
apps/fumadocs/src/app/(home)/_widgets/overlay-themes.generated.ts | Landing-page theme gallery |
CI verifies the outputs are in sync: bun run tokens && git diff --exit-code. Never edit a generated file by hand.
Shared overlay geometry and clock formatting (roundedRectPath, roundedRectPerimeter, formatClock, SQUIRCLE_RADIUS) live in the workspace package @dirework/overlay-kit (packages/overlay-kit), used by both the real OBS overlays and the docs mocks. A unit test in the web app keeps tokens.json in sync with the Theme Center presets and SQUIRCLE_RADIUS.
Focus Console
The visual language is Focus Console — a dark-first instrument panel. Dark mode
is the hero: a MrDemonWolf midnight-navy base (the #091533 family) with cool-white
text. Light mode is fully supported (cool paper with a navy cast).
- Brand primary: Cerulean
#00ACED— the accent, used sparingly (buttons, links, active rings). - Secondary accent: Cornflower
#6B8BF5. - Twitch:
#9146FFis reserved for "Sign in / Connect with Twitch" actions only. - Phase colors: work = emerald
#34C759, break = cerulean, long break = cornflower, paused = amber#FF9F0A. - State: emerald = live / connected, amber = paused / warning (LED-style chips).
Type:
- Display / headings: Montserrat (
--font-display) - Body: IBM Plex Sans (
--font-body) - Labels & numerals: IBM Plex Mono (
--font-mono) — timer digits usetabular-nums
Tokens
Structural tokens (spacing, radius, motion, shadow, and the type scale) come from the
generated --ds-* layer. The Focus Console color and font choices live in
apps/fumadocs/src/app/global.css, mirroring the web app's apps/web/src/index.css, and
are exposed through a thin semantic layer the docs surfaces read from.
| Namespace | Variable pattern | Example |
|---|---|---|
| Brand | --brand-500 / --brand-600 / --brand-50 | --brand-500: #00ACED (cerulean) |
| Phase | --phase-{work,break,long-break,paused} | timer ring + status accents |
| Partner | --color-twitch, --color-live | Twitch actions / live state |
| Surface | --bg-base / --bg-surface / --bg-elev | light/dark aware |
| Text | --txt-1 / --txt-2, --hairline | light/dark aware |
| Fonts | --font-display / --font-body / --font-mono | Montserrat / Plex Sans / Plex Mono |
| Space | --ds-space-{0…11} | 4px-based scale (generated) |
| Radius | --ds-radius-{xs…2xl,pill} | --ds-radius-pill: 9999px (generated) |
| Motion | --ds-motion-duration-*, --ds-motion-easing-* | fast: 150ms (generated) |
Dark-mode values are swapped under .dark automatically.
The dw-* utility layer
The marketing and docs surfaces use a thin set of utility classes (defined in
apps/fumadocs/src/app/global.css) that read the tokens. They keep the landing page
token-backed without pulling in a component framework.
| Class | Purpose |
|---|---|
dw-display / dw-mono | Montserrat heading + Plex Mono label styles |
dw-text-1 / dw-text-2 / dw-text-brand | Text hierarchy |
dw-bg-base / dw-bg-surface / dw-bg-elev | Surfaces |
panel / panel-hero / panel-inset | Flat instrument panels (workhorse / gradient hero / recessed well) |
console-label / console-rule | Mono section label + labeled hairline rule |
dw-chip + dw-chip-{accent,live,warn} | LED-style status chips |
dw-kicker + dw-kicker-num | Numbered section kicker (01 · …) |
dw-card / dw-card-hover | Content container |
dw-btn + dw-btn-{primary,secondary,twitch,ghost} | Buttons |
dw-pill | Metadata / trust chip |
dw-code | Code well |
bg-grain / bg-checker | Module grain / OBS transparency preview |
dw-reveal-{1,2,3} / animate-led-pulse | Staggered entrance + LED pulse |
Component catalog
Shared primitives are documented one-per-file under design-system/components/:
- Button, Card, Glass Card, Pill — console chrome
- Timer Ring — the overlay progress ring (circle + squircle), mirroring
apps/web/src/lib/timer-utils.ts - Task Card — the grouped task overlay, mirroring
task-list-display.tsx - Chat Bubble — the Twitch command preview
- Theme Swatch — the overlay theme gallery, driven by the generated
OVERLAY_THEMES
Overlay themes
overlay.themes in tokens.json mirrors the 6 presets in apps/web/src/lib/theme-presets.ts, holding the four swatch colors each exposes (bg, accent, text, username). That data is generated into a typed module the landing-page gallery renders. When a preset's preview colors change, update tokens.json and run bun run tokens.
Accessibility rules
- Two themes, always. Every surface must read in light and dark.
- Never color alone. Done tasks use strike-through and a dimmed color.
- Honor reduced motion. Animated primitives stop under
prefers-reduced-motion: reduce. - Real interactive elements. Buttons and links are
<button>/<a>, never clickable<div>s.