update design handoff with framework-free token exports

New tokens/ directory with YAML palette + syntax files for all
four themes, plus a pure dart:ui Dart file (no Material). README
updated to reflect the no-Material constraint and open typography
question.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-04-22 16:29:17 +02:00
co-authored by Claude
parent 272b59e752
commit de9a7b9745
6 changed files with 520 additions and 22 deletions
+85 -22
View File
@@ -14,11 +14,12 @@ bundle/
├─ Clide Hi-Fi.html ← 3 hi-fi scenes · 4 swappable themes
├─ Clide Design System.html ← tokens · type · components · syntax
├─ themes/ ← DROP-IN Dart files
│ ├─ clide_theme.dart (default · cool near-black + periwinkle)
│ ├─ midnight_theme.dart (VS Code-adjacent muted dark)
│ ├─ paper_theme.dart (drafting-sheet light)
─ terminal_theme.dart (near-black + amber)
├─ tokens/ ← framework-free token exports
│ ├─ clide.yaml (default · cool near-black + periwinkle)
│ ├─ midnight.yaml (VS Code-adjacent muted dark)
│ ├─ paper.yaml (drafting-sheet light)
─ terminal.yaml (near-black + amber)
│ └─ clide_tokens.dart (all four themes · pure `dart:ui`, no Material)
└─ png/ ← flat renders for tickets / PRs
├─ wireframe-layout.png
@@ -42,11 +43,11 @@ Drop the bundle into the repo (e.g. `docs/design/`) and point Claude at it:
```bash
claude "read docs/design/README.md and docs/design/Clide\ Design\ System.html,
then implement the Clide theme from docs/design/themes/clide_theme.dart
so it's wired through kernel/theme.dart"
then adopt the clide palette from docs/design/tokens/clide.yaml
into our theme pipeline"
```
Claude Code can parse the HTML natively and see every token value, component, and layout annotation. It can also read the Dart theme files without conversion.
Claude Code can parse the HTML natively and see every token value, component, and layout annotation. The YAML files match the clide theme pipeline format; the Dart file is there as a convenience for literal-paste.
---
@@ -57,6 +58,8 @@ Claude Code can parse the HTML natively and see every token value, component, an
- **Display** — `Josefin Sans 300` for titles, section heads, and the wordmark. Light weight is load-bearing; using 400+ changes the feel entirely.
- **UI + code** — `JetBrains Mono 400/500` for everything else. Tab labels, file paths, status bar, editor. Monospace is a deliberate choice — clide is an IDE for people who like their grids.
> **Open question** — whether UI chrome text should be mono too, or reserved for code surfaces only. The hi-fi currently runs mono across the board; swapping to a prop sans in chrome is a ~5-file edit.
### 2 · Layout (classicPreset)
Three columns + statusbar. Every box in the frame is a `SlotHost` slot populated by `TabContribution`s sorted by priority (lower = leftmost tab).
@@ -64,18 +67,20 @@ Three columns + statusbar. Every box in the frame is a `SlotHost` slot populated
```
┌────────────┬──────────────────────┬──────────────┐
│ sidebar │ workspace │ context │
240 px │ flex │ 300 px │
│ 180400 │ │ 220420 │
180 px │ flex │ 300 px │
│ 160360 │ │ 220420 │
├────────────┴──────────────────────┴──────────────┤
│ statusbar · 24 px │
└──────────────────────────────────────────────────┘
```
Sidebar navigates via a bottom **icon rail** (Files / Git / pql / Problems), not tabs at the top.
See `Wireframe.html` for the full architectural breakdown — every red-pencil annotation cites the source file it came from.
### 3 · Themes
Four presets ship by default. `clide` is the reference — the other three are variations on the same component vocabulary, differing only in token values.
Four presets ship by default. `clide` is the reference — the other three are variations on the same component vocabulary, differing only in palette values.
| name | bg | accent | feel |
|------------|-----------|-----------|-------------------------------|
@@ -84,20 +89,78 @@ Four presets ship by default. `clide` is the reference — the other three are v
| `paper` | `#F4F1EA` | `#C14B2A` | drafting sheet · light |
| `terminal` | `#0A0A0A` | `#E0B050` | near-black + amber |
All four share the same semantic token names (`bg`, `surface`, `border`, `text`, `accent`, `ok/warn/err/info`, syntax roles). A widget written against the tokens will render correctly in all four.
All four share the same palette keys (`bg`, `surface`, `border`, `text*`, `accent`, `ok/warn/err/info`) and syntax roles. A widget written against a semantic role will render correctly in all four.
### 4 · Drop-in usage
### 4 · Token shape
```dart
import 'themes/clide_theme.dart';
No Material wrapper. Tokens ship in two flavors — pick whichever your pipeline already handles.
MaterialApp(
theme: ClideTheme.data,
home: const ClideApp(),
);
**YAML** (preferred — matches the clide theme pipeline):
```yaml
name: clide
dark: true
palette:
bg: "#20202C"
bgSunken: "#1A1A24"
surface: "#242838"
surfaceHi: "#2C3046"
border: "#343850"
borderHi: "#3C445C"
textHi: "#E6E8F2"
text: "#B1BBE3"
textDim: "#78809C"
textMute: "#545C84"
accent: "#78A0F8"
accentPress: "#6C90DC"
accentSoft: "rgba(120,160,248,0.13)"
onAccent: "#0D1020"
ok: "#7DD3A8"
warn: "#E6C370"
err: "#E87D7D"
info: "#78A0F8"
syntax:
keyword: "#C792EA"
type: "#78A0F8"
string: "#A8D99B"
number: "#E6C370"
comment: "#545C84"
method: "#82B1FF"
punct: "#78809C"
```
The `ClideTheme.tokens` object exposes semantic colors for cases where a Material widget can't carry the meaning — e.g. syntax highlighting, git status markers, Claude message kinds.
**Dart** (pure `dart:ui` — no Flutter material/cupertino imports):
```dart
import 'tokens/clide_tokens.dart';
final theme = ClideThemes.clide;
paintWith(theme.palette.accent);
highlightWith(theme.syntax.keyword);
```
`clide_tokens.dart` declares all four themes in one file — `ClideThemes.clide`, `.midnight`, `.paper`, `.terminal`, plus `.all` and `.defaultTheme`.
### 5 · Palette key reference
| key | role |
|---------------|-------------------------------------------------------|
| `bg` | page / editor canvas |
| `bgSunken` | sidebar, gutters, anything below the main surface |
| `surface` | cards, table header, pill backgrounds |
| `surfaceHi` | hover / selected row |
| `border` | hairlines, dividers |
| `borderHi` | outlined controls, focus rings |
| `textHi` | primary text |
| `text` | secondary labels |
| `textDim` | metadata |
| `textMute` | all-caps section labels, disabled |
| `accent` | brand / primary |
| `accentPress` | pressed state |
| `accentSoft` | tinted fills (13% alpha accent) |
| `onAccent` | text on accent bg |
| `ok/warn/err` | status |
| `info` | neutral info; often === `accent` |
---
@@ -106,7 +169,7 @@ The `ClideTheme.tokens` object exposes semantic colors for cases where a Materia
| # | screen | purpose |
|---|--------------------------------|----------------------------------------------------------|
| 1 | **Main IDE · at rest** | cold-start settled · all slots populated · Claude primary |
| 2 | **Editor · with Claude panel** | file editor in workspace · Claude as context-column tab |
| 2 | **Claude + editor reference** | Claude as workspace center · pinned editor in right pane |
| 3 | **Welcome · no project** | first-run landing · start actions + recent projects |
Open `Clide Hi-Fi.html` and use the floating Tweaks panel (bottom-right, toggle from the toolbar) to swap between themes live.
@@ -131,4 +194,4 @@ These are the highest-leverage next design targets.
All HTMLs render offline, no network required after first open. Fonts are bundled as CSS and fall back to system monospace if Josefin Sans or JetBrains Mono are blocked.
Generated by the design pass · refreshed 2026-04
Generated by the design pass · refreshed 2026-04 · v2 (tokens-only, no Material)
+55
View File
@@ -0,0 +1,55 @@
# clide theme · clide
# cool near-black + periwinkle · default
#
# Flat palette. Raw hex values — no wrappers, no framework.
# Layer your semantic roles on top of these keys; surface tokens consume
# the semantic layer, not palette directly.
name: clide
dark: true
subtitle: "cool near-black + periwinkle · default"
palette:
bg: "#20202C"
bgSunken: "#1A1A24"
surface: "#242838"
surfaceHi: "#2C3046"
border: "#343850"
borderHi: "#3C445C"
textHi: "#E6E8F2"
text: "#B1BBE3"
textDim: "#78809C"
textMute: "#545C84"
accent: "#78A0F8"
accentPress: "#6C90DC"
accentSoft: "rgba(120,160,248,0.13)"
onAccent: "#0D1020"
ok: "#7DD3A8"
warn: "#E6C370"
err: "#E87D7D"
info: "#78A0F8"
syntax:
keyword: "#C792EA"
type: "#78A0F8"
string: "#A8D99B"
number: "#E6C370"
comment: "#545C84"
method: "#82B1FF"
punct: "#78809C"
# Suggested semantic roles (rename to whatever your pipeline uses):
#
# text -> palette.textHi
# textMuted -> palette.textDim
# textSubtle -> palette.textMute
# bg -> palette.bg
# bgSurface -> palette.surface
# bgHover -> palette.surfaceHi
# divider -> palette.border
# brand -> palette.accent
# brandOn -> palette.onAccent
# status.ok -> palette.ok
# status.warn -> palette.warn
# status.err -> palette.err
# status.info -> palette.info
+215
View File
@@ -0,0 +1,215 @@
// clide_tokens.dart
//
// Raw token values for the four default clide themes — framework-free.
// No Material, no Cupertino, no ThemeData. Just colors, organized into a
// flat palette + syntax block. Wire these into your theme pipeline
// (YAML palette -> semantic roles -> surface tokens).
//
// Mirror of bundle/tokens/*.yaml · keep them in sync.
import 'dart:ui' show Color;
class ClideTheme {
const ClideTheme({
required this.name,
required this.dark,
required this.subtitle,
required this.palette,
required this.syntax,
});
final String name;
final bool dark;
final String subtitle;
final ClidePalette palette;
final ClideSyntax syntax;
}
class ClidePalette {
const ClidePalette({
required this.bg,
required this.bgSunken,
required this.surface,
required this.surfaceHi,
required this.border,
required this.borderHi,
required this.textHi,
required this.text,
required this.textDim,
required this.textMute,
required this.accent,
required this.accentPress,
required this.accentSoft,
required this.onAccent,
required this.ok,
required this.warn,
required this.err,
required this.info,
});
final Color bg, bgSunken, surface, surfaceHi;
final Color border, borderHi;
final Color textHi, text, textDim, textMute;
final Color accent, accentPress, accentSoft, onAccent;
final Color ok, warn, err, info;
}
class ClideSyntax {
const ClideSyntax({
required this.keyword,
required this.type,
required this.string,
required this.number,
required this.comment,
required this.method,
required this.punct,
});
final Color keyword, type, string, number, comment, method, punct;
}
class ClideThemes {
// ─── clide ───────────────────────────────────────────────────────
static const clide = ClideTheme(
name: 'clide',
dark: true,
subtitle: 'cool near-black + periwinkle · default',
palette: ClidePalette(
bg: Color(0xFF20202C),
bgSunken: Color(0xFF1A1A24),
surface: Color(0xFF242838),
surfaceHi: Color(0xFF2C3046),
border: Color(0xFF343850),
borderHi: Color(0xFF3C445C),
textHi: Color(0xFFE6E8F2),
text: Color(0xFFB1BBE3),
textDim: Color(0xFF78809C),
textMute: Color(0xFF545C84),
accent: Color(0xFF78A0F8),
accentPress: Color(0xFF6C90DC),
accentSoft: Color(0x2178A0F8),
onAccent: Color(0xFF0D1020),
ok: Color(0xFF7DD3A8),
warn: Color(0xFFE6C370),
err: Color(0xFFE87D7D),
info: Color(0xFF78A0F8),
),
syntax: ClideSyntax(
keyword: Color(0xFFC792EA),
type: Color(0xFF78A0F8),
string: Color(0xFFA8D99B),
number: Color(0xFFE6C370),
comment: Color(0xFF545C84),
method: Color(0xFF82B1FF),
punct: Color(0xFF78809C),
),
);
// ─── midnight ────────────────────────────────────────────────────
static const midnight = ClideTheme(
name: 'midnight',
dark: true,
subtitle: 'VS Code-adjacent muted dark',
palette: ClidePalette(
bg: Color(0xFF1E1E1E),
bgSunken: Color(0xFF181818),
surface: Color(0xFF252526),
surfaceHi: Color(0xFF2D2D2E),
border: Color(0xFF333333),
borderHi: Color(0xFF3F3F3F),
textHi: Color(0xFFD4D4D4),
text: Color(0xFFBBBBBB),
textDim: Color(0xFF858585),
textMute: Color(0xFF6A6A6A),
accent: Color(0xFF569CD6),
accentPress: Color(0xFF4785BD),
accentSoft: Color(0x21569CD6),
onAccent: Color(0xFF0B1220),
ok: Color(0xFF89D185),
warn: Color(0xFFD7BA7D),
err: Color(0xFFF48771),
info: Color(0xFF569CD6),
),
syntax: ClideSyntax(
keyword: Color(0xFFC586C0),
type: Color(0xFF4EC9B0),
string: Color(0xFFCE9178),
number: Color(0xFFB5CEA8),
comment: Color(0xFF6A9955),
method: Color(0xFFDCDCAA),
punct: Color(0xFF858585),
),
);
// ─── paper ───────────────────────────────────────────────────────
static const paper = ClideTheme(
name: 'paper',
dark: false,
subtitle: 'drafting sheet · red-pencil accent · light',
palette: ClidePalette(
bg: Color(0xFFF4F1EA),
bgSunken: Color(0xFFECE7DB),
surface: Color(0xFFFBF8F1),
surfaceHi: Color(0xFFECE7DB),
border: Color(0xFF1A1A1A),
borderHi: Color(0xFF4A4A4A),
textHi: Color(0xFF1A1A1A),
text: Color(0xFF4A4A4A),
textDim: Color(0xFF8A8A82),
textMute: Color(0xFFA8A89E),
accent: Color(0xFFC14B2A),
accentPress: Color(0xFFA03D20),
accentSoft: Color(0x21C14B2A),
onAccent: Color(0xFFFBF8F1),
ok: Color(0xFF2D8A52),
warn: Color(0xFFB88A2A),
err: Color(0xFFB03A2A),
info: Color(0xFF2A6FC1),
),
syntax: ClideSyntax(
keyword: Color(0xFF7B3F8C),
type: Color(0xFF2A6FC1),
string: Color(0xFF2D8A52),
number: Color(0xFFB88A2A),
comment: Color(0xFF8A8A82),
method: Color(0xFF1E5D9E),
punct: Color(0xFF4A4A4A),
),
);
// ─── terminal ────────────────────────────────────────────────────
static const terminal = ClideTheme(
name: 'terminal',
dark: true,
subtitle: 'near-black + amber · tmux feel',
palette: ClidePalette(
bg: Color(0xFF0A0A0A),
bgSunken: Color(0xFF000000),
surface: Color(0xFF111111),
surfaceHi: Color(0xFF181818),
border: Color(0xFF242424),
borderHi: Color(0xFF2E2E2E),
textHi: Color(0xFFE6E6E6),
text: Color(0xFFBDBDBD),
textDim: Color(0xFF7A7A7A),
textMute: Color(0xFF4A4A4A),
accent: Color(0xFFE0B050),
accentPress: Color(0xFFC29438),
accentSoft: Color(0x21E0B050),
onAccent: Color(0xFF000000),
ok: Color(0xFF8FDC9B),
warn: Color(0xFFE0B050),
err: Color(0xFFE05050),
info: Color(0xFFA3C4FF),
),
syntax: ClideSyntax(
keyword: Color(0xFFE05050),
type: Color(0xFFE0B050),
string: Color(0xFF8FDC9B),
number: Color(0xFFC792EA),
comment: Color(0xFF4A4A4A),
method: Color(0xFFA3C4FF),
punct: Color(0xFF7A7A7A),
),
);
static const all = [clide, midnight, paper, terminal];
static const defaultTheme = clide;
}
+55
View File
@@ -0,0 +1,55 @@
# clide theme · midnight
# VS Code-adjacent muted dark
#
# Flat palette. Raw hex values — no wrappers, no framework.
# Layer your semantic roles on top of these keys; surface tokens consume
# the semantic layer, not palette directly.
name: midnight
dark: true
subtitle: "VS Code-adjacent muted dark"
palette:
bg: "#1E1E1E"
bgSunken: "#181818"
surface: "#252526"
surfaceHi: "#2D2D2E"
border: "#333333"
borderHi: "#3F3F3F"
textHi: "#D4D4D4"
text: "#BBBBBB"
textDim: "#858585"
textMute: "#6A6A6A"
accent: "#569CD6"
accentPress: "#4785BD"
accentSoft: "rgba(86,156,214,0.13)"
onAccent: "#0B1220"
ok: "#89D185"
warn: "#D7BA7D"
err: "#F48771"
info: "#569CD6"
syntax:
keyword: "#C586C0"
type: "#4EC9B0"
string: "#CE9178"
number: "#B5CEA8"
comment: "#6A9955"
method: "#DCDCAA"
punct: "#858585"
# Suggested semantic roles (rename to whatever your pipeline uses):
#
# text -> palette.textHi
# textMuted -> palette.textDim
# textSubtle -> palette.textMute
# bg -> palette.bg
# bgSurface -> palette.surface
# bgHover -> palette.surfaceHi
# divider -> palette.border
# brand -> palette.accent
# brandOn -> palette.onAccent
# status.ok -> palette.ok
# status.warn -> palette.warn
# status.err -> palette.err
# status.info -> palette.info
+55
View File
@@ -0,0 +1,55 @@
# clide theme · paper
# drafting sheet · red-pencil accent · light
#
# Flat palette. Raw hex values — no wrappers, no framework.
# Layer your semantic roles on top of these keys; surface tokens consume
# the semantic layer, not palette directly.
name: paper
dark: false
subtitle: "drafting sheet · red-pencil accent · light"
palette:
bg: "#F4F1EA"
bgSunken: "#ECE7DB"
surface: "#FBF8F1"
surfaceHi: "#ECE7DB"
border: "#1A1A1A"
borderHi: "#4A4A4A"
textHi: "#1A1A1A"
text: "#4A4A4A"
textDim: "#8A8A82"
textMute: "#A8A89E"
accent: "#C14B2A"
accentPress: "#A03D20"
accentSoft: "rgba(193,75,42,0.13)"
onAccent: "#FBF8F1"
ok: "#2D8A52"
warn: "#B88A2A"
err: "#B03A2A"
info: "#2A6FC1"
syntax:
keyword: "#7B3F8C"
type: "#2A6FC1"
string: "#2D8A52"
number: "#B88A2A"
comment: "#8A8A82"
method: "#1E5D9E"
punct: "#4A4A4A"
# Suggested semantic roles (rename to whatever your pipeline uses):
#
# text -> palette.textHi
# textMuted -> palette.textDim
# textSubtle -> palette.textMute
# bg -> palette.bg
# bgSurface -> palette.surface
# bgHover -> palette.surfaceHi
# divider -> palette.border
# brand -> palette.accent
# brandOn -> palette.onAccent
# status.ok -> palette.ok
# status.warn -> palette.warn
# status.err -> palette.err
# status.info -> palette.info
+55
View File
@@ -0,0 +1,55 @@
# clide theme · terminal
# near-black + amber · tmux feel
#
# Flat palette. Raw hex values — no wrappers, no framework.
# Layer your semantic roles on top of these keys; surface tokens consume
# the semantic layer, not palette directly.
name: terminal
dark: true
subtitle: "near-black + amber · tmux feel"
palette:
bg: "#0A0A0A"
bgSunken: "#000000"
surface: "#111111"
surfaceHi: "#181818"
border: "#242424"
borderHi: "#2E2E2E"
textHi: "#E6E6E6"
text: "#BDBDBD"
textDim: "#7A7A7A"
textMute: "#4A4A4A"
accent: "#E0B050"
accentPress: "#C29438"
accentSoft: "rgba(224,176,80,0.13)"
onAccent: "#000000"
ok: "#8FDC9B"
warn: "#E0B050"
err: "#E05050"
info: "#A3C4FF"
syntax:
keyword: "#E05050"
type: "#E0B050"
string: "#8FDC9B"
number: "#C792EA"
comment: "#4A4A4A"
method: "#A3C4FF"
punct: "#7A7A7A"
# Suggested semantic roles (rename to whatever your pipeline uses):
#
# text -> palette.textHi
# textMuted -> palette.textDim
# textSubtle -> palette.textMute
# bg -> palette.bg
# bgSurface -> palette.surface
# bgHover -> palette.surfaceHi
# divider -> palette.border
# brand -> palette.accent
# brandOn -> palette.onAccent
# status.ok -> palette.ok
# status.warn -> palette.warn
# status.err -> palette.err
# status.info -> palette.info