Files
Lyra/docs/superpowers/specs/2026-07-12-frontend-design-system.md
T
Jonathan 4655d815ee docs: Pressing Plant frontend design system spec (Phase 1)
Design language + Phase 1 plan (design system + app shell + home page).
Comp signed off. Liner Notes / record-label identity, chrome-only
metaphor, manila+spruce palette, Fraunces/mono, state-as-form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 13:53:52 +02:00

7.5 KiB
Raw Blame History

Lyra frontend: the "Pressing Plant" design system

Date: 2026-07-12 Status: approved (design comp signed off), implementing Comp: https://claude.ai/code/artifact/af6f9654-619d-4245-b3dd-602a6427934a

Intent

Give Lyra a real visual identity instead of unstyled raw HTML. Direction: Liner Notes / "Pressing Plant" — the app presented as a record label's internal catalog for an audience of one. The acquisition pipeline reads as a pressing plant. The metaphor lives in the chrome only (masthead, section names, catalog/matrix numbers, deadwax etch styling); functional labels stay literal and legible (Downloading, Verifying, Needs attention) so nothing is obscured. Single-user homelab tool → license to be bold.

This is a tool, not a document: information design first (summary before detail, state encoded as form — severity stripe + chip — not just prose), editorial typography second.

Design language (the reusable reference)

Color — deliberately off the AI-editorial cliché (no cream, no vermilion)

Two-color-print feel: manila/kraft paper + warm ink + one bold deep spruce accent. Tokens are CSS custom properties on :root; both themes get equal care. Semantic status colors are separate from the accent.

Token Day (light) Night (dark) Use
--paper #E7DFCC #14130F ground
--paper-2 #DED5BE #1D1B16 recessed panel
--ink #1B1A17 #E9E1CD primary text
--graphite #726D5F #938C7B secondary text / mono meta
--rule rgba(ink,.16) rgba(ink,.16) hairlines
--rule-2 rgba(ink,.30) rgba(ink,.28) stronger rules
--accent #1F5138 #5BB487 the one bold move; links, active nav, "pressed"
--accent-ink #F3EEDF #10120F text on accent
--live (semantic) #9A6B1E amber #D2A24E work in progress
--alert (semantic) #99392B clay #D8695A needs attention (errors only)

Theme mechanics: define tokens on :root; redefine under @media (prefers-color-scheme: dark); also redefine under :root[data-theme="light"] and :root[data-theme="dark"] so an explicit in-app toggle wins in both directions. Style components through tokens only, never inside the media query. Faint paper grain via a tiled radial-gradient. Sharp corners (radius 02px) — letterpress/label feel, and it dodges the rounded-lg cliché.

Type — serif/mono tension is the concept

  • Display + editorial: Fraunces (OFL variable serif; soft, optical, warm), self-hosted via next/font/local (woff2 vendored under web/src/fonts/, subset to latin). The comp used a Palatino system stack as a stand-in; the real app ships Fraunces.
  • Machine voice (all metadata, labels, data, progress): a system mono stack (ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace) — zero weight, reliable. Uppercase mono labels get letter-spacing: 0.120.22em.
  • Scale (rem): masthead clamp(2.6, 6vw, 3.7), job title 1.42, tile value 2.5, body 1.0, section head 0.78 mono, meta/labels 0.620.72 mono. text-wrap: balance on headings; running text ~65ch; font-variant-numeric: tabular-nums on all aligned digits.

Motifs

Masthead wordmark + tagline + live worker dot + "Pressing № NNNN" catalog mark; contents-bar nav (hairline top/bottom, active item underlined in accent); summary tiles (hairline grid); dept section headers (mono small-caps + rule fill + count); tracklist job rows with a left severity stripe; mono status chip; thin ruled progress bar (indeterminate variant for search); deadwax matrix etch line for pressed items (Lyra·A0430 — FLAC 24/48); colophon footer.

Motion (restrained)

Live-dot pulse; indeterminate progress slide; hover underlines. All gated by @media (prefers-reduced-motion: reduce). No scattered effects.

Architecture

Hand-rolled CSS, no framework (matches the lightweight Next 15 / React 19 stack).

  • web/src/app/globals.css (new) — token definitions (both themes), base/reset, paper grain, focus-visible, reduced-motion. Imported once in the root layout.
  • web/src/app/design.css (new, or co-located module) — the component classes (masthead, contents nav, tiles, dept header, job row, chip, bar, pressed list, buttons, inputs). Plain global classes keep it simple and shared across pages.
  • Fonts: web/src/fonts/ vendored Fraunces woff2 + next/font/local wiring, exposed as a CSS variable on <body>.
  • App shell: web/src/app/layout.tsx gains the shared chrome — a <Masthead/> + <ContentsNav/> server components wrapping {children} in the editorial column, plus a small client theme toggle that stamps data-theme on <html> and persists to localStorage. Individual page files stop repeating the ad-hoc nav line.
  • Components live under web/src/app/_ui/ (e.g. masthead.tsx, contents-nav.tsx, theme-toggle.tsx, stat-tiles.tsx, job-row.tsx, status-chip.tsx, progress-bar.tsx, section-header.tsx). Each: one clear job, styled via the shared classes, driven by props.

Rollout (this spec covers Phase 1; later phases are their own plans)

Phase 1 — system + shell + flagship (this plan):

  1. Fonts + globals.css tokens (both themes) + base reset, wired into the root layout.
  2. Component library (_ui/) + design.css classes: masthead, contents-nav, theme-toggle, stat-tiles, section-header, job-row, status-chip, progress-bar, pressed-list.
  3. App shell in layout.tsx (masthead + nav + column + toggle).
  4. Rebuild the home / "The Floor" page (app/page.tsx + queue.tsx) on the real queue data: summary tiles, on-the-press job list (state → stripe+chip+bar, real pipeline stages mapped to literal labels: resolving/searching/downloading/verifying/tagging; needs-attention shows recovery actions), recently-pressed list, empty state.

Phase 2 (later): restyle Artists, Artist detail, Discover, Discover/artist preview, Wanted onto the same system.

Phase 3 (later): Settings redesign — the paths + auth pain point. Editorial form treatment for credentials (Qobuz, slskd) with clear "set/unset" affordances; a Library section surfacing the configured music path. NOTE/constraint: MUSIC_DIR is a container mount, not runtime-editable from the UI (changing a string can't remount a Docker volume), so paths are shown with explanation (and any genuinely runtime-config paths made editable); credentials and discover.*/monitor.*/scan.chunkSize become first-class, well-labelled controls. Scoped in its own spec when we reach it.

Testing & verification

  • The existing web suite (vitest, 71 tests) tests routes/logic, not visuals; a restyle must keep it green. Preserve accessible names / test hooks — existing aria-labels, button text ("Save", "Search"), and aria-label="scan result" etc. Update a test only where copy/behavior intentionally changes, and in the same commit.
  • New interactive component (theme toggle) gets a small test (persists + toggles data-theme).
  • Visual verification: drive the real app (playwright) and eyeball the home page in both themes + a mobile width before calling Phase 1 done — screenshots, not just "it compiles".
  • Accessibility: visible :focus-visible, prefers-reduced-motion honored, contrast legible on both grounds, keyboard-navigable nav + toggle.

Out of scope (Phase 1)

Phases 23 pages; any backend/data changes (home reads existing queue/config data as-is); new fonts beyond Fraunces + system mono; charts.