-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathDESIGN.json
More file actions
192 lines (192 loc) · 13.4 KB
/
Copy pathDESIGN.json
File metadata and controls
192 lines (192 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
{
"schemaVersion": 2,
"generatedAt": "2026-07-02T17:47:50Z",
"title": "Design System: JAT",
"extensions": {
"colorMeta": {
"base-bg": {
"role": "neutral",
"displayName": "Base Background",
"canonical": "oklch(22% 0.01 250)",
"tonalRamp": ["oklch(14% 0.02 250)", "oklch(18% 0.015 250)", "oklch(22% 0.01 250)", "oklch(30% 0.02 250)", "oklch(45% 0.02 250)", "oklch(60% 0.02 250)", "oklch(75% 0.02 250)", "oklch(85% 0.02 250)"]
},
"base-content": {
"role": "neutral",
"displayName": "Base Content",
"canonical": "oklch(85% 0.02 250)",
"tonalRamp": ["oklch(30% 0.02 250)", "oklch(45% 0.02 250)", "oklch(55% 0.02 250)", "oklch(65% 0.02 250)", "oklch(75% 0.02 250)", "oklch(85% 0.02 250)", "oklch(92% 0.01 250)", "oklch(98% 0.01 250)"]
},
"industrial-blue": {
"role": "primary",
"displayName": "Industrial Blue",
"canonical": "oklch(70% 0.18 240)",
"tonalRamp": ["oklch(30% 0.10 240)", "oklch(40% 0.13 240)", "oklch(50% 0.15 240)", "oklch(60% 0.15 240)", "oklch(70% 0.18 240)", "oklch(80% 0.18 240)", "oklch(88% 0.12 240)", "oklch(95% 0.06 240)"]
},
"muted-purple": {
"role": "secondary",
"displayName": "Muted Purple",
"canonical": "oklch(50% 0.10 280)",
"tonalRamp": ["oklch(25% 0.08 280)", "oklch(35% 0.10 280)", "oklch(45% 0.12 280)", "oklch(50% 0.10 280)", "oklch(60% 0.18 280)", "oklch(70% 0.20 280)", "oklch(82% 0.12 280)", "oklch(92% 0.06 280)"]
},
"signal-cyan": {
"role": "tertiary",
"displayName": "Signal Cyan",
"canonical": "oklch(75% 0.15 200)",
"tonalRamp": ["oklch(30% 0.08 200)", "oklch(45% 0.12 200)", "oklch(60% 0.14 200)", "oklch(70% 0.18 200)", "oklch(75% 0.15 200)", "oklch(85% 0.18 200)", "oklch(92% 0.10 200)", "oklch(97% 0.04 200)"]
},
"working-amber": {
"role": "state",
"displayName": "Working Amber",
"canonical": "oklch(75% 0.16 85)",
"tonalRamp": ["oklch(35% 0.08 85)", "oklch(50% 0.12 85)", "oklch(65% 0.15 85)", "oklch(75% 0.16 85)", "oklch(80% 0.18 85)", "oklch(88% 0.15 85)", "oklch(93% 0.10 85)", "oklch(97% 0.05 85)"]
},
"success-green": {
"role": "state",
"displayName": "Success Green",
"canonical": "oklch(65% 0.20 145)",
"tonalRamp": ["oklch(30% 0.10 145)", "oklch(45% 0.15 145)", "oklch(55% 0.18 145)", "oklch(65% 0.20 145)", "oklch(72% 0.20 145)", "oklch(82% 0.16 145)", "oklch(90% 0.10 145)", "oklch(96% 0.05 145)"]
},
"error-red": {
"role": "state",
"displayName": "Error Red",
"canonical": "oklch(65% 0.22 25)",
"tonalRamp": ["oklch(30% 0.12 25)", "oklch(45% 0.18 25)", "oklch(55% 0.20 25)", "oklch(65% 0.22 25)", "oklch(72% 0.20 25)", "oklch(82% 0.16 25)", "oklch(90% 0.10 25)", "oklch(96% 0.05 25)"]
}
},
"typographyMeta": {
"display": { "displayName": "Display", "purpose": "Route/section headers via PageHeader — the largest text in a product surface." },
"title": { "displayName": "Title", "purpose": "Small uppercase/tracked instrument label — panel + section headers." },
"body": { "displayName": "Body", "purpose": "Default UI text, descriptions, table cells." },
"label": { "displayName": "Label", "purpose": "Badge text, meta chips, micro-labels." },
"data": { "displayName": "Data (Mono)", "purpose": "IDs, timestamps, code, agent output, log lines. Reserved — never for prose." }
},
"shadows": [
{
"name": "state-glow",
"value": "0 0 20px color-mix(in oklch, var(--anim-primary) 40%, transparent)",
"purpose": "State-signaling glow under session cards / task rows. Hue tracks the agent state (blue/amber/green/red). NOT ambient elevation."
}
],
"motion": [
{
"name": "ease-entrance",
"value": "cubic-bezier(0.250, 0.460, 0.450, 0.940)",
"purpose": "Ease-out for entrances — quick start, gentle settle. ~300-500ms."
},
{
"name": "ease-exit",
"value": "cubic-bezier(0.550, 0.085, 0.680, 0.530)",
"purpose": "Ease-in for exits — slow start, accelerating departure."
},
{
"name": "ease-bounce",
"value": "cubic-bezier(0.34, 1.56, 0.64, 1)",
"purpose": "Playful feedback (pop, ring-pulse)."
}
],
"breakpoints": [
{ "name": "sm", "value": "640px" },
{ "name": "md", "value": "768px" },
{ "name": "lg", "value": "1024px" },
{ "name": "xl", "value": "1280px" }
]
},
"components": [
{
"name": "Primary Button",
"kind": "button",
"refersTo": "button-primary",
"description": "The primary action — industrial blue, used sparingly for the main action on a surface.",
"html": "<button class=\"ds-btn-primary\">Spawn Agent</button>",
"css": ".ds-btn-primary { background: oklch(70% 0.18 240); color: oklch(22% 0.01 250); padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500; border: none; border-radius: 0.25rem; transition: filter 0.15s, transform 0.15s; } .ds-btn-primary:hover { filter: brightness(1.1); } .ds-btn-primary:focus-visible { outline: 2px solid oklch(80% 0.18 240); outline-offset: 2px; } .ds-btn-primary:active { transform: translateY(1px); }"
},
{
"name": "State Badge (Working)",
"kind": "chip",
"refersTo": "badge-state-working",
"description": "A live session-state badge. Background/text derive from the state hue in statusColors.ts — working is amber. Every state paints one hue as bar, badge, and glow.",
"html": "<span class=\"ds-badge-working\">Working</span>",
"css": ".ds-badge-working { display: inline-flex; align-items: center; gap: 0.25rem; background: color-mix(in oklch, oklch(75% 0.16 85) 18%, transparent); color: oklch(85% 0.16 85); border: 1px solid color-mix(in oklch, oklch(75% 0.16 85) 40%, transparent); border-radius: 0.375rem; padding: 0.125rem 0.5rem; font-size: 0.6875rem; font-weight: 500; letter-spacing: 0.05em; }"
},
{
"name": "Session Card",
"kind": "card",
"refersTo": "card-session",
"description": "JAT's signature surface — a live agent card with a semantic state-colored left accent bar (sourced from statusColors.ts) and a state glow. The cockpit's primary readout.",
"html": "<div class=\"ds-session-card\"><div class=\"ds-session-bar\"></div><div class=\"ds-session-body\"><span class=\"ds-session-name\">AmberReef</span><span class=\"ds-session-meta\">jst-m2swb.9</span></div></div>",
"css": ".ds-session-card { position: relative; display: flex; background: oklch(18% 0.015 250); color: oklch(85% 0.02 250); border-radius: 0.5rem; padding: 0.75rem 1rem 0.75rem 1.25rem; overflow: hidden; box-shadow: 0 0 20px color-mix(in oklch, oklch(75% 0.16 85) 15%, transparent); } .ds-session-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: oklch(75% 0.16 85); } .ds-session-body { display: flex; flex-direction: column; gap: 0.125rem; } .ds-session-name { font-size: 0.875rem; font-weight: 600; } .ds-session-meta { font-family: ui-monospace, monospace; font-size: 0.75rem; color: oklch(65% 0.02 250); }"
},
{
"name": "Input Field",
"kind": "input",
"refersTo": "input-field",
"description": "Text input on the sunken base layer with a subtle border and token-routed focus.",
"html": "<input class=\"ds-input\" type=\"text\" placeholder=\"Filter tasks\" aria-label=\"Filter tasks\" />",
"css": ".ds-input { background: oklch(14% 0.02 250); color: oklch(85% 0.02 250); border: 1px solid oklch(40% 0.03 250); border-radius: 0.25rem; padding: 0.5rem 0.75rem; font-size: 0.875rem; transition: border-color 0.15s, box-shadow 0.15s; } .ds-input::placeholder { color: oklch(60% 0.02 250); } .ds-input:focus-visible { outline: none; border-color: oklch(70% 0.18 240); box-shadow: 0 0 0 2px color-mix(in oklch, oklch(70% 0.18 240) 30%, transparent); }"
},
{
"name": "Page Header",
"kind": "nav",
"refersTo": null,
"description": "The canonical route header — a small uppercase/tracked instrument label with an optional count chip.",
"html": "<header class=\"ds-page-header\"><span class=\"ds-page-title\">Tasks</span><span class=\"ds-page-count\">42</span></header>",
"css": ".ds-page-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem; } .ds-page-title { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: oklch(85% 0.02 250); } .ds-page-count { font-family: ui-monospace, monospace; font-size: 0.6875rem; background: oklch(14% 0.02 250); color: oklch(70% 0.18 200); border-radius: 0.375rem; padding: 0.0625rem 0.375rem; }"
}
],
"narrative": {
"northStar": "The Cockpit",
"overview": "JAT is mission control for a swarm of AI coding agents — dense, legible, alive. Maximum signal per square inch, nothing hidden, every state readable at a glance. The register is product, not marketing: the design serves the operator's work. Industrial-dark, a single bespoke DaisyUI theme built on OKLCH tokens, neutrals tinted toward blue for cohesion, workhorse sans for UI and ui-monospace reserved for data. Motion is not decoration — every animation communicates a state change and respects prefers-reduced-motion. Reference feel: Bloomberg terminal, tmux, flight-sim HUD, synthesizer panel.",
"keyCharacteristics": [
"Cockpit density — signal fidelity over beginner-friendly whitespace; assume an expert operator.",
"State is the color — hue carries meaning; a state reads identically as bar, badge, or glow.",
"Industrial-dark, blue-tinted — neutrals lean hue 250; a single dark theme is the primary surface.",
"Purposeful motion — every animation signals a state change; none are ornamental.",
"Product register, locked — no marketing/brand surface; onboarding screens are still product."
],
"rules": [
{
"name": "The State-Is-The-Color Rule",
"body": "A reader must know an agent's state from hue alone — amber always means working, red always means needs-input, green always means done. Never hardcode a state hue in a component; import a helper from statusColors.ts and ask. Canonical seven: starting (blue 250), working (amber 85), needs-input (red 25), ready-for-review (cyan 200), completing (teal 170), completed (green 145), idle (slate 250).",
"section": "colors"
},
{
"name": "The One-Hue-Per-Semantic Rule",
"body": "Three parallel palettes (DaisyUI --color-*, --anim-* motion set, statusColors.ts) are kept in lockstep on hue so a given semantic never reads two colors. info/accent/review are all cyan 200; working is amber 85 at chroma 0.16 everywhere. Category/identity hues are a separate axis.",
"section": "colors"
},
{
"name": "The Mono-Is-For-Data Rule",
"body": "Monospace is reserved for machine values — IDs, timestamps, code, agent output. Do not reach for it to make prose look technical. If a human wrote it as a sentence, it's sans.",
"section": "typography"
},
{
"name": "The Tonal-Depth Rule",
"body": "Layer surfaces by darkening the neutral (three base steps), not by stacking shadows. A shadow that isn't a state glow is a smell — remove it or route it through an --anim-* token.",
"section": "elevation"
},
{
"name": "The Glow-Signals-State Rule",
"body": "Every glow tracks a canonical state hue via color-mix(in oklch, var(--anim-*) X%, transparent). Blue means entrance/primary, amber working, green completion, red exit. Motion and static state must never disagree.",
"section": "elevation"
}
],
"dos": [
"Do route every state color through statusColors.ts helpers (sessionStateVisual, sessionStateLabel, normalizeSignalState) — bar, badge, and glow read the same hue.",
"Do use DaisyUI semantic classes (bg-base-*, text-base-content, badge-*, btn-*) for structural chrome so it survives a theme switch.",
"Do use color-mix(in oklch, var(--anim-*) X%, transparent) for animation/glow/tint color — the sanctioned mechanism for theme-aware variable-transparency motion.",
"Do reserve ui-monospace for data, IDs, code, and agent output only.",
"Do convey depth by tonal layering (three base steps) and state glow, not ambient shadow.",
"Do reuse the shared ui/ state primitives and skeleton library for empty/loading/error — no bespoke clones.",
"Do keep motion GPU-friendly (transform/opacity only), reduced-motion-gated, and hue-matched to the state it signals."
],
"donts": [
"Don't hardcode a state hue in a component — a raw oklch(...) state color inline is a bug; ask statusColors.ts.",
"Don't reword a state label — 'At Review' is 'At Review' everywhere; add an icon, not new words.",
"Don't ship gradient text, decorative glassmorphism, the hero-metric template, undifferentiated card grids, or modal-as-first-thought.",
"Don't treat JAT as token-only/white-label — OKLCH literals in token definitions and --anim-* keyframes are correct, not slop. The JST 'no OKLCH literals' ban does not apply here.",
"Don't add a duplicate @keyframes spin/pulse/fadeIn/slide* to a component — reuse the centralized .animate-* utilities in app.css.",
"Don't use monospace for prose to signal 'technical.'",
"Don't add a shadow that isn't a state glow, or a marketing/brand surface anywhere — the register is product, locked."
]
}
}