Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions docs/superpowers/specs/2026-06-15-terminal-native-redesign-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Terminal-native redesign — design spec

**Date:** 2026-06-15
**Status:** Approved (vibe confirmed via `design-demo/` prototype)
**Scope:** Whole-site visual redesign (home, explore, config cards, docs, header, footer, shared shell)

## 1. Direction

Refined, terminal-native identity executed with **restraint** — the register is "high-end,
textured, not flashy, no AI-smell," in the spirit of Vercel / pi.dev. Fully monospace, dark-first
with a deliberate light mode. The terminal is the brand's visual *language* (prompts, carets, mono,
command-style labels), not literal cosplay — sections are clean web layouts with **one** real
terminal window as the signature moment.

**Anti-goals (the "AI-smell" to avoid):** purple/blue gradients, gradient blobs, heavy neon glows,
over-rounded everything, evenly-distributed timid color, flat digital surfaces, emoji UI.

**Reference prototype:** `design-demo/index.html` (throwaway). The production build reproduces this
look using the project's CSS-variable system and Svelte components. The demo is the source of truth
for the visual target.

## 2. Design tokens

Re-map values onto the **existing** token names in `src/lib/styles/variables.css` (so components
don't all need editing), and add the new tokens listed. Pure white text is intentionally retired in
favor of a soft off-white for a premium feel.

### Dark (default)
```
--bg-primary: #0a0a0b (was #0a0a0a)
--bg-secondary: #100f12 surface (cards, terminal, command box)
--bg-tertiary: #161519 surface-2 (code blocks, raised)
--bg-hover: #1b1a1f
--text-primary: #ededf0 soft white, not #ffffff
--text-secondary:#9a99a2
--text-muted: #5b5a63
--accent: #4ec98a refined mint (was neon #22c55e)
--accent-hover: #6ad9a0
--accent-glow: rgba(78,201,138,0.10) (lower than before)
--border: #1f1e22
--border-hover: #2c2b30
--code-bg: #161519
--header-bg: rgba(10,10,11,0.78)
--danger: #d4655c refined red
--danger-hover: #c0473d
/* new */
--accent-deep: #2f6b4d muted prompt / subtle ring
--amber: #c9a14e secondary terminal color (warnings/steps)
--shadow: rgba(0,0,0,0.5)
--vignette: color-mix(in srgb, var(--bg-primary) 55%, #000)
--grain-blend: soft-light
--grain-opacity:0.05
```

### Light ("paper terminal")
```
--bg-primary: #fafaf8 warm off-white (was stark #ffffff)
--bg-secondary: #ffffff
--bg-tertiary: #f3f3f0
--bg-hover: #ecece7
--text-primary: #18181b
--text-secondary:#5b5b60
--text-muted: #909095
--accent: #1c7d52 deep green, AA on light
--accent-hover: #176343
--accent-glow: rgba(28,125,82,0.08)
--border: #e7e7e2
--border-hover: #d6d6cf
--code-bg: #f3f3f0
--header-bg: rgba(250,250,248,0.78)
--danger: #c0473d
--danger-hover: #a83a31
/* new */
--accent-deep: #cde7d9
--amber: #946a1a
--shadow: rgba(20,20,30,0.10)
--vignette: transparent
--grain-blend: multiply
--grain-opacity:0.035
```

## 3. Typography — fully monospace

- **Family:** Geist Mono (primary) → JetBrains Mono (fallback, already loaded) → system mono.
Add a `--font-mono` token; set it as the global body font.
- **Loading:** In `src/app.html`, replace the `Outfit` Google Fonts request with `Geist Mono`
(weights 400/500/600). Keep `JetBrains Mono`. Outfit is removed entirely.
- **Hierarchy comes from size / weight / color / case** (one family, no font-switching):

| Role | Size | Weight | Tracking | Notes |
|------|------|--------|----------|-------|
| Display (h1) | clamp(2.3rem, 4.6vw, 3.7rem) | 500 | -0.04em | line-height 1.04 |
| h2 | 1.7rem | 500 | -0.025em | |
| h3 | ~1rem | 500 | -0.01em | |
| Body | 0.94rem | 400 | — | line-height 1.7, max-width ≤ 54–62ch |
| Label / eyebrow | 0.72–0.8rem | 400/500 | 0.02–0.1em | often lowercase or `#`/`>`-prefixed, uppercase for footer col heads |

**Fully-mono readability guardrails (hard rules):** body line-height ≥ 1.7; text measure ≤ 62ch;
body size ≥ 15px (0.94rem). These keep mono prose comfortable.

## 4. Texture, depth & motion

- **Film grain:** fixed full-viewport SVG fractal-noise overlay (`body::after`), `mix-blend-mode`
and opacity per `--grain-blend` / `--grain-opacity`. This is the primary "texture." Add to the
layout shell.
- **Vignette:** subtle radial darkening at page edges in dark mode only (`--vignette`); transparent
in light.
- **Grid:** faint graph-paper grid behind the hero only, radial-masked, ~0.4 opacity. Not site-wide.
- **Depth:** hairline 1px borders + soft low shadows (`--shadow`). No large lifts, no neon.
- **Motion:** 150–250ms ease-out. Hover = border brightens + faint `--accent-glow` ring + ≤1px
nudge. One on-scroll reveal (fade + 8px rise, once). Hero terminal auto-types. **All motion
(typing, reveals, caret) disabled under `prefers-reduced-motion`** — terminal renders final state.

## 5. Component / file changes

Project uses **pure CSS + scoped `<style>` + CSS variables**, no Tailwind. Footer currently lives in
`src/routes/+page.svelte`.

| File | Change |
|------|--------|
| `src/lib/styles/variables.css` | New token values + added tokens (§2). |
| `src/app.html` | Swap Outfit→Geist Mono in the fonts link. |
| `src/routes/+layout.svelte` | Global body font → `--font-mono`; add grain + vignette overlays; base type rhythm; `prefers-reduced-motion` reset. |
| `src/lib/components/SiteHeader.svelte` | Terminal status-bar style: `$ openboot` (green prompt), lowercase mono nav, `★ 256`, refined ☾/☀ toggle, hairline border + blur. |
| `src/routes/+page.svelte` | Hero (mono display headline w/ green on key phrase, `#`-eyebrow, ✓ list, hairline click-to-copy command box w/ caret, signature auto-typing terminal, masked grid bg); How It Works (prompt header `> how it works`, hairline-divided 4-cell grid, quiet `01–04`, hover fill); Footer (`openboot $ _` prompt + caret, mono link columns, legal line). Tighten section rhythm. |
| `src/routes/explore/+page.svelte` | `> explore` prompt header; mono sort control; raise muted-text contrast; spacing rhythm. |
| `src/lib/components/ConfigCard.svelte` | Mono throughout; keep colored top accent but unify into the terminal language; green stats; badges as `[featured]`/`[official]`; bottom install line w/ copy; hover = border + faint glow. |
| Docs styles (mdsvex/docs layout) | Mono prose w/ readability guardrails; code blocks on `--bg-tertiary` w/ left green border; sidebar active item w/ `>` marker. |

## 6. Accessibility

- All text/background pairs meet **WCAG AA** (the new `--text-muted` and light-mode `--accent` are
chosen for this; verify with a contrast check during build).
- Full `prefers-reduced-motion` support (§4).
- Keep keyboard focus styles; command/terminal copy actions remain reachable.

## 7. Quality (non-visual, in-scope)

- Investigate & fix the **2–3 console errors** seen on the live site during this pass.

## 8. Out of scope / non-goals

- No new pages, features, or copy rewrites beyond micro-labels (prompts, eyebrows). Marketing
copywriting is a separate effort.
- No backend / API / DB changes.
- No framework or build-system changes (still SvelteKit + scoped CSS, no Tailwind).
- `design-demo/` is a throwaway and is removed (or git-ignored) before merge.
- Self-hosting Geist Mono (vs Google Fonts) is a possible later perf optimization, not this pass.

## 9. Success criteria

- Home, explore, docs, header, footer, config cards all render in the new terminal-native system,
dark + light, both deliberate.
- `npm run validate` (check + lint + test) passes.
- Visual parity with the approved `design-demo/` look on the home page.
- No remaining console errors on the main pages.
- Target subjective quality: ~9/10 per the original critique's gap list, all six gaps closed.
2 changes: 1 addition & 1 deletion src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚀</text></svg>" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="OpenBoot" />
%sveltekit.head%
Expand Down
2 changes: 1 addition & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const SECURITY_HEADERS: Record<string, string> = {
'Content-Security-Policy': [
"default-src 'self'",
"script-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"img-src 'self' https: data:",
"font-src 'self' https://fonts.gstatic.com",
"connect-src 'self' https://api.github.com https://accounts.google.com https://oauth2.googleapis.com https://formulae.brew.sh https://registry.npmjs.org",
Expand Down
16 changes: 8 additions & 8 deletions src/lib/components/ConfigCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,8 @@
}

.card:hover {
border-color: var(--card-border-hover);
transform: translateY(-4px);
box-shadow: 0 20px 50px -12px rgba(var(--card-accent), 0.15);
border-color: var(--border-hover);
box-shadow: 0 0 0 1px var(--accent-glow), 0 14px 40px -22px var(--shadow);
}

.card:focus-visible {
Expand Down Expand Up @@ -235,11 +234,12 @@
}

.card-name {
font-size: 1.2rem;
font-weight: 700;
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
line-height: 1.3;
letter-spacing: -0.01em;
}

.card-slug {
Expand All @@ -264,7 +264,7 @@
.vis-tag {
padding: 3px 8px;
font-size: 0.6rem;
font-weight: 700;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
border-radius: 5px;
Expand Down Expand Up @@ -301,8 +301,8 @@
}

.stat-val {
font-size: 1.5rem;
font-weight: 800;
font-size: 1.4rem;
font-weight: 600;
line-height: 1;
color: var(--text-primary);
font-variant-numeric: tabular-nums;
Expand Down
31 changes: 19 additions & 12 deletions src/lib/components/SiteHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<header class="site-header">
<div class="header-container">
<div class="header-left">
<a href="/" class="header-logo">OpenBoot</a>
<a href="/" class="header-logo"><span class="prompt">$</span> openboot</a>
<nav class="header-nav">
<a href="/explore" class:active={currentPath === '/explore' || currentPath.startsWith('/explore')}>Explore</a>
<a href="/docs" class:active={currentPath === '/docs' || currentPath.startsWith('/docs')}>Docs</a>
Expand Down Expand Up @@ -52,9 +52,10 @@
}

.header-container {
max-width: 1200px;
max-width: 1160px;
margin: 0 auto;
padding: 14px 24px;
height: 56px;
padding: 0 36px;
display: flex;
justify-content: space-between;
align-items: center;
Expand All @@ -63,33 +64,39 @@
.header-left {
display: flex;
align-items: center;
gap: 20px;
gap: 26px;
}

.header-logo {
font-family: 'JetBrains Mono', monospace;
font-size: 1.05rem;
font-weight: 700;
color: var(--accent);
letter-spacing: -0.02em;
font-family: var(--font-mono);
font-size: 0.95rem;
font-weight: 500;
color: var(--text-primary);
letter-spacing: -0.01em;
text-decoration: none;
transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.header-logo .prompt {
color: var(--accent);
margin-right: 2px;
}

.header-logo:hover {
opacity: 0.8;
}

.header-nav {
display: flex;
align-items: center;
gap: 20px;
gap: 22px;
}

.header-nav a {
color: var(--text-secondary);
font-size: 0.9rem;
font-weight: 500;
font-size: 0.85rem;
font-weight: 400;
text-transform: lowercase;
text-decoration: none;
transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
Expand Down
81 changes: 49 additions & 32 deletions src/lib/styles/variables.css
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
:root {
--bg-primary: #0a0a0a;
--bg-secondary: #111111;
--bg-tertiary: #1a1a1a;
--bg-hover: #222222;
--text-primary: #ffffff;
--text-secondary: #a0a0a0;
--text-muted: #666666;
--accent: #22c55e;
--accent-hover: #16a34a;
--accent-glow: rgba(34, 197, 94, 0.15);
--border: #2a2a2a;
--border-hover: #3a3a3a;
--code-bg: #1e1e1e;
--header-bg: rgba(10, 10, 10, 0.9);
--danger: #ef4444;
--danger-hover: #dc2626;
/* dark (default) — refined terminal-native */
--bg-primary: #0a0a0b;
--bg-secondary: #100f12;
--bg-tertiary: #161519;
--bg-hover: #1b1a1f;
--text-primary: #ededf0; /* soft white, not pure #fff */
--text-secondary: #9a99a2;
--text-muted: #777680; /* raised for AA */
--accent: #4ec98a; /* refined mint, not neon */
--accent-hover: #6ad9a0;
--accent-glow: rgba(78, 201, 138, 0.1);
--border: #1f1e22;
--border-hover: #2c2b30;
--code-bg: #161519;
--header-bg: rgba(10, 10, 11, 0.78);
--danger: #d4655c;
--danger-hover: #c0473d;
/* added */
--accent-deep: #2f6b4d;
--amber: #c9a14e;
--shadow: rgba(0, 0, 0, 0.5);
--vignette: color-mix(in srgb, var(--bg-primary) 55%, #000);
--grain-blend: soft-light;
--grain-opacity: 0.05;
--font-mono: 'Geist Mono', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

[data-theme='light'] {
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #f1f3f4;
--bg-hover: #e8eaed;
--text-primary: #1a1a1a;
--text-secondary: #5f6368;
--text-muted: #9aa0a6;
--accent: #16a34a;
--accent-hover: #15803d;
--accent-glow: rgba(22, 163, 74, 0.15);
--border: #e0e0e0;
--border-hover: #d0d0d0;
--code-bg: #f5f5f5;
--header-bg: rgba(255, 255, 255, 0.9);
--danger: #dc2626;
--danger-hover: #b91c1c;
/* light — "paper terminal" */
--bg-primary: #fafaf8;
--bg-secondary: #ffffff;
--bg-tertiary: #f3f3f0;
--bg-hover: #ecece7;
--text-primary: #18181b;
--text-secondary: #5b5b60;
--text-muted: #767679; /* raised for AA */
--accent: #1c7d52; /* deep green, AA on light */
--accent-hover: #176343;
--accent-glow: rgba(28, 125, 82, 0.08);
--border: #e7e7e2;
--border-hover: #d6d6cf;
--code-bg: #f3f3f0;
--header-bg: rgba(250, 250, 248, 0.78);
--danger: #c0473d;
--danger-hover: #a83a31;
/* added */
--accent-deep: #cde7d9;
--amber: #946a1a;
--shadow: rgba(20, 20, 30, 0.1);
--vignette: transparent;
--grain-blend: multiply;
--grain-opacity: 0.035;
}

/* Shiki dual-theme: dark mode (default) uses --shiki-dark, light mode uses --shiki-light */
Expand Down
Loading
Loading