Skip to content

Commit 2094e69

Browse files
fullstackjamclaude
andauthored
feat(ui): terminal-native redesign — fully-mono, dark-first (#16)
* docs: add terminal-native redesign design spec * feat(ui): terminal-native redesign — fully-mono, dark-first Refined terminal aesthetic across home, explore, docs, header, footer and config cards: Geist Mono throughout, restrained green accent, film-grain texture, hairline borders, soft shadows. Retires neon glows, 3D rotate, gradient text and rainbow blobs for a high-contrast, deliberate look in both dark and a new 'paper terminal' light mode. - variables.css: re-tuned dark/light tokens + grain/vignette/amber/font-mono - app.html: load Geist Mono (drop Outfit) - layout: global mono font, film-grain + vignette overlays, reduced-motion reset - hooks.server.ts: allow fonts.googleapis.com in style-src (fixes blocked font CSS) - home/explore/docs/cards: terminal-motif layouts, AA-contrast text Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7825885 commit 2094e69

10 files changed

Lines changed: 707 additions & 941 deletions

File tree

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Terminal-native redesign — design spec
2+
3+
**Date:** 2026-06-15
4+
**Status:** Approved (vibe confirmed via `design-demo/` prototype)
5+
**Scope:** Whole-site visual redesign (home, explore, config cards, docs, header, footer, shared shell)
6+
7+
## 1. Direction
8+
9+
Refined, terminal-native identity executed with **restraint** — the register is "high-end,
10+
textured, not flashy, no AI-smell," in the spirit of Vercel / pi.dev. Fully monospace, dark-first
11+
with a deliberate light mode. The terminal is the brand's visual *language* (prompts, carets, mono,
12+
command-style labels), not literal cosplay — sections are clean web layouts with **one** real
13+
terminal window as the signature moment.
14+
15+
**Anti-goals (the "AI-smell" to avoid):** purple/blue gradients, gradient blobs, heavy neon glows,
16+
over-rounded everything, evenly-distributed timid color, flat digital surfaces, emoji UI.
17+
18+
**Reference prototype:** `design-demo/index.html` (throwaway). The production build reproduces this
19+
look using the project's CSS-variable system and Svelte components. The demo is the source of truth
20+
for the visual target.
21+
22+
## 2. Design tokens
23+
24+
Re-map values onto the **existing** token names in `src/lib/styles/variables.css` (so components
25+
don't all need editing), and add the new tokens listed. Pure white text is intentionally retired in
26+
favor of a soft off-white for a premium feel.
27+
28+
### Dark (default)
29+
```
30+
--bg-primary: #0a0a0b (was #0a0a0a)
31+
--bg-secondary: #100f12 surface (cards, terminal, command box)
32+
--bg-tertiary: #161519 surface-2 (code blocks, raised)
33+
--bg-hover: #1b1a1f
34+
--text-primary: #ededf0 soft white, not #ffffff
35+
--text-secondary:#9a99a2
36+
--text-muted: #5b5a63
37+
--accent: #4ec98a refined mint (was neon #22c55e)
38+
--accent-hover: #6ad9a0
39+
--accent-glow: rgba(78,201,138,0.10) (lower than before)
40+
--border: #1f1e22
41+
--border-hover: #2c2b30
42+
--code-bg: #161519
43+
--header-bg: rgba(10,10,11,0.78)
44+
--danger: #d4655c refined red
45+
--danger-hover: #c0473d
46+
/* new */
47+
--accent-deep: #2f6b4d muted prompt / subtle ring
48+
--amber: #c9a14e secondary terminal color (warnings/steps)
49+
--shadow: rgba(0,0,0,0.5)
50+
--vignette: color-mix(in srgb, var(--bg-primary) 55%, #000)
51+
--grain-blend: soft-light
52+
--grain-opacity:0.05
53+
```
54+
55+
### Light ("paper terminal")
56+
```
57+
--bg-primary: #fafaf8 warm off-white (was stark #ffffff)
58+
--bg-secondary: #ffffff
59+
--bg-tertiary: #f3f3f0
60+
--bg-hover: #ecece7
61+
--text-primary: #18181b
62+
--text-secondary:#5b5b60
63+
--text-muted: #909095
64+
--accent: #1c7d52 deep green, AA on light
65+
--accent-hover: #176343
66+
--accent-glow: rgba(28,125,82,0.08)
67+
--border: #e7e7e2
68+
--border-hover: #d6d6cf
69+
--code-bg: #f3f3f0
70+
--header-bg: rgba(250,250,248,0.78)
71+
--danger: #c0473d
72+
--danger-hover: #a83a31
73+
/* new */
74+
--accent-deep: #cde7d9
75+
--amber: #946a1a
76+
--shadow: rgba(20,20,30,0.10)
77+
--vignette: transparent
78+
--grain-blend: multiply
79+
--grain-opacity:0.035
80+
```
81+
82+
## 3. Typography — fully monospace
83+
84+
- **Family:** Geist Mono (primary) → JetBrains Mono (fallback, already loaded) → system mono.
85+
Add a `--font-mono` token; set it as the global body font.
86+
- **Loading:** In `src/app.html`, replace the `Outfit` Google Fonts request with `Geist Mono`
87+
(weights 400/500/600). Keep `JetBrains Mono`. Outfit is removed entirely.
88+
- **Hierarchy comes from size / weight / color / case** (one family, no font-switching):
89+
90+
| Role | Size | Weight | Tracking | Notes |
91+
|------|------|--------|----------|-------|
92+
| Display (h1) | clamp(2.3rem, 4.6vw, 3.7rem) | 500 | -0.04em | line-height 1.04 |
93+
| h2 | 1.7rem | 500 | -0.025em | |
94+
| h3 | ~1rem | 500 | -0.01em | |
95+
| Body | 0.94rem | 400 || line-height 1.7, max-width ≤ 54–62ch |
96+
| Label / eyebrow | 0.72–0.8rem | 400/500 | 0.02–0.1em | often lowercase or `#`/`>`-prefixed, uppercase for footer col heads |
97+
98+
**Fully-mono readability guardrails (hard rules):** body line-height ≥ 1.7; text measure ≤ 62ch;
99+
body size ≥ 15px (0.94rem). These keep mono prose comfortable.
100+
101+
## 4. Texture, depth & motion
102+
103+
- **Film grain:** fixed full-viewport SVG fractal-noise overlay (`body::after`), `mix-blend-mode`
104+
and opacity per `--grain-blend` / `--grain-opacity`. This is the primary "texture." Add to the
105+
layout shell.
106+
- **Vignette:** subtle radial darkening at page edges in dark mode only (`--vignette`); transparent
107+
in light.
108+
- **Grid:** faint graph-paper grid behind the hero only, radial-masked, ~0.4 opacity. Not site-wide.
109+
- **Depth:** hairline 1px borders + soft low shadows (`--shadow`). No large lifts, no neon.
110+
- **Motion:** 150–250ms ease-out. Hover = border brightens + faint `--accent-glow` ring + ≤1px
111+
nudge. One on-scroll reveal (fade + 8px rise, once). Hero terminal auto-types. **All motion
112+
(typing, reveals, caret) disabled under `prefers-reduced-motion`** — terminal renders final state.
113+
114+
## 5. Component / file changes
115+
116+
Project uses **pure CSS + scoped `<style>` + CSS variables**, no Tailwind. Footer currently lives in
117+
`src/routes/+page.svelte`.
118+
119+
| File | Change |
120+
|------|--------|
121+
| `src/lib/styles/variables.css` | New token values + added tokens (§2). |
122+
| `src/app.html` | Swap Outfit→Geist Mono in the fonts link. |
123+
| `src/routes/+layout.svelte` | Global body font → `--font-mono`; add grain + vignette overlays; base type rhythm; `prefers-reduced-motion` reset. |
124+
| `src/lib/components/SiteHeader.svelte` | Terminal status-bar style: `$ openboot` (green prompt), lowercase mono nav, `★ 256`, refined ☾/☀ toggle, hairline border + blur. |
125+
| `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. |
126+
| `src/routes/explore/+page.svelte` | `> explore` prompt header; mono sort control; raise muted-text contrast; spacing rhythm. |
127+
| `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. |
128+
| Docs styles (mdsvex/docs layout) | Mono prose w/ readability guardrails; code blocks on `--bg-tertiary` w/ left green border; sidebar active item w/ `>` marker. |
129+
130+
## 6. Accessibility
131+
132+
- All text/background pairs meet **WCAG AA** (the new `--text-muted` and light-mode `--accent` are
133+
chosen for this; verify with a contrast check during build).
134+
- Full `prefers-reduced-motion` support (§4).
135+
- Keep keyboard focus styles; command/terminal copy actions remain reachable.
136+
137+
## 7. Quality (non-visual, in-scope)
138+
139+
- Investigate & fix the **2–3 console errors** seen on the live site during this pass.
140+
141+
## 8. Out of scope / non-goals
142+
143+
- No new pages, features, or copy rewrites beyond micro-labels (prompts, eyebrows). Marketing
144+
copywriting is a separate effort.
145+
- No backend / API / DB changes.
146+
- No framework or build-system changes (still SvelteKit + scoped CSS, no Tailwind).
147+
- `design-demo/` is a throwaway and is removed (or git-ignored) before merge.
148+
- Self-hosting Geist Mono (vs Google Fonts) is a possible later perf optimization, not this pass.
149+
150+
## 9. Success criteria
151+
152+
- Home, explore, docs, header, footer, config cards all render in the new terminal-native system,
153+
dark + light, both deliberate.
154+
- `npm run validate` (check + lint + test) passes.
155+
- Visual parity with the approved `design-demo/` look on the home page.
156+
- No remaining console errors on the main pages.
157+
- Target subjective quality: ~9/10 per the original critique's gap list, all six gaps closed.

src/app.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<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>" />
77
<link rel="preconnect" href="https://fonts.googleapis.com" />
88
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9-
<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" />
9+
<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" />
1010
<meta property="og:type" content="website" />
1111
<meta property="og:site_name" content="OpenBoot" />
1212
%sveltekit.head%

src/hooks.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const SECURITY_HEADERS: Record<string, string> = {
1919
'Content-Security-Policy': [
2020
"default-src 'self'",
2121
"script-src 'self' 'unsafe-inline'",
22-
"style-src 'self' 'unsafe-inline'",
22+
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
2323
"img-src 'self' https: data:",
2424
"font-src 'self' https://fonts.gstatic.com",
2525
"connect-src 'self' https://api.github.com https://accounts.google.com https://oauth2.googleapis.com https://formulae.brew.sh https://registry.npmjs.org",

src/lib/components/ConfigCard.svelte

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,8 @@
188188
}
189189
190190
.card:hover {
191-
border-color: var(--card-border-hover);
192-
transform: translateY(-4px);
193-
box-shadow: 0 20px 50px -12px rgba(var(--card-accent), 0.15);
191+
border-color: var(--border-hover);
192+
box-shadow: 0 0 0 1px var(--accent-glow), 0 14px 40px -22px var(--shadow);
194193
}
195194
196195
.card:focus-visible {
@@ -235,11 +234,12 @@
235234
}
236235
237236
.card-name {
238-
font-size: 1.2rem;
239-
font-weight: 700;
237+
font-size: 1.1rem;
238+
font-weight: 600;
240239
color: var(--text-primary);
241240
margin: 0;
242241
line-height: 1.3;
242+
letter-spacing: -0.01em;
243243
}
244244
245245
.card-slug {
@@ -264,7 +264,7 @@
264264
.vis-tag {
265265
padding: 3px 8px;
266266
font-size: 0.6rem;
267-
font-weight: 700;
267+
font-weight: 600;
268268
text-transform: uppercase;
269269
letter-spacing: 0.06em;
270270
border-radius: 5px;
@@ -301,8 +301,8 @@
301301
}
302302
303303
.stat-val {
304-
font-size: 1.5rem;
305-
font-weight: 800;
304+
font-size: 1.4rem;
305+
font-weight: 600;
306306
line-height: 1;
307307
color: var(--text-primary);
308308
font-variant-numeric: tabular-nums;

src/lib/components/SiteHeader.svelte

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<header class="site-header">
1414
<div class="header-container">
1515
<div class="header-left">
16-
<a href="/" class="header-logo">OpenBoot</a>
16+
<a href="/" class="header-logo"><span class="prompt">$</span> openboot</a>
1717
<nav class="header-nav">
1818
<a href="/explore" class:active={currentPath === '/explore' || currentPath.startsWith('/explore')}>Explore</a>
1919
<a href="/docs" class:active={currentPath === '/docs' || currentPath.startsWith('/docs')}>Docs</a>
@@ -52,9 +52,10 @@
5252
}
5353
5454
.header-container {
55-
max-width: 1200px;
55+
max-width: 1160px;
5656
margin: 0 auto;
57-
padding: 14px 24px;
57+
height: 56px;
58+
padding: 0 36px;
5859
display: flex;
5960
justify-content: space-between;
6061
align-items: center;
@@ -63,33 +64,39 @@
6364
.header-left {
6465
display: flex;
6566
align-items: center;
66-
gap: 20px;
67+
gap: 26px;
6768
}
6869
6970
.header-logo {
70-
font-family: 'JetBrains Mono', monospace;
71-
font-size: 1.05rem;
72-
font-weight: 700;
73-
color: var(--accent);
74-
letter-spacing: -0.02em;
71+
font-family: var(--font-mono);
72+
font-size: 0.95rem;
73+
font-weight: 500;
74+
color: var(--text-primary);
75+
letter-spacing: -0.01em;
7576
text-decoration: none;
7677
transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
7778
}
7879
80+
.header-logo .prompt {
81+
color: var(--accent);
82+
margin-right: 2px;
83+
}
84+
7985
.header-logo:hover {
8086
opacity: 0.8;
8187
}
8288
8389
.header-nav {
8490
display: flex;
8591
align-items: center;
86-
gap: 20px;
92+
gap: 22px;
8793
}
8894
8995
.header-nav a {
9096
color: var(--text-secondary);
91-
font-size: 0.9rem;
92-
font-weight: 500;
97+
font-size: 0.85rem;
98+
font-weight: 400;
99+
text-transform: lowercase;
93100
text-decoration: none;
94101
transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
95102
position: relative;

src/lib/styles/variables.css

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,56 @@
11
:root {
2-
--bg-primary: #0a0a0a;
3-
--bg-secondary: #111111;
4-
--bg-tertiary: #1a1a1a;
5-
--bg-hover: #222222;
6-
--text-primary: #ffffff;
7-
--text-secondary: #a0a0a0;
8-
--text-muted: #666666;
9-
--accent: #22c55e;
10-
--accent-hover: #16a34a;
11-
--accent-glow: rgba(34, 197, 94, 0.15);
12-
--border: #2a2a2a;
13-
--border-hover: #3a3a3a;
14-
--code-bg: #1e1e1e;
15-
--header-bg: rgba(10, 10, 10, 0.9);
16-
--danger: #ef4444;
17-
--danger-hover: #dc2626;
2+
/* dark (default) — refined terminal-native */
3+
--bg-primary: #0a0a0b;
4+
--bg-secondary: #100f12;
5+
--bg-tertiary: #161519;
6+
--bg-hover: #1b1a1f;
7+
--text-primary: #ededf0; /* soft white, not pure #fff */
8+
--text-secondary: #9a99a2;
9+
--text-muted: #777680; /* raised for AA */
10+
--accent: #4ec98a; /* refined mint, not neon */
11+
--accent-hover: #6ad9a0;
12+
--accent-glow: rgba(78, 201, 138, 0.1);
13+
--border: #1f1e22;
14+
--border-hover: #2c2b30;
15+
--code-bg: #161519;
16+
--header-bg: rgba(10, 10, 11, 0.78);
17+
--danger: #d4655c;
18+
--danger-hover: #c0473d;
19+
/* added */
20+
--accent-deep: #2f6b4d;
21+
--amber: #c9a14e;
22+
--shadow: rgba(0, 0, 0, 0.5);
23+
--vignette: color-mix(in srgb, var(--bg-primary) 55%, #000);
24+
--grain-blend: soft-light;
25+
--grain-opacity: 0.05;
26+
--font-mono: 'Geist Mono', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
1827
}
1928

2029
[data-theme='light'] {
21-
--bg-primary: #ffffff;
22-
--bg-secondary: #f8f9fa;
23-
--bg-tertiary: #f1f3f4;
24-
--bg-hover: #e8eaed;
25-
--text-primary: #1a1a1a;
26-
--text-secondary: #5f6368;
27-
--text-muted: #9aa0a6;
28-
--accent: #16a34a;
29-
--accent-hover: #15803d;
30-
--accent-glow: rgba(22, 163, 74, 0.15);
31-
--border: #e0e0e0;
32-
--border-hover: #d0d0d0;
33-
--code-bg: #f5f5f5;
34-
--header-bg: rgba(255, 255, 255, 0.9);
35-
--danger: #dc2626;
36-
--danger-hover: #b91c1c;
30+
/* light — "paper terminal" */
31+
--bg-primary: #fafaf8;
32+
--bg-secondary: #ffffff;
33+
--bg-tertiary: #f3f3f0;
34+
--bg-hover: #ecece7;
35+
--text-primary: #18181b;
36+
--text-secondary: #5b5b60;
37+
--text-muted: #767679; /* raised for AA */
38+
--accent: #1c7d52; /* deep green, AA on light */
39+
--accent-hover: #176343;
40+
--accent-glow: rgba(28, 125, 82, 0.08);
41+
--border: #e7e7e2;
42+
--border-hover: #d6d6cf;
43+
--code-bg: #f3f3f0;
44+
--header-bg: rgba(250, 250, 248, 0.78);
45+
--danger: #c0473d;
46+
--danger-hover: #a83a31;
47+
/* added */
48+
--accent-deep: #cde7d9;
49+
--amber: #946a1a;
50+
--shadow: rgba(20, 20, 30, 0.1);
51+
--vignette: transparent;
52+
--grain-blend: multiply;
53+
--grain-opacity: 0.035;
3754
}
3855

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

0 commit comments

Comments
 (0)