From c807a726235a7abbcd60af92d24bd8fec5afa6ff Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sun, 31 May 2026 20:57:32 -0400 Subject: [PATCH] Spec M4: cockpit-style web UI design pass State-driven accent HUD, stacked bands, CSS/JS split out of the inline HTML, polished presentational review recap. No behavior changes. Co-Authored-By: Claude Opus 4.8 --- .../specs/2026-05-31-m4-look-good-design.md | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-31-m4-look-good-design.md diff --git a/docs/superpowers/specs/2026-05-31-m4-look-good-design.md b/docs/superpowers/specs/2026-05-31-m4-look-good-design.md new file mode 100644 index 0000000..dc1d928 --- /dev/null +++ b/docs/superpowers/specs/2026-05-31-m4-look-good-design.md @@ -0,0 +1,134 @@ +# M4 — "Look good" Design + +**Goal:** A real design pass on the web UI: a cockpit-style, state-aware HUD that +reads at a glance, with CSS/JS split out of the inline HTML for maintainability, +and a polished review recap. No behavior changes. + +**Status:** Design approved 2026-05-31. Supersedes the utilitarian inline UI +shipped through M3.5. + +--- + +## 1. Direction & Visual System + +The UI is an **instrument panel you glance at** — a cockpit, not a document. +Dark, near-black cool-neutral base. State is carried by a **single state-driven +accent**: a CSS custom property `--accent` switched by a `data-state` attribute +on the `
` element. The accent colors the status band's top border and the +state pill, so the frame itself communicates where you are without reading text. + +### State → accent mapping + +| State | `data-state` | Accent | +|--------------------|--------------|--------------------| +| locked | `locked` | dim gray | +| planning | `planning` | blue | +| active · on-task | `active` | calm green / cyan | +| active · nudge | `nudge` | amber | +| active · drifting | `drift` | red | +| review | `review` | violet-neutral | + +`data-state` is derived in the client render from `runtime_state` plus, when +active, the drift sub-status (`drifting` → `drift`; a present `nudge` → `nudge`; +otherwise `active`). This mirrors the precedence already used by the status-file +renderer (drift outranks nudge). + +### Design tokens (CSS custom properties) + +- Surfaces / text: `--bg`, `--panel`, `--line`, `--ink`, `--ink-dim` +- State accent: `--accent` (the only variable that changes with `data-state`) +- Fixed semantic colors: `--ok`, `--warn`, `--danger` + +### Typography + +- Timer: heavy weight, `font-variant-numeric: tabular-nums`. +- Evidence times: `ui-monospace` so the bucket columns align. +- Band headers / pills: small, uppercase, letter-spaced (keeps the existing pill + idiom from the current UI). +- Prose: `system-ui`. + +## 2. Layout — Stacked HUD Bands + +Every state composes the same **band primitive**: a row with a top divider and +consistent horizontal/vertical padding. Stacking bands produces the layered HUD +look. The active session follows the approved sketch: + +``` +ACTIVE · on task · 7 switches ← status band (accent border-top + pill) +24:18 write the spec section ← timer band +done when: draft saved ← task band +now code·spec ● | code 18:02 … ← evidence band +[ Complete ] ← action band +``` + +Drift and nudge are **not** a separate floating box. When the session drifts or +is nudged, the **status band itself** changes copy and `data-state` flips, so the +whole frame goes amber/red. The same controls render inside that band: + +- Drift: `Back to task` (`/refocus`), `This is on task` (`/ontask`), + `End session` (`/complete`). +- Nudge: `Dismiss` (client-only, current behavior). +- Pending: a quiet "checking focus…" line. + +## 3. Per-State Treatment + +- **Locked:** one dim band, large `Start planning` button (`/planning`). +- **Planning:** an intent + `Sharpen` band, then field bands — Next action, + Success condition, Minutes, Allowed apps — with the blue accent. All existing + input ids (`#intent`, `#na`, `#sc`, `#mins`, `#apps`, `#start`, + `#coachStatus`) and the coach pre-fill behavior are untouched. +- **Active:** the HUD described in §2. +- **Review (polished, presentational only):** summary bands built from data the + state already carries — `next_action`, `success_condition`, the context-switch + count, and the per-window bucket recap (reusing the existing `evidence` + fields). **No new backend data** is introduced; richer session reflection is + M7's job. The `End` button (`/end`) remains. + +## 4. Structure + +Split the single inline file into three files under `internal/web/static/`: + +- `index.html` — markup shell only (`` links the stylesheet and script). +- `app.css` — the full visual system (tokens, bands, per-state rules). +- `app.js` — the render logic, **moved verbatim**: same `render()` function, + same partial-update paths (`updateActiveDrift`, `updatePlanningCoach`), same + element ids, same `EventSource('/events')` and POST endpoints. The only + additions are the band markup in the template strings and setting + `main.dataset.state` per render. + +`web.go` currently serves only `/` via `c.FileFromFS`. Add routes so the two new +assets are served from the embedded `staticFS`: + +- `GET /app.css` → `static/app.css` +- `GET /app.js` → `static/app.js` + +No new Go dependencies, no JavaScript build step, no framework. The embedded +static directory and the conciseness/token-efficiency ethos of the Go rewrite +are preserved. + +## 5. Behavior & Data Flow — Unchanged + +Same SSE stream, same partial-update `render()` logic, same element ids, same +POST endpoints, same server-authoritative expiry timer. The redesign is markup + +CSS + asset routing only. This is precisely what keeps the existing +`web_test.go` (endpoint and state-JSON assertions, markup-agnostic) green. + +## 6. Testing + +- **Existing `web_test.go` stays green.** It asserts on endpoint status codes and + the state JSON, not on HTML markup, so the visual rework does not touch it. +- **New Go test:** `GET /app.css` and `GET /app.js` each return `200` with the + correct `Content-Type` (`text/css`, `text/javascript` / `application/javascript`). + Asserted against the router via `httptest`, stdlib `testing` only. +- **Manual visual checklist** across the six `data-state` values: locked, + planning, active (on-task), active (nudge), active (drift), review. There is no + JavaScript test harness in this Go project; the rendering is presentational and + verified by eye, consistent with the existing approach. + +## 7. Out of Scope + +- Micro-interactions / motion (timer easing, accent transitions, panel slide-in) + — explicitly excluded for M4; can be a later pass. +- Any new backend data or fields on the state payload. +- M7 reflection content (real session summary, time-on-task analytics). The M4 + review screen is presentational recap of already-available data only.