diff --git a/.gitignore b/.gitignore index 191f790..277696e 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ tests/reference_agents/presentation_agent/output/ # Python build artifacts client/build/ +# Console SPA staged into the server wheel by `make console` (built output; +# the canonical source lives in frontend/, see server/pyproject.toml). +server/harmonograf_server/_console/ # Demo output tarballs waffle.tar.gz diff --git a/Makefile b/Makefile index e04850a..258ec5f 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CLIENT_PB := $(ROOT)/client/harmonograf_client/pb FRONTEND_PB := $(ROOT)/frontend/src/pb .PHONY: help proto proto-python proto-ts \ - server-install client-install frontend-install install \ + server-install client-install frontend-install install console \ server-run frontend-dev demo demo-presentation demo-presentation-orchestrated demo-standalone .demo-agents-stage \ test server-test client-test frontend-test e2e \ lint format clean stats @@ -24,6 +24,7 @@ help: @echo " proto-python Regenerate Python stubs under server/ and client/" @echo " proto-ts Regenerate TypeScript stubs under frontend/" @echo " install Install all components" + @echo " console Build the frontend and stage it into the server wheel" @echo " server-run Run the server in dev mode" @echo " frontend-dev Run the Vite dev server" @echo " demo Boot server + frontend + adk web (shows both presentation_agent variants)" @@ -107,6 +108,26 @@ client-install: frontend-install: @cd $(ROOT)/frontend && pnpm install --frozen-lockfile +# --------------------------------------------------------------------------- +# Console bundle (ship the built SPA inside the server wheel) +# --------------------------------------------------------------------------- + +# Where the wheel expects the bundled console (see server/pyproject.toml +# force-include + static_site.py importlib.resources lookup). +CONSOLE_DIR := $(ROOT)/server/harmonograf_server/_console + +# Build the frontend and stage it into the server package so the wheel ships +# the UI. Run this before packaging the server (`uv build server`, etc.). +# The server's static_site.py also auto-locates ../frontend/dist in a repo +# checkout, so `make console` is only required for producing a distributable +# wheel — local `make server-run` works without it. +console: + @cd $(ROOT)/frontend && pnpm install --frozen-lockfile && pnpm build + @rm -rf $(CONSOLE_DIR) + @mkdir -p $(CONSOLE_DIR) + @cp -R $(ROOT)/frontend/dist/. $(CONSOLE_DIR)/ + @echo "Console staged into $(CONSOLE_DIR) (shipped in the server wheel)." + # --------------------------------------------------------------------------- # Run # --------------------------------------------------------------------------- @@ -322,4 +343,5 @@ clean: @find $(ROOT) -type d -name __pycache__ -prune -exec rm -rf {} + 2>/dev/null || true @find $(ROOT) -type d -name .pytest_cache -prune -exec rm -rf {} + 2>/dev/null || true @rm -rf $(ROOT)/frontend/dist + @rm -rf $(CONSOLE_DIR) @echo "Clean done. Run 'make proto' to regenerate stubs." diff --git a/docs/design/zicato-ui-study/BRIEF.md b/docs/design/zicato-ui-study/BRIEF.md new file mode 100644 index 0000000..6adea78 --- /dev/null +++ b/docs/design/zicato-ui-study/BRIEF.md @@ -0,0 +1,201 @@ +# BRIEF — harmonograf UI study in the zicato design language + +This is the **single source of truth** for the team building this study. Read it +fully, then read the source files it points to. Where this brief and a source +file disagree about a token/hex/class, **the source file wins** — re-grep. + +## 0. Goal & deliverable + +Produce a **UI study**: a self-contained set of HTML pages that show +harmonograf's console redrawn in **zicato's design language**, theme-switchable +across all 16 themes, with before/after comparisons per surface. This is a +*design artifact*, not production code — standalone HTML/CSS/JS, no build step, +opens from `file://`. + +The native form of a study in this ecosystem is zicato's +`~/git/zicato/docs/design/tournament-viz-study/` — **clone its conventions +exactly** (self-contained pages, ported token block, `_embed.js` with +`?only/?bare/?theme`, a `compose.html`). Match its quality bar. + +**Output dir:** `~/git/harmonograf/docs/design/zicato-ui-study/` (this dir). + +## 1. The two design languages + +**zicato** — canonical docs (read both, fully): +- `~/git/zicato/docs/design/DESIGN-LANGUAGE.md` — the *language* (tokens, type, + line-art figure grammar §5, motion/digest-gating §7, a11y §9, and §10 a worked + "build a harmonograf execution timeline" example — **use it**). +- `~/git/zicato/docs/design/CONSOLE-DESIGN-LANGUAGE.md` — the dashboard's + *application* of it (figure catalogue §4.1, mark conventions §4.2). +- Authoritative token sheet: `~/git/zicato/src/zicato/dashboard/static/css/variants/T/console4.css`. +- A clonable study page (port its `--v2-*`→local token block + structure): + `~/git/zicato/docs/design/tournament-viz-study/single-matchup.html`, and the + shared `_embed.js` + `compose.html` in that dir. + +Ethos in one line: **Tufte data-ink line-art, monospace-forward, a calm ground +with signal earned by direction, theme-adaptive by pure CSS swap, never +flashing.** + +**harmonograf today** — what we are restyling (read the chrome + Gantt): +- `~/git/harmonograf/frontend/src/index.css` — ALL chrome classes (`.hg-*`): + shell grid, appbar, rail, strip, transport, drawer, picker, help, panels. +- `~/git/harmonograf/frontend/src/theme/themes.ts` — MD3 tokens + the span-kind + and goldfive-category hues we must re-home. +- `~/git/harmonograf/frontend/src/gantt/colors.ts` — kind×status → fill/stroke/ + treatment (the 2-axis encoding; preserve it, §3). +- `~/git/harmonograf/frontend/src/gantt/renderer.ts` — 3-layer canvas Gantt. +- Components: `frontend/src/components/{Gantt,OrchestrationTimeline,TaskStages,LiveActivity,Interventions,SessionPicker,TransportBar,shell}`. + +It is **Material Design 3**: `--md-sys-color-*`, system-ui sans, elevation +containers, rounded radii, blue primary, several `animation:…infinite` pulses. + +## 2. THE CENTRAL DECISION — full categorical palette from Gogh ANSI + +zicato's "one green accent, everything else neutral" is built for a binary +promote/reject surface. harmonograf is a **categorical instrument**: many +agents, 9 span kinds, goldfive call categories. We are **keeping the full +categorical palette** — but sourcing every categorical hue from the active +theme's **terminal ANSI palette** (the Gogh scheme each zicato theme derives +from). This ties the categorical encoding to the theme system instead of +fighting it: switch theme → the whole palette re-skins, ANSI and all. + +Preserve harmonograf's elegant **2-axis encoding**: +- **KIND = hue** → mapped to a theme ANSI color (full categorical, below). +- **STATUS = treatment** → mapped to zicato semantic roles + treatments + (running → the *one* `--accent` + breathing; FAILED → `--bad` + error glyph; + PENDING/CANCELLED → reduced opacity / hatch; planned → dashed). Status is the + only place good/bad/accent appear, so zicato's "earned by direction" rule + holds: a span is never red for its identity, only when it failed. + +### 2.1 Span KIND → ANSI slot (proposed; foundation worker finalizes) + +ANSI slots: `color_01..08` = black,red,green,yellow,blue,magenta,cyan,white; +`color_09..16` = bright variants. + +| harmonograf kind | ANSI slot | rationale | +|---|---|---| +| `INVOCATION` | `color_09` bright-black/grey | structural container, recedes | +| `LLM_CALL` | `color_05` blue | | +| `TOOL_CALL` | `color_07` cyan | | +| `USER_MESSAGE` | `color_03` green | | +| `AGENT_MESSAGE` | `color_11` bright-green | distinct from user | +| `TRANSFER` | `color_04` yellow | | +| `WAIT_FOR_HUMAN` | `color_06` magenta | attention, but NOT red (red=failed) | +| `PLANNED` | `color_09` grey + dashed | ghost/planned | +| `CUSTOM` | `color_08` white/neutral | | + +goldfive lane categories: judge severity → roles (on-task `--good`, warning +`--caution`, critical `--bad`, neutral `--flat`); `refine` → magenta `color_06`; +`plan` → cyan `color_07`; `reflective` → grey `color_09`. + +### 2.2 Agent identity ramp + +Agents (lanes/lifelines) get an **ordinal ramp** derived from tokens, not 8 +saturated primaries — a low-sat sequence so lanes are distinguishable without +competing with kind hues or the accent. Build with `color-mix()` off ANSI +slots or an OKLCH spin; foundation worker decides and documents it. + +## 3. Token / type mapping (MD3 → zicato roles) + +| harmonograf (MD3) | zicato role / token | +|---|---| +| `surface` / `surface-container*` elevation ladder | `--paper` ground + ONE `--panel` lift; elevation→hairline `--rule`, not shadow | +| `primary` (#a8c8ff) | `--accent` — reserved for now/selected/live ONLY | +| `error` / `error-container` | `--bad` / `--bad-soft` | +| `tertiary` / transfer / wait hues | `--caution` | +| 9 `--hg-kind-*` | per-theme ANSI categorical (§2.1) | +| `outline` / `outline-variant` | `--rule` / `--rule-soft` | +| `on-surface` / `-variant` | `--ink` / `--ink-soft` / `--ink-faint` | +| system-ui body, 14px | `--mono`/prose-mono; data uses code-mono + `tabular-nums` | +| radii 4/8/12, pill chips | panels 4px, bars `rx:3`, `.dn-pill` mono outline-first | + +Use the zicato `--v2-*` role values from `console4.css` / +`single-matchup.html` (paper/panel/ink/ink-soft/ink-faint/rule/rule-soft/ +good/good-soft/bad/bad-soft/caution/accent/flat/cell-empty) for all 16 themes, +ported into local tokens exactly as the study pages do. + +## 4. Surfaces to redesign (each gets before/after + rationale + legend) + +1. **shell.html** — chrome: AppBar→zicato **topbar** (inline-SVG `zıcato` + wordmark w/ dotless-ı + green dot, breadcrumbs, swatch theme picker, typeface + switch, scale pill, status/RUN pill); NavRail; CurrentTaskStrip; TransportBar + (transport controls, LIVE pill, clock); Drawer/inspector (tabs, attrs, code). +2. **gantt.html** — THE HERO. The execution Gantt in line-art: hairline + gridlines (`--rule-soft`, 0.6w), `rx:3` bars at reduced fill-opacity lifting + to 1 on hover, full categorical kind hues (§2), status treatments, the accent + for the "now" cursor / selected span, agent gutter + lifelines, context band. + Present BOTH options: (a) keep canvas, restyle via tokens; (b) fit-to-width + SVG line-art. Use realistic mock multi-agent trace data. +3. **figures.html** — OrchestrationTimeline, TaskStages, LiveActivity (table as + `.dn-board-table` idiom), Interventions, SessionPicker (⌘K). Pills mono + outline-first; hovercards; tabular-nums. + +## 5. File layout + +``` +zicato-ui-study/ + BRIEF.md # this file + STYLE-GUIDE.md # foundation worker writes: final span→ANSI map, token map, do/dont + _refs/gogh-palettes.json # palette worker writes: 16 themes × full ANSI + _tokens.css # 16 themes: --v2 roles (from console4) + ANSI categorical (from json) + _study.css # shared page chrome + the .hg-* zicato-language component CSS + _embed.js # ported from zicato tournament-viz-study (?only/?bare/?theme) + index.html # overview + the categorical-palette thesis + links + theme picker + shell.html + gantt.html + figures.html + compose.html # side-by-side, theme-synced, iframes of the above +``` + +Each page: ports/links the token block, ships the swatch theme picker +(default `monokai`), sets ``, includes `_embed.js`. + +## 6. Conventions to honor (from DESIGN-LANGUAGE.md) + +- **Token-only color.** No hardcoded hex in any mark/component — read `--*` + tokens so a theme swap is a pure re-skin. (The per-theme blocks in `_tokens.css` + are the only place hex appears.) +- **Fit-to-width**, no pan/zoom; figures `width:100%` + `viewBox` + `role="img"`. +- **Motion discipline** (§7): the only keyframe is a status/now pulse, gated + behind `@media (prefers-reduced-motion: reduce)`. No `animation:…infinite` on + structure. Note digest-gating in the rationale (harmonograf already half-does + it: "React never drives the render loop"). +- **Focus rings**: `2px solid var(--accent)` `:focus-visible`, small offset. +- **Mono-forward** type; `tabular-nums` on all numerics/durations. +- **Verify in BOTH** a light theme (`paper`) and a dark one (`monokai`). + +## 7. Gogh palette sourcing (palette worker) + +Source: `https://raw.githubusercontent.com/Gogh-Co/Gogh/master/themes/.yml`. +Format (verified): `color_01..16` + `background` + `foreground`. color_01-08 +normal black/red/green/yellow/blue/magenta/cyan/white; 09-16 bright. + +Fetch these 16 (confirmed filenames in **bold**; others try canonical casing and +verify): **Belafonte Day**, **Belafonte Night**, **Dracula**, **Espresso**, +**Ubuntu**; Monokai, Solarized Dark, Solarized Light, Google Dark, Google Light, +Lunaria Light, Lunaria Eclipse, Paper, Zenburn, Selenized Black, Relaxed. + +**Self-check:** each Gogh `background` MUST equal zicato's `--v2-paper` for that +theme (e.g. Dracula bg `#282A36` ✓, Belafonte Night `#20111B` ✓, Espresso +`#323232`, Ubuntu `#300A24`, Monokai `#1e1f1c`). zicato `--v2-paper` per theme is +in `DESIGN-LANGUAGE.md §2.2`. If a fetched bg doesn't match, you have the wrong +file — find the right one or note the discrepancy in the json. Emit +`_refs/gogh-palettes.json`: `{ "": { "ansi": {"black":..., "red":..., +... "brightWhite":...}, "bg":..., "fg":... }, ... }` keyed by zicato theme id. + +## 8. Team structure (an agent team with an explicit LEAD) + +- **Lead** owns the whole deliverable, coherence, and final QA. The Lead: + reads this brief + sources; builds the foundation (`_tokens.css`, + `_study.css`, `_embed.js`, `STYLE-GUIDE.md`) AFTER the palette worker returns + (or builds it in parallel and wires the json last); spawns the three surface + workers in parallel with crisp specs + the foundation contract; reviews each + returned page for token-only color, fit-to-width, theme correctness, and + cross-page visual coherence; assembles `index.html` + `compose.html`; runs the + §6 validation in both `monokai` and `paper`; returns a summary of what was + built, key decisions, and any open questions. +- **Palette worker** → §7, returns `_refs/gogh-palettes.json`. +- **Shell / Gantt / Figures workers** → §4, one page each, against the foundation. + +Keep every page self-contained and theme-switchable. The bar is zicato's own +study pages — match it. diff --git a/docs/design/zicato-ui-study/README.md b/docs/design/zicato-ui-study/README.md new file mode 100644 index 0000000..2ec5b76 --- /dev/null +++ b/docs/design/zicato-ui-study/README.md @@ -0,0 +1,59 @@ +# harmonograf UI study — in the zicato design language + +A self-contained, theme-switchable study showing harmonograf's MD3 console +redrawn in **zicato's design language**, keeping harmonograf's full categorical +palette but sourcing every categorical hue from each theme's **Gogh terminal +ANSI palette**. Standalone HTML/CSS/vanilla-JS — no build step. + +## Open it + +Everything opens straight from `file://` — no build step, no server. Start at +**`index.html`** (the thesis, surface links, 16-theme wall), or jump to +**`compose.html`** for the full interactive console. + +## Files + +``` +index.html overview + the categorical-palette thesis + links + theme picker +shell.html chrome before/after: topbar · rail · strip · transport · drawer +gantt.html THE HERO — the execution timeline (SVG line-art + canvas options) +sequence.html how the agents talk: the vertical sequence diagram (recommended) + + the directional transfer chord (topology) + the score (alt) +figures.html OrchestrationTimeline · TaskStages · LiveActivity · Interventions · ⌘K +grammar.html fourteen new figures: seismograph · ladder · sankey · strata · + plan DAG · delegation score · chord · fingerprint · … +brand.html harmonograf's own mark — the Lissajous α, wordmark, lockups +compose.html THE COMPOSED CONSOLE — interactive. The gantt as its own hero + view + one coalesced "instruments" view leading with the plan: + the plan REEL sits above the plan DAG and DRIVES it — click a + revision and the DAG redraws that version's task set (added in + accent, dropped-since-prior ghosted/dashed). Then sequence · + projectable topology chord · and ONE coordinated time-track + stack: the drift seismograph with the judge heartbeat folded in + (one time axis) over the time-aligned intervention ladder. + Sessions ONLY via the ⌘K fingerprint picker (no sidebar). + Clickable spans → inspector. ?ver= deep-links a reel revision. + (The earlier A/B/C whole-UI proposals + fleet sidebar live in + git history.) + +_tokens.css 16 themes: zicato --v2 roles + --ansi-* + the --hg-* categorical +_study.css shared page chrome + the .hg-* zicato-language component CSS +_embed.js ?only / ?bare / ?theme (ported from zicato tournament-viz-study) +_refs/gogh-palettes.json 16 themes × full ANSI, self-checked vs --v2-paper + +STYLE-GUIDE.md the foundation contract: span-KIND→ANSI map, agent ramp, + MD3→zicato token map, the accent-collision rule, do/don'ts, + and the open questions +BRIEF.md the original brief (single source of truth) +``` + +## The one idea + +zicato spends **one** green accent on a calm ground. harmonograf is a +**categorical** instrument, so this study keeps the full palette but sources +every hue from the active theme's **terminal ANSI** set. The 2-axis encoding +holds: **KIND = hue** (an ANSI slot), **STATUS = treatment** (running → the one +`--accent` + breathe; failed → `--bad` + `✕`; pending → faint; cancelled → hatch; +planned → dashed). good / bad / accent appear **only** for status — a span is +never red for its identity, only when it failed. Switch theme → the whole thing +re-skins, ANSI and all, with no re-render. See `STYLE-GUIDE.md`. diff --git a/docs/design/zicato-ui-study/STYLE-GUIDE.md b/docs/design/zicato-ui-study/STYLE-GUIDE.md new file mode 100644 index 0000000..41d072a --- /dev/null +++ b/docs/design/zicato-ui-study/STYLE-GUIDE.md @@ -0,0 +1,226 @@ +# STYLE-GUIDE — harmonograf in the zicato design language + +The foundation contract. Surface pages (`shell.html`, `gantt.html`, +`figures.html`) build against this. It finalizes the proposals in +[BRIEF.md](BRIEF.md): the span-KIND→ANSI map, the agent ramp, the MD3→zicato +token map, and the do/don'ts. Where this and a source file disagree about a +token, **the source wins** — re-grep. + +Files in this study: + +``` +_refs/gogh-palettes.json 16 themes × full ANSI, self-checked vs --v2-paper +_tokens.css 16 theme blocks: --v2 roles + --ansi-* + --hg-* categorical +_study.css shared page chrome + the .hg-* zicato-language components +_embed.js ?only / ?bare / ?theme (ported from zicato study) +STYLE-GUIDE.md this file +index.html shell.html gantt.html figures.html compose.html +``` + +--- + +## 1. The thesis (why this study exists) + +zicato is a **binary** promote/reject surface: one green accent, everything else +neutral. harmonograf is a **categorical instrument**: many agents, 9 span kinds, +goldfive call categories. We keep harmonograf's full categorical palette — but +**source every categorical hue from the active theme's terminal ANSI palette** +(the Gogh scheme each zicato theme derives from). Switch theme → the whole +categorical palette re-skins, ANSI and all. This ties the encoding to the theme +system instead of fighting it. + +The elegant **2-axis encoding** is preserved: + +- **KIND = hue** → a theme ANSI slot (`--hg-kind-*`, full categorical). +- **STATUS = treatment** → zicato semantic roles + treatments. Status is the + **only** place good / bad / accent appear, so zicato's "earned by direction" + rule holds: a span is never red for its identity, only when it failed. + +--- + +## 2. Span KIND → ANSI slot (FINAL) + +ANSI slots map onto `--ansi-*` tokens in `_tokens.css`; the kind tokens alias them. + +| harmonograf kind | token | ANSI slot | rationale | +|---|---|---|---| +| `INVOCATION` | `--hg-kind-invocation` | bright-black (grey) | structural container, recedes (rendered at low opacity) | +| `LLM_CALL` | `--hg-kind-llm-call` | blue | | +| `TOOL_CALL` | `--hg-kind-tool-call` | cyan | | +| `USER_MESSAGE` | `--hg-kind-user-message` | green | | +| `AGENT_MESSAGE` | `--hg-kind-agent-message` | bright-green | distinct from user | +| `TRANSFER` | `--hg-kind-transfer` | yellow | | +| `WAIT_FOR_HUMAN` | `--hg-kind-wait-for-human` | magenta | attention, but **NOT red** (red = failed) | +| `PLANNED` | `--hg-kind-planned` | bright-black (grey) | ghost / planned + **dashed** treatment | +| `CUSTOM` | `--hg-kind-custom` | white / neutral | | + +**goldfive** lane categories (`--hg-gf-*`): judge severity → roles +(`on-task`→`--good`, `warning`→`--caution`, `critical`→`--bad`, +`neutral`→`--flat`); `refine`→magenta; `plan`→cyan; `reflective`→bright-black. + +### 2.1 STATUS treatments (the second axis) + +Applied **over** the kind hue. The renderer/marks read these; never bake a status +color into a kind. + +| status | treatment | +|---|---| +| `COMPLETED` | kind hue at fill-opacity `0.55` idle → `1.0` on hover | +| `RUNNING` | **`--accent`** stroke (w 2) + the breathing pulse (`hg-breathe`, reduced-motion → static) | +| `FAILED` | fill `--bad` + the `✕` error glyph (1:1 overlay) | +| `PENDING` | kind hue at opacity `0.35`, no stroke | +| `CANCELLED` | opacity `0.30` + diagonal hatch | +| `AWAITING_HUMAN` | fill `--bad-soft`, stroke `--bad`, the `⏱`/`◷` attention glyph; pulses | +| `PLANNED` (kind) | `--rule-soft` fill + `--ink-faint` **dashed** outline | +| `replaced` | opacity `0.30` (stacks with status) | + +--- + +## 3. The accent-collision rule (the categorical-vs-one-accent tension) + +The hard part. Because zicato derived each theme's `--v2-accent` **from** its +ANSI cyan/blue, in several themes a kind hue's base hex **equals** the accent: + +| collision | themes | +|---|---| +| `LLM_CALL` (blue) == accent | monokai, solarized-light, belafonte-day, paper, espresso | +| `TOOL_CALL` (cyan) == accent | solarized-dark, google-dark, lunaria-light, relaxed | + +Resolution — **distinguish the accent by TREATMENT, never rely on hue:** + +1. **Kind hues are always quieted fills** (idle fill-opacity `0.5–0.6`, lifting to + `1` only on hover). The accent appears only as a **full-strength stroke** (the + now-cursor, the selected-span spine, a focus ring) + the breathing pulse — a + treatment **no kind fill ever takes**. So even when `LLM_CALL` and `--accent` + share a base hex, the live/selected mark is unmistakable: it is the stroked, + breathing one. +2. **`--accent` is reserved** for now / selected / live / interactive focus — + full stop. It is never spent on a kind, a legend swatch's identity, or chrome + decoration. +3. Legends label kind by **name + a quieted swatch**, so a blue==accent theme + still reads "LLM_CALL" unambiguously from the label, not the chip alone. + +This is the honest version of "keep the categorical palette": the categorical +layer and the emphasis layer are separated by **role and treatment**, not by +holding 9 hues that are all guaranteed distinct from the accent in all 16 themes +(impossible given the derivation). Documented as an open question for Sunil (§8). + +--- + +## 4. Agent identity ramp (FINAL) + +harmonograf today hashes `agent_id` onto **Tableau-10** (8 saturated primaries) — +exactly the "8 saturated primaries" the brief says to replace. Instead, lanes get +an **ordinal ramp** derived from tokens: + +``` +--hg-agent-1..8 : color-mix(in oklab, 62%, var(--v2-ink-faint)) +``` + +slots, in order: `blue, cyan, green, yellow, magenta, bright-blue, bright-green, +bright-yellow`. The 62% mix toward `--ink-faint` **desaturates** every lane so +the gutter/lifelines stay distinguishable without competing with the (full-sat) +kind hues on the bars or with the accent. Two synthetic actors are fixed: + +- `--hg-agent-user` — caution-mixed (warm neutral, reads as "person"). +- `--hg-agent-goldfive` — accent-mixed (cool neutral, reads as "orchestrator"). + +Lifelines/gutter labels use the agent color at low strength; the bars on a lane +take the **kind** hue, not the agent hue (agent identity is the lane, kind is the +bar). All theme-adaptive: a swap re-mixes the ramp. + +--- + +## 5. MD3 → zicato token map (FINAL) + +| harmonograf (MD3) | zicato role / token | +|---|---| +| `surface` / `surface-container*` elevation ladder | `--paper` ground + ONE `--panel` lift; elevation → hairline `--rule`, **not** shadow | +| `primary` (#a8c8ff) | `--accent` — reserved (now / selected / live / focus) | +| `primary-container` | `color-mix(--accent 14%, --panel)` for selected rows | +| `error` / `error-container` | `--bad` / `--bad-soft` | +| `tertiary` / transfer / wait hues | `--caution` (chrome) ; kind hues use ANSI (§2) | +| `secondary-container` (rail selected) | `color-mix(--accent 14%, --panel)` + accent text | +| 9 `--hg-kind-*` | per-theme ANSI categorical (§2) | +| `outline` / `outline-variant` | `--rule` / `--rule-soft` | +| `on-surface` / `-variant` | `--ink` / `--ink-soft` / `--ink-faint` | +| system-ui body, 14px | `--mono` everywhere; data uses mono + `tabular-nums` | +| radii 4 / 8 / 12, pill chips | panels **4px**, bars `rx:3`, `.dn-pill` mono outline-first 10px | + +### 5.1 Type + +All-mono, terminal-forward (the study's default face stack is +`ui-monospace, "JetBrains Mono", …`). `tabular-nums` on every numeric / duration / +clock. Headings = same mono, slightly heavier; section eyebrows uppercase with +`0.12em` tracking. No system-ui sans anywhere. + +### 5.2 The dotless-ı wordmark + +The topbar carries the inline-SVG `zıcato` wordmark (dotless ı U+0131, the green +accent circle **is** the i's dot) + the spiral brand mark, both `currentColor` +strokes with `var(--zicato-accent)` dots — ported from the zicato compose.html +(`MARK_SPIRAL` / the wordmark builder). A `.dt-brand-variant` tag reads +`console`. + +--- + +## 6. Line-art conventions (from DESIGN-LANGUAGE.md §5) + +- Hairline gridlines: `stroke:var(--rule-soft); stroke-width:0.6; vector-effect: + non-scaling-stroke`. No gridframe, no 3-D, no chartjunk. +- Bars: `rx:3`, fill the **kind** token at reduced `fill-opacity` (`0.55`), + lifting to `1` on hover. `stroke:none` except status treatments. +- The one emphasis: `--accent`, stroke-width 2–2.4 (now-cursor / selected spine). +- Reference / planned: `--ink-faint` dashed (`stroke-dasharray:3 3` / `4 3`). +- Every figure **fit-to-width**: `width:100%` + `viewBox` + `role="img"`; a glyph + that must stay round goes in a separate 1:1 overlay. No pan/zoom, no fixed px + width that overflows. +- Hovercards: a singleton card on `--panel` / `--rule`, mono, `pointer-events: + none`, outside any gated render. + +## 7. Motion & a11y + +- The **only** keyframe is a now/running pulse (`hg-breathe`, `hg-now-pulse`), + gated behind `@media (prefers-reduced-motion: reduce)` → static. **No** + `animation:…infinite` on structure (kills harmonograf's MD3 `*-pulse` loops). +- Note in rationale: harmonograf already half-does digest-gating ("React never + drives the render loop" — `renderer.ts`); the study makes that explicit. +- Focus rings: `2px solid var(--accent)`, small offset, `:focus-visible`. +- Verify every page in BOTH `paper` (light) and `monokai` (dark). + +## 8. Do / Don't (study-specific) + +**Do** — read color from `--*` tokens only; earn good/bad by direction; reserve +`--accent`; quiet kind fills, full-strength only on hover/selection; mono + tabular +everywhere; one `--panel` lift, hairlines not shadows; gate motion. + +**Don't** — hardcode hex in a mark (the per-theme `_tokens.css` blocks are the +only hex); spend `--accent` on a kind or chrome decoration; color a span red for +its identity (only FAILED is red); use system-ui sans; run structure on +`animation:…infinite`; force horizontal scroll; pin a figure to a fixed px width. + +### 8.1 Open questions for Sunil + +1. **Accent collisions (§3).** Resolved by treatment, not hue. If you'd rather the + kind hues be guaranteed-distinct from the accent in every theme, we'd nudge + `LLM_CALL`/`TOOL_CALL` off the accent slot per-theme (a per-theme override + table) — more faithful-to-ANSI vs. more separable. Current choice favors ANSI + fidelity + treatment-based distinction. +2. **Monokai ANSI source.** zicato's `monokai` is "original" lineage, not Gogh; + its closest Gogh file (Monokai Soda, bg `#1A1A1A`) doesn't match `--v2-paper` + `#1e1f1c` and uses different greens. We sourced monokai's ANSI from the + **classic** Monokai terminal palette (matches zicato's good/bad/accent roles). + Flagged in `gogh-palettes.json`. +3. **Zenburn green.** Zenburn's ANSI "green" slot is actually a yellow; we used + its sage (`#7f9f7f`) so USER_MESSAGE stays green-ish. Muted by design. +4. **belafonte-night hue-collapse.** On this ONE theme the ANSI kind slots + collapse into near-identical warm greys (blue `#426A79` / cyan `#989A9C` / + green `#858162` / white `#968C83` / bright-black `#5E5252`), so the categorical + *hues* blur there — kinds stay legible by **treatment + named legend/hovercard** + (FAILED red, RUNNING accent-stroke, TRANSFER yellow, dashed/hatch, gutter + ticks), not by hue. Same "more separable vs more ANSI-faithful" tradeoff as + §8.1.1: a remedy would spin belafonte-night's collapsed kinds apart in + `_tokens.css`. Left ANSI-faithful by default; flagged by the Gantt + Figures + review pass. (The collision-theme recheck — espresso / solarized-light / + google-dark / dracula — otherwise PASSED, validating the treatment-based §3 + resolution.) diff --git a/docs/design/zicato-ui-study/_embed.js b/docs/design/zicato-ui-study/_embed.js new file mode 100644 index 0000000..588897c --- /dev/null +++ b/docs/design/zicato-ui-study/_embed.js @@ -0,0 +1,100 @@ +/* =================================================================== + EMBED MODE — shared across the harmonograf zicato-UI-study pages. + Ported from zicato tournament-viz-study/_embed.js. Honors URL params + so a page can be composed into compose.html via an