10 KiB
10 KiB
Design System — Agent Orchestrator
Product Context
- What this is: A web-based dashboard for managing fleets of parallel AI coding agents. Each agent gets its own git worktree, branch, and PR. The dashboard is the operator's single pane of glass.
- Who it's for: Developers running 10-30+ AI coding agents in parallel. From solo devs to engineering teams.
- Space/industry: AI agent orchestration. Competitors: Conductor.build, T3 Code, OpenAI Codex app, Emdash. All are native Mac apps. Agent Orchestrator is the web-based alternative.
- Project type: Web app (Next.js 15, React 19, Tailwind v4). Kanban board with 6 attention-priority columns.
Aesthetic Direction
- Direction: Industrial Precision
- Decoration level: Intentional — subtle depth through surface hierarchy, ambient glow on active states, gradient surfaces in dark mode. No decorative blobs, no gratuitous gradients.
- Mood: Trading terminal meets control room. Dense, scannable, utilitarian, with just enough warmth that developers want to live in it for 10 hours. "I'm running an operation" not "I'm organizing tasks."
- Reference sites: Conductor.build, t3.codes, openai.com/codex, emdash.dev
Typography
- Display/Hero: Geist Sans, weight 680, letter-spacing -0.035em — same font as body but differentiated through weight and tracking. Tighter and heavier creates display hierarchy without a font swap. No cognitive gear-shifts on a scan-heavy dashboard.
- Body: Geist Sans, weight 400, letter-spacing -0.011em — purpose-built for dense interfaces at 13px. Better digit alignment than IBM Plex Sans, designed for exactly this density level.
- UI/Labels: Geist Sans, weight 600, letter-spacing 0.06em, uppercase, 10-11px — column headers, section labels, status indicators.
- Data/Tables: JetBrains Mono, weight 400, 11-13px, tabular-nums — agent IDs, branch names, timestamps, commit hashes, diff stats, PR numbers.
- Code: JetBrains Mono, weight 400 — terminal output, code blocks, inline code.
- Loading: Google Fonts via next/font/google. CSS variables:
--font-sans(Geist),--font-mono(JetBrains Mono). Display strategy: swap. - Scale:
- xs: 10px (timestamps, metadata)
- sm: 11px (secondary text, captions, labels)
- base: 13px (body text, card content)
- lg: 15px (section titles)
- xl: 17px (page titles)
- display: clamp(22px, 2.8vw, 32px) (hero headings)
Color
- Approach: Restrained with signal accents. Color is a priority channel, not decoration.
- Accent (cool): #5B7EF8 — interactive elements, links, focus rings. Used sparingly.
- Accent hover: #7a96ff
- Accent tint: rgba(91, 126, 248, 0.12)
- Attention (warm): #f1be64 — states requiring human input. Amber is universally "needs attention" without the panic of red.
Surfaces (Dark Mode)
| Token | Value | Usage |
|---|---|---|
| bg-base | #0a0d12 | Page background |
| bg-surface | #11161d | Card/column backgrounds |
| bg-elevated | #171d26 | Modals, popovers, hover states |
| bg-elevated-hover | #1c2430 | Hover on elevated surfaces |
| bg-subtle | rgba(177, 206, 255, 0.05) | Subtle tints, pill backgrounds |
Surfaces (Light Mode)
| Token | Value | Usage |
|---|---|---|
| bg-base | #f5f5f7 | Page background |
| bg-surface | #ffffff | Card/column backgrounds |
| bg-elevated | #ffffff | Modals, popovers |
| bg-elevated-hover | #f7f7f8 | Hover states |
| bg-subtle | #f0f0f2 | Subtle tints |
Text (Dark Mode)
| Token | Value | Usage |
|---|---|---|
| text-primary | #eef3ff | Headings, card titles, body. Blue-white, not pure white. |
| text-secondary | #a5afc4 | Descriptions, metadata. Readable in dense layouts. |
| text-tertiary | #6f7c94 | Timestamps, placeholders, disabled states. |
Text (Light Mode)
| Token | Value | Usage |
|---|---|---|
| text-primary | #1b1b1f | Headings, card titles, body. |
| text-secondary | #5e5e66 | Descriptions, metadata. |
| text-tertiary | #8e8e96 | Timestamps, placeholders. |
Borders (Dark Mode)
| Token | Value | Usage |
|---|---|---|
| border-subtle | rgba(160, 190, 255, 0.08) | Dividers, section separators |
| border-default | rgba(160, 190, 255, 0.14) | Card edges, input borders |
| border-strong | rgba(185, 214, 255, 0.24) | Hover states, focus indicators |
Status Colors
| Status | Dark Mode | Light Mode | Usage |
|---|---|---|---|
| Working | #22c55e | #16a34a | Agent actively coding. Green dot with pulse ring animation. |
| Ready | #5B7EF8 | #5e6ad2 | Queued, awaiting start or CI pending. |
| Respond | #f1be64 | #ca8a04 | Needs human input. Amber = attention without panic. |
| Review | #06b6d4 | #0891b2 | Code ready for review. Cyan = "look when ready." |
| Error | #ef4444 | #dc2626 | CI failed, agent crashed. Red = broken. |
| Done | #3a4252 | #d0d7de | Completed. Fades to secondary text. Done items recede. |
- Dark mode strategy: Blue-tinted graphite palette (not neutral gray). Reduce font weight by one step in dark mode (semibold becomes 500, bold becomes 600). Inset highlights on elevated surfaces:
inset 0 1px 0 rgba(255,255,255,0.04). Subtle radial gradients on body for ambient depth.
Spacing
- Base unit: 4px
- Density: Comfortable — dense enough for 30+ cards, spacious enough for 10-hour sessions
- Scale: 1(4) 2(8) 3(12) 4(16) 5(20) 6(24) 8(32) 10(40) 12(48) 16(64)
Layout
- Approach: Grid-disciplined
- Kanban grid: 6 equal-width columns on desktop, 3 on tablet, stacked on mobile
- Mobile column order: Respond > Review > Pending > Working (urgency-first)
- Max content width: 1280px for settings/detail pages
- Border radius:
- base: 2px (cards, buttons, inputs — consistent, sharp, intentional)
- sm: 4px (tooltips, small transient elements)
- md: 6px (dropdowns, floating interactive elements)
- lg: 8px (modals, large floating overlays)
- full: 9999px (pills, badges, count indicators)
- Card inset highlight:
inset 0 1px 0 rgba(255,255,255,0.04)in dark mode - Status accent: 2px solid left border on session cards, colored by status
Motion
- Approach: Intentional — every animation has a clear purpose and passes the frequency test
- Easing:
- enter/exit:
cubic-bezier(0.16, 1, 0.3, 1)(spring-like deceleration, feels responsive) - move/morph:
cubic-bezier(0.77, 0, 0.175, 1)(natural acceleration/deceleration) - hover/color:
ease-out - constant (spinner, marquee):
linear
- enter/exit:
- Duration:
- micro: 100-160ms (button press, hover state)
- short: 150-200ms (tooltips, popovers, card entrance)
- medium: 200-300ms (modals, drawers, card expand)
- long: 2s (status dot pulse, continuous indicators)
- Card entrance:
translateY(8px)+ opacity, 0.2s with 40ms stagger between siblings - Status pulse: GPU-composited pseudo-element on Working dots.
transform: scale(0.8→1.3)+opacity: 0.5→0, 2s ease-in-out infinite. Not box-shadow (triggers paint). - Button press:
transform: scale(0.97)on:active, 160ms ease-out - Rules:
- Never animate keyboard-initiated actions (command palette toggle, shortcuts)
- One animation per element, one purpose per animation
- CSS transitions for interruptible UI, keyframes for continuous indicators
- All animations must respect
prefers-reduced-motion: reduce - Use
contain: layout style painton session cards for performance with 30+ cards
Performance Guidelines
- Use
contain: layout style paintandcontent-visibility: autoon session cards - Animate only
transformandopacity(GPU-composited). Never animatepadding,margin,height,width,border, orbox-shadow. - Status dot pulse must use pseudo-element with
will-change: transform, opacity, not box-shadow rings - Backdrop blur on nav capped at 12px (diminishing returns above 12)
- Pause all non-essential animations when tab is hidden
Anti-Patterns (Never Do)
- Purple/violet gradients as default accent
- 3-column feature grid with icons in colored circles
- Centered everything with uniform spacing
- Uniform bubbly border-radius (8-12px) on all elements
- Gradient buttons as primary CTA pattern
transition: all— always specify exact propertiesscale(0)entry animations — start fromscale(0.95)withopacity: 0ease-inon UI elements — useease-outfor responsiveness- Animations over 300ms on frequently-triggered UI elements
Decisions Log
| Date | Decision | Rationale |
|---|---|---|
| 2026-03-28 | Initial design system created | Created by /design-consultation with competitive research (Conductor.build, T3 Code, OpenAI Codex, Emdash) + 4 design voices (primary, Codex CLI, Claude subagent, Emil Kowalski design eng) |
| 2026-03-28 | Geist Sans + JetBrains Mono (2 fonts only) | Emil review: 4 fonts creates cognitive gear-shifts on scan-heavy dashboards. Two fonts, hierarchy through weight + tracking. |
| 2026-03-28 | Accent #5B7EF8 instead of Tailwind blue-500 | Emil review: stock Tailwind blue reads "default" and undermines Industrial Precision identity. Existing token-reference blue is more sophisticated. |
| 2026-03-28 | Dual accent (cool blue + warm amber) | All 3 outside voices independently proposed amber for attention states. Two accents with clear semantic roles beat a single color. |
| 2026-03-28 | Fixed-width kanban columns (not variable) | Emil review: variable width breaks spatial memory. Encode urgency in column header dots instead. |
| 2026-03-28 | 2px base border-radius | Full 0px risks looking unstyled. 2px reads as intentionally sharp while feeling designed. Consistent across cards, buttons, inputs. Distinct from competitors' 8-12px rounded corners. |
| 2026-03-28 | Keep dot pulse, remove border heartbeat | Emil review: 4s border animation on 15+ cards is "decorative anxiety" with high perf cost. Existing 8px dot pulse is correct pattern — small surface, GPU-composited. |
| 2026-03-28 | Simplify ready-to-merge to single animation | Emil review: 3 concurrent keyframe animations on merge-ready cards is over-engineered. One animation per element, one purpose. Keep dot pulse only. |