agent-orchestrator/DESIGN.md

158 lines
10 KiB
Markdown

# 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`
- **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 paint` on session cards for performance with 30+ cards
## Performance Guidelines
- Use `contain: layout style paint` and `content-visibility: auto` on session cards
- Animate only `transform` and `opacity` (GPU-composited). Never animate `padding`, `margin`, `height`, `width`, `border`, or `box-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 properties
- `scale(0)` entry animations — start from `scale(0.95)` with `opacity: 0`
- `ease-in` on UI elements — use `ease-out` for 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. |