Add design/ contract extracted from the as-built UI
Inventory the as-built recaps.cc look and distill it into a durable, vendor-neutral design contract: design/DESIGN.md (nine-section brand brief) + design/tokens.tokens.json (W3C DTCG tokens), plus brand icon and provenance notes. Canonical calls reconciled with the owner: indigo #818cf8 as the single interactive accent, purple #a855f7 for premium only, the #0a0e1a->#111827->#0f172a surface ladder, and a normalized type scale. Wire the AGENTS.md Design line and record the contract-vs-code drift as a cleanup backlog in ROADMAP.md.
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# Recap — Design brief
|
||||
|
||||
The durable brand contract for Recap's user-facing UI. Read this and
|
||||
`design/tokens.tokens.json` before building or changing any UI. This was
|
||||
**extracted** from the as-built `recaps.cc` interface (no prior guidelines), then
|
||||
**reconciled** with the owner on 2026-06-16 — so where the live code still
|
||||
disagrees with a value here, *this file is the intent* and the code is the cleanup
|
||||
backlog (see `ROADMAP.md`). Provenance: there was no design tool or export; the
|
||||
source is the shipped `public/index.html`, `public/auth.html`, and the app icon.
|
||||
|
||||
---
|
||||
|
||||
## 1. Visual theme
|
||||
|
||||
A **dense, dark, information-first developer-tool aesthetic.** Restraint over
|
||||
decoration: small type, tight radii, thin hairline borders, flat panels on a
|
||||
near-black navy field, with the indigo accent used sparingly to mark what's
|
||||
interactive or active. It should read like a fast, technical instrument — closer
|
||||
to a code editor or an ops dashboard than a consumer media app. Calm, quiet, and
|
||||
legible at high density; never glossy, never playful.
|
||||
|
||||
The brand mark (app icon) is a **play-triangle filled with a blue→purple gradient
|
||||
over four light "transcript" lines**, on the dark navy field — the product in one
|
||||
glyph: *press play on a video, get the text back.* That blue→purple gradient is
|
||||
the origin of the whole accent story (§2).
|
||||
|
||||
Voice: precise, plain-spoken, unhyped. The UI explains tersely and trusts the
|
||||
user. What it is **not**: not gradient-heavy, not glassmorphic beyond a light
|
||||
overlay blur, not rounded-and-bubbly, not light-mode, not framework-flashy.
|
||||
|
||||
## 2. Color palette
|
||||
|
||||
Built almost entirely on the **Tailwind Slate + Indigo** ramps over a custom
|
||||
near-black navy base. Canonical roles below; full values in
|
||||
`tokens.tokens.json`.
|
||||
|
||||
**Surface ladder (warm/cool split — the agreed system).**
|
||||
| Role | Value | Where |
|
||||
|---|---|---|
|
||||
| Base | `#0a0e1a` | page, body, sticky top bars, full-height side panels (history sidebar, log drawer). Also the PWA `theme_color`. |
|
||||
| Card | `#111827` (warm gray-900) | raised cards, modals, popovers, toasts, icon-buttons, pipeline steps, skeletons. |
|
||||
| Inset | `#0f172a` (cool slate-900) | recessed fields & list rows: settings/key inputs, queue items, subscription items, model buttons, expanded-chunk bg. |
|
||||
| Raised field | `#1e293b` | the **primary URL input only** — deliberately lighter than the inset so the hero field pops. |
|
||||
|
||||
> Legacy darks **`#0a0e17`, `#0b1120`, `#020617`** are near-duplicates that
|
||||
> leaked in; fold them into the nearest rung (`#0a0e17`/`#0b1120` → Base,
|
||||
> `#020617` → Inset). Don't add new background darks.
|
||||
|
||||
**Accent — indigo (THE single interactive accent).**
|
||||
- `#818cf8` (indigo-400) — **the accent.** Fills (submit button, active tab/icon,
|
||||
processing badge) and marks (links, focus ring, active state, timestamps,
|
||||
expanded-chunk arrow).
|
||||
- `#a5b4fc` (indigo-300) — accent hover (lighter), active-line emphasis.
|
||||
- Indigo tints `rgba(129,140,248, .06–.20)` — hover washes, active backgrounds,
|
||||
the `0 0 0 3px …/.15` focus ring, the `0 4px 24px …/.3` submit glow.
|
||||
- **Demoted:** `#6366f1` (indigo-500) and its hovers `#4f46e5`/`#4338ca` are
|
||||
legacy dups — migrate them to `#818cf8`; do not introduce new ones.
|
||||
|
||||
**Premium — purple (RESERVED for paid/upgrade only).**
|
||||
- `#a855f7` (purple-500) — upgrade button, highlighted tier, buy badge, primary
|
||||
buy CTA. `#c084fc` hover; `#9333ea` deep.
|
||||
- `#c4b5fd`/`#d8b4fe` (purple-300/200) — tier-badge & Pro text.
|
||||
- Purple appears **nowhere** in non-premium UI.
|
||||
|
||||
**Text ramp (slate).**
|
||||
`#e2e8f0` primary · `#f1f5f9` strong/headings (canonical near-white — fold the
|
||||
stray `#f5f9ff` into this) · `#cbd5e1` running body copy · `#94a3b8` muted/
|
||||
secondary · `#64748b` labels & placeholders · `#475569` faint meta/timestamps ·
|
||||
`#334155` dimmest (doubles as the hover-border). `#fff` only on filled
|
||||
accent/premium buttons.
|
||||
|
||||
**Borders.** `#1e293b` (slate-800) default hairline → `#334155` (slate-700) on
|
||||
hover/active → `#475569` (slate-600) strongest hover. Borders, not shadows, are
|
||||
the primary way surfaces are separated.
|
||||
|
||||
**Semantic status (consistent, intentional — keep).**
|
||||
- Success/green: `#22c55e` base · `#4ade80` text · `#86efac` soft · `#16a34a` deep.
|
||||
- Error/red: `#ef4444` base · `#f87171` text · `#fca5a5` soft · `#dc2626` deep.
|
||||
- Warning/amber: `#fbbf24` base/dot · `#fcd34d` · `#fde68a` · `#f59e0b` (update btn).
|
||||
- Info/blue: `#3b82f6` base · `#60a5fa` · `#93c5fd`. **Blue is status/info only**
|
||||
(and the legacy auth-screen accent, which should migrate to indigo) — never a
|
||||
primary interactive color in-app.
|
||||
|
||||
**Speaker chips (8-hue categorical set — intentional, keep as-is).** A→H:
|
||||
red/blue/green/amber/purple/sky/pink/slate, each as the *tinted triplet*
|
||||
(background α≈.18, light-shade text, border α≈.35).
|
||||
|
||||
## 3. Typography
|
||||
|
||||
- **Sans (everything):** `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
sans-serif`. System stack — **no web fonts.**
|
||||
- **Mono (timestamps, license keys, URLs, code):** `ui-monospace, "SF Mono",
|
||||
Menlo, Consolas, monospace`. One canonical stack — snap the near-variants to it.
|
||||
- **Scale (px):** `10 · 11 · 12 · 13 · 14 · 16 · 18 · 20 · 22 · 28`.
|
||||
- 10–11 — micro labels, badges, meta, section labels, pills, hints.
|
||||
- 12 — secondary UI default (buttons, labels, stats, list titles).
|
||||
- 13 — body default (descriptions, list items, transcript-adjacent).
|
||||
- 14 — emphasis / larger body, drawer & settings headers.
|
||||
- 16 — input text, modal `h2`, section heads.
|
||||
- 18 — sub-headers, logo wordmark, large numerals.
|
||||
- 20–22 — headings, modal/activation titles, tier names.
|
||||
- 28 — display (price). Snap strays `15→16`, `24→22`, fractionals
|
||||
`12.5/11.5→12`, `10.5/9→10`.
|
||||
- **Weights:** 400 normal · 500 medium · **600 semibold (the UI default)** · 700
|
||||
bold (headings, badges) · 800 extrabold (tier badge, big numerals). Snap
|
||||
`650→600`, `680→700`.
|
||||
- **Line-height:** 1.5 body · 1.55 denser reading blocks · 1.3–1.4 titles · 1.25
|
||||
large titles · 1 single-line badges.
|
||||
- **Letter-spacing:** 0 default. Uppercase micro-labels track `0.05em`; badges
|
||||
`0.04em`; tier/section labels `0.06–0.08em`; one display title tightens
|
||||
`-0.01em`.
|
||||
|
||||
## 4. Component styling
|
||||
|
||||
- **Buttons.** *Primary:* filled `#818cf8`, white text, radius 8–10px, weight
|
||||
600, hover lifts `translateY(-1px)` + indigo glow; disabled → `#1e293b` bg /
|
||||
`#475569` text. *Secondary:* `#1e293b` fill, `#334155` border, `#94a3b8`→
|
||||
`#cbd5e1` text. *Icon/ghost:* `#111827` (or transparent), `#1e293b` border,
|
||||
muted glyph; hover lightens bg + border; `.active` → accent fill. *Premium:*
|
||||
filled `#a855f7`.
|
||||
- **Inputs.** Inset `#0f172a` (or `#1e293b` for the hero URL input), `#334155`/
|
||||
`#1e293b` border; focus → accent border + `0 0 0 3px rgba(129,140,248,.15)`
|
||||
ring. Mono font for keys/codes; placeholders `#64748b`/`#475569`.
|
||||
- **Cards.** `#111827` bg, `#1e293b` border, radius 10–14px; border lightens on
|
||||
hover; expanded/active → accent border + faint `0 2px 16px …/.06` accent glow.
|
||||
- **Pills / badges / chips — the "tinted triplet".** Background at α≈.1,
|
||||
text in the light shade, border at α≈.2–.45 of the same hue. Status pills,
|
||||
tier badges, `queue-from` tags, clip badges, and speaker chips all follow this
|
||||
one rule.
|
||||
- **Modals.** `#111827` (settings) / `#0f172a` (buy) bg, radius 16px, sticky
|
||||
header with `1px #1e293b` bottom border, `slideUp` entrance, scrim
|
||||
`rgba(0,0,0,.6)` + `backdrop-filter: blur(4px)`.
|
||||
- **Toasts.** Top-right stack, `#1e293b` bg, `#334155` border, slide-in from
|
||||
right, auto-fade.
|
||||
- **Spinner.** 3px ring, `#1e293b` track, `#818cf8` top, `spin 0.8s linear`.
|
||||
- **Pipeline / tracker.** Stepped pills: idle neutral, `.active` → accent
|
||||
tint+border, `.done` → green tint+border.
|
||||
|
||||
## 5. Layout
|
||||
|
||||
- **Single fluid column.** `.container` `max-width:100%`, padding `36px 24px`
|
||||
(landing) tightening to `16px 24px` (results) and down on mobile.
|
||||
- **Results = split screen.** `.results-left` 58% (video/player, sticky top) +
|
||||
`.results-right` (scrolling chunk list), 16px gap; stacks vertically <900px.
|
||||
- **Persistent left history sidebar**, 320px, *pushes* content on desktop /
|
||||
overlays on mobile. **Right log drawer**, 440px, slides in.
|
||||
- **Dense vertical rhythm.** Card margin 14px, chunk margin 6px, gaps 6–16px.
|
||||
- **Spacing steps (de-facto):** `4 · 6 · 8 · 10 · 12 · 14 · 16 · 20 · 24` for
|
||||
controls/gaps, `28 · 32 · 36` for section padding. Not a strict 4/8 grid —
|
||||
dense and organic by design; prefer these steps over new in-between values.
|
||||
|
||||
## 6. Depth / elevation
|
||||
|
||||
**Flat by default — separation comes from 1px borders, not shadows.** Shadows are
|
||||
reserved for things that genuinely float:
|
||||
- Overlays/drawers/modals: `0 8px 24px …/.3` (toast) · `0 8px 32px …/.4` (video,
|
||||
side drawers `±8px 0 32px`) · `0 12px 32px …/.5` (menu) · `0 20px 60px …/.5`
|
||||
and `0 24px 64px …/.5–.6` (panel, settings/buy modal). All `rgba(0,0,0,α)`.
|
||||
- **Accent glows** signal primary/active: submit `0 4px 24px rgba(129,140,248,.3)`;
|
||||
focus ring `0 0 0 3px rgba(129,140,248,.15)`; expanded chunk `0 2px 16px …/.06`;
|
||||
premium tier `0 12px 40px rgba(168,85,247,.25)`.
|
||||
- Overlay scrims use `rgba(0,0,0,.4–.65)` + `backdrop-filter: blur(4–6px)`.
|
||||
- Drag/drop affordance is an accent line: `box-shadow: 0 ±2px 0 0 #818cf8`.
|
||||
|
||||
## 7. Do's and don'ts
|
||||
|
||||
**Do**
|
||||
- Use `#818cf8` as the *single* interactive accent; reserve purple `#a855f7`
|
||||
strictly for premium/upgrade.
|
||||
- Separate surfaces with 1px `#1e293b` borders that lighten to `#334155` on hover;
|
||||
keep shadows for true overlays only.
|
||||
- Build every status/category chip as the tinted triplet (bg α.1 / light text /
|
||||
border α.2).
|
||||
- Keep type dense — 12–13px body, 10–11px meta — with 600 as the default weight.
|
||||
- Follow the surface ladder: base `#0a0e1a` → card `#111827` → inset `#0f172a`.
|
||||
- Use the system font stack; mono only for timestamps / keys / URLs.
|
||||
|
||||
**Don't**
|
||||
- Don't introduce new `#6366f1`/`#4f46e5` indigos — they migrate to `#818cf8`.
|
||||
- Don't put blue `#3b82f6` on primary interactive elements; blue is info/status
|
||||
(and legacy auth) only — auth should move to indigo.
|
||||
- Don't add new background darks (`#0a0e17`/`#0b1120`/`#020617` are legacy dups).
|
||||
- Don't use purple for non-premium UI, or the accent indigo for premium.
|
||||
- Don't add fractional font sizes (12.5/11.5/10.5) or off-scale weights (650/680).
|
||||
- Don't reach for a framework, web font, or heavy drop shadows — vanilla JS,
|
||||
system fonts, flat-with-borders is the intentional language.
|
||||
|
||||
## 8. Responsive behavior
|
||||
|
||||
- **Breakpoints:** `900px` (primary: split→stack, sidebar push→overlay), `880px`
|
||||
(tablet: top breadcrumb swaps to a hoisted mobile copy), `600px` (phone:
|
||||
icon-only submit, hamburger menu, desktop toolbar/pills hidden), `640px` (share
|
||||
export). Plus `≤900px landscape` → fullscreen video.
|
||||
- **Mobile rules:** form inputs forced to `16px` (iOS auto-zoom guard); touch
|
||||
targets 44–48px; sticky top bar; full-width drawers/panels; hover-gated
|
||||
controls pinned visible (touch has no hover). Use `100dvh` for full-height.
|
||||
|
||||
## 9. Agent prompt guide
|
||||
|
||||
When building or changing UI in this repo:
|
||||
- Read `design/tokens.tokens.json` and pull values from it — don't eyeball new hex.
|
||||
- Match the **dense dark vanilla-JS** style. The frontend is one file,
|
||||
`public/index.html`, with two `<style>` blocks + ~447 inline `style=` attrs and
|
||||
a render-into-`innerHTML` loop. No framework, no bundler, no web fonts — keep it
|
||||
that way.
|
||||
- Accent is `#818cf8`; purple is premium-only; follow the surface ladder; build
|
||||
chips as the tinted triplet; system font for text, mono for timestamps/keys.
|
||||
- **Three surfaces stay in sync:** the main app stylesheet, the `SHARE_PAGE_CSS`
|
||||
string (the self-contained share export), and `public/auth.html`. A token change
|
||||
must be reflected in all three. Auth currently uses the legacy blue accent —
|
||||
new auth work should adopt indigo.
|
||||
- Sanitize operator-internal strings at error boundaries (per `AGENTS.md`) — they
|
||||
must never reach cloud users, design surfaces included.
|
||||
Reference in New Issue
Block a user