---
name: sketch-ux
description: "Design method: sketch to foreground design and architecture questions. Fan first, then funnel: the fan is the divergent set of playable rendered treatments (never questionnaires), one in-page ballot per gallery; the funnel is the controlled convergence. Buxton, Ervin, and Tufte lenses. Pull at the moment a UI/UX design task begins."
---

# Skill: sketch-ux

Approach UX/design work by **sketching to foreground the design and architecture questions** · lead with a few rough alternatives that make the open choices visible, not one finished solution.

> **Status:** authored 2026-06-18 from Stephen's directive during the through-the-lens calibrator UI work (born in the geo apps; the directive was *general*, so it lives here as a substrate skill, not inside any one app or the `geospatial-ux-ui` design-system bead `f80f1929`). The geo *grammar* (layer-tree, `<stac-menu>`, `--acq-*` tokens) stays in `geospatial-ux-ui`; this is the design *method* on top.
>
> **Updated 2026-06-22** (Stephen's directive during the Sandy fire-tuning app): sketches are **rendered** · low-fi interactive HTML/SVG artifacts in the house style (e.g. `apps/camera-grid/plume.html`), **never ASCII art** · and they must **show transitions** (Buxton), not static frames. See "How to work" §4 and the Buxton lens.
>
> **Updated 2026-07-09/10** (Stephen's corrections during the glass-bead-game work, twin bead `c2ca1e60`): sketches are **PLAYABLE, never questionnaires** · the question arises implicitly in the reader's hands, and engine-native sketches (taos) are a sanctioned medium; and **THE FAN COMES FIRST** · one version followed by questions is not sketching. See §4a/§4b below; decision trail in the twin's [notes/06](https://redfish.acequia.io/guerin/.agents/c2ca1e60-1c8c-4bfa-a55d-2f82ef0aa796/2026-07-09/notes/06-ballot-drain-01-stephen.md), [notes/07](https://redfish.acequia.io/guerin/.agents/c2ca1e60-1c8c-4bfa-a55d-2f82ef0aa796/2026-07-09/notes/07-ballot-drain-02-heard-sketches.md), [notes/08](https://redfish.acequia.io/guerin/.agents/c2ca1e60-1c8c-4bfa-a55d-2f82ef0aa796/2026-07-09/notes/08-method-correction-the-fan-comes-first.md).
>
> **Updated 2026-07-20** (Stephen's terminology challenge, track-fabio bead `07eb1ef7`): **"fan" is a ratified HOUSE term, not a Buxton term — "fan first, then funnel."** The provenance audit showed the word began as an agent coinage (2026-07-09, glass-bead-game session) that Stephen echoed (*"i was clumsily trying to say the fan (or collection of sketches are questions)"*, [verbatim chat](https://redfish.acequia.io/guerin/.agents/c2ca1e60-1c8c-4bfa-a55d-2f82ef0aa796/2026-07-09/chats/2026-07-09-glass-bead-engine-going.md)); it was briefly deprecated on his directive, then Stephen ratified it the same day with full provenance in hand: *"i do like fan in that sense. fan first then funnel."* So the pairing is the method in four words: **the fan** is the divergent spread of alternatives (Buxton's "getting the right design"); **the funnel** is the deliberate convergence (Buxton's design funnel, after Pugh's controlled convergence; empirical backing Tohidi, Buxton, Baecker & Sellen, CHI 2006). When writing for outside audiences, gloss it as "multiple alternatives." Full audit + ratification arc: [track-fabio notes/05](https://redfish.acequia.io/guerin/.agents/07eb1ef7-0848-478f-b3e9-6cfa5ddec5cc/2026-07-20/notes/05-fan-term-audit.md).
>
> **Updated 2026-07-10 (evening)** (Stephen's ballot on the event-flow fan, bead `bc9679ac`): two amendments to §4b's ballot placement. (1) **Questions live WITH each sketch again**: every treatment carries its own question block including an **Other/notes affordance** ("In future keep questions with each sketch as its importtant that I can have the OTHER/Notes for each sketch"); the gallery-only single ballot lost per-treatment annotation. The page-level recombination ballot remains alongside. (2) **Combine the fan on ONE page**: treatments share a single compare surface rather than one file per treatment behind card links ("also try to compbine them in one page"). Also a rendering rule from the same drain: **no travel/journey animation**; direction of a sequence link is Tufte minimal ink, first choice subtle hue cycling along the stroke. Drain record: [bc9679ac notes/02](https://redfish.acequia.io/guerin/.agents/bc9679ac-5fa3-4ae7-b4c7-14a6a64d1162/2026-07-10/notes/02-ballot-drain-01-stephen.md).
>
> **Updated 2026-07-12** (Stephen's directive on the taos-projection fan, bead `461d7aea`): **anonymous voting is a standing ballot option** — a sketch may embed a write-capable token so visitors with no acequia identity can still cast — **but the token is always a specialized mint scoped to that one ballot box, to limit blast radius**. See the ballot-mechanics bullets in §4b for the recipe and rules.
>
> **Updated 2026-07-10 (late evening)** (Stephen's second event-flow ballot, same bead): three more standing rules. (1) **Accessibility font floor**: Stephen is 58 and uses readers ("in the future use larger fonts for me"); body text 15px minimum, controls/labels 14px minimum, nothing below 13px, in every sketch and app. (2) **Morph, never cut**: hard cuts to separate window displays are jarring context shifts; every view change morphs, and the reader controls the lerp wherever feasible ("try to morph whenever possible and give user control over the lerp process"). (3) **Questions render as comparisons**: text-only option lists are hard to answer ("it would be easier for me to see side by side comparisons for questions you are asking and then notes to comment"); where a fork exists, render the alternatives side by side, small and live where possible, with the checkboxes and notes beside the comparison. Drain record: [bc9679ac notes/04](https://redfish.acequia.io/guerin/.agents/bc9679ac-5fa3-4ae7-b4c7-14a6a64d1162/2026-07-10/notes/04-ballot-drain-02-stephen.md).

> **Updated 2026-07-21** (Stephen's directives during the 3d-terrain-tracking fan, bead
> [`019f8706`](https://redfish.acequia.io/guerin/.agents/019f8706-2bdb-7a90-9c38-681dad6f18ac/about.md)):
> two amendments to the ballot mechanics. (1) **The standard label is "critique"/"critic", never
> "voter"** (*"change your standard labeling now and in future to 'critique' instead of voter.
> voting is one function of what they do and this will align with harvard gsd design reviews"*).
> A reader's deposit is a critique in the GSD design-review sense (the crit, the same tradition
> as the Ervin lens below); the checkboxes are one function inside it, the notes are the crit.
> JSON field `critic` (with `voter` read as legacy alias); all UI copy says critique/critic.
> (2) **Every cast is its own record**: deposits are
> `feedback/<critic>-<iso-ts>-<fan>.json`, so re-casting appends rather than overwrites
> (supersedes the one-json-per-voter last-write-wins rule below), and the 📊 results panel
> tallies under a mode toggle, **latest critique per critic** vs **sum of all critiques**;
> option letters dedupe by mode, notes always list in full. First implemented in the
> [terrain-tracking fan](https://redfish.acequia.io/guerin/.agents/019f8706-2bdb-7a90-9c38-681dad6f18ac/2026-07-21/artifacts/sketches/terrain-tracking-fan/index.html);
> design record [notes/02](https://redfish.acequia.io/guerin/.agents/019f8706-2bdb-7a90-9c38-681dad6f18ac/2026-07-21/notes/02-ballot-mechanics-multi-vote.md).
> **⚠ PRIME — feedback is an APPEND-ONLY LOG in a directory, never a single overwritten file (2026-07-27, Stephen `bind-bead andy`, after a live overwrite bug):** every cast is a NEW immutable file with a **unique** name — `feedback/<critic>-<iso-ts>-<shortid>.json` (the `slug_{shortid}` no-increment rule, [beads.md](https://redfish.acequia.io/.ai/beads.md)). A **deterministic** name like `<critic>-<fan>.json` or `<sketch>__<voter>.json` is **FORBIDDEN**: repeated casts overwrite it, which is concurrency-lossy AND destroys the critique history. The reader computes the view (latest-per-critic / tally / full log) at **READ** time; the write **never** overwrites — the same discipline as `uploads/`/`chats/` immutability. The shared [ballot.js](https://redfish.acequia.io/guerin/.agents/3bf89750-6b01-41ba-8a98-3db7136d0f56/repo/sketches/ballot.js) (bead `3bf89750`) is **DEPRECATED on this point, not canonical** — it still writes `${SKETCH}__${voterKey}.json` with `overwrite:true` (one-file-per-voter last-write-wins), the exact anti-pattern; do NOT copy its filename scheme until it's fixed (queued at that bead's dock, alongside the critique/critic relabel debt).
>
> **Updated 2026-07-27** (Stephen, standing house-style directive, `bind-bead debbie [...]
> record`, during the domain-routing-sketches fan, bead `c4a8e2f1`): three rules, ratified
> from a pattern already in use that day.
>
> 1. **One page, cards pop to a larger div.** A fan with multiple live sketches lives as
>    **cards on ONE page**, not one file per treatment behind links (this extends the
>    2026-07-10 "combine the fan on one page" rule from per-treatment sections to whole
>    live-simulation sketches). Each card is a readable **summary** by default — a live
>    stat strip / headgate, not the full dense diagram — with an `⤢ expand` toggle that
>    pops the card to a fixed-overlay "larger div" (backdrop dims the rest; `Esc` /
>    backdrop-click / `✕ collapse` closes). A card's own live simulation keeps running
>    identically whether compact or expanded — expand only changes how much room it gets to
>    show it, never what it's doing. Where a card's diagram needs more legibility than its
>    compact width affords, render it at **native pixel size** (not scaled down to fit) so
>    the font floor is never silently violated, and let the compact view scroll/clip; only
>    scale **up** on expand. Old single-sketch URLs that predate a consolidation become
>    thin `<meta http-equiv="refresh">` stubs pointing at the new card's `#hash`, so shared
>    links never break. Worked example:
>    [domain-routing-sketches/index.html](https://redfish.acequia.io/guerin/.agents/c4a8e2f1-7b6d-4e93-a5c2-8f1d3b0e9a47/artifacts/domain-routing-sketches/index.html)
>    (v0.3.0 on, three live-world cards + expand).
> 2. **Clear-on-submit, no reload.** Casting a critique/answerable-question **PUTs to
>    `feedback/`, then resets the qblock IN PLACE** — checkboxes uncheck, notes clear, a
>    transient "recorded ✓" status shows and fades — and the page **never reloads**. This
>    supersedes any earlier assumption that a cast leaves the form as-is; the standing
>    reason is the same one behind clear-on-submit forms generally (the reader should be
>    able to cast a second, revised critique immediately without re-navigating or
>    re-reading their own prior answer as if it were still live). Implemented in the shared
>    `enhanceQblock()` helper in the worked example above; the canonical `ballot.js`
>    (bead `3bf89750`) does not yet do this — queued via that bead's dock alongside the
>    2026-07-21 critique/critic relabeling debt.
> 3. **Sketches under devops version control, each version carrying its own critique-log
>    (design only, not yet built).** Every revision of a sketch (v0.1 → v0.2 → …) should be
>    a **retained, addressable version** a reader can go back to, and each version should
>    carry **the critiques that drove the NEXT version** — so "why did this change" is
>    always one click from "what it changed to." The natural backend is the same git-verbs
>    substrate the rest of this workspace already uses for bead history faces (HEAD/branch/
>    mirror), not a bespoke versioning scheme — flagged to
>    [devops `64be6d29`](https://redfish.acequia.io/guerin/.agents/64be6d29-d133-4ade-9dce-f62701003e37/about.md)
>    and [domain-manager `c1192f49`](https://redfish.acequia.io/guerin/.agents/c1192f49-7859-4a5a-b393-c6ad176d0975/about.md)
>    for the storage side. The UX side (Debbie's to own): a **version switcher** (a compact
>    control naming each retained version by its ship date/critique headline, not a bare
>    number) and a **per-version critique-log view** (which ballots landed on that version,
>    verbatim, linked to what changed in response) — sketched, not shipped. Design note:
>    [domain-routing-sketches notes/00 §"Version-control + critique-log"](https://redfish.acequia.io/guerin/.agents/c4a8e2f1-7b6d-4e93-a5c2-8f1d3b0e9a47/2026-07-27/notes/00-domain-routing-sketches-provenance.md).

## When to use

Pull this skill **at the moment a design task begins** · NOT at bead bind / startup (it would tax every startup and you don't need "how to sketch" until you're designing). Invoke when:
- You're about to **propose or redesign a UI/UX** · a panel, layout, flow, component, information design.
- The user asks for **UX/design** work, a mockup, "how should this look/work," or to improve a screen.
- You're about to **spin up UX-designer subagents** (have them work in this mode).

You do **not** need it for reading or coding *existing* UI, or for pure-logic/backend work.

## The directive (why)

Stephen, 2026-06-18: *"i will ask you ux designers to sketch to foreground design and architecture questions, and not just give a solution."* A finished solution hides the questions and forecloses exploration. A sketch makes the open choices and trade-offs visible so the design is decided **together**, before committing to a render.

## How to work

1. **Lead with 2–4 rough sketches/options**, not one polished answer. Each probes a different design/architecture question.
2. For each, **name the question it's probing and its trade-off** (e.g., "headline = error vs reprojection?", "hide lat/lon or keep it?").
3. Keep fidelity **deliberately low** until the *right* design is chosen. Roughness is a feature · it reads as a question, not a verdict, and stays cheap to throw away.
4. **Render the sketches · do NOT use ASCII art.** (Stephen, 2026-06-22: ASCII mockups are not acceptable as sketches · render them.) A sketch is a small, self-contained, **low-fidelity HTML/SVG artifact** in the house style · see `apps/camera-grid/plume.html`, itself a real interactive sketch-grade artifact (dark palette, real map, sliders/buttons, a canvas stand-in for the render pane). Keep fidelity deliberately low: rough, annotated with the *question*, cheap to discard · rendered, not polished.
   - **Show transitions** (Buxton lens below): each sketch must demonstrate the *behavior over time* · before → action → after · with a replay control, not just static screens. The design lives in the transition.
   - **4a. PLAYABLE, never a questionnaire** (Stephen 2026-07-09: *"transitions that raise the question almost implicitly by the reader. not explicit questionaires"*; and on v1.4.0 of the game: *"the tufte criteria is a failure... so much wasted pixels and very little affordance"*). The sketch IS an interaction the reader plays; the central question arrives in the hands inside 60 seconds, before any text explains it. State an **ink budget** in a marker on the page and honor it; hard line caps keep sketches disposable (the heard-fan treatments ran 164 to 199 lines each). Engine-native sketches (taos) are sanctioned when the medium pays; 2D is equally legitimate. No decorative motion: a paused frame is still, and every moving pixel is owed to a driven quantity.
   - **4b. THE FAN COMES FIRST, THEN THE FUNNEL** (Stephen 2026-07-10: *"You give me one version and then questions. that is not sketching"*, then clarifying: *"the fan (or collection of sketches) are questions"*; term audited and ratified 2026-07-20, *"fan first then funnel"* · see the update above). For one goal, deliver N (3 to 5+) **genuinely divergent rendered treatments of the SAME thing** · different in kind (medium, structure, visual language), never parameter tweaks · side by side on **one compare surface (one page, per the 2026-07-10 amendment above)**. The collection asks by plurality. **Each treatment carries its own question block with an Other/notes affordance (2026-07-10 amendment; supersedes the earlier no-forms-on-treatments rule)**, and the literal recombination question stays first-class as **ONE page-level ballot**: multi-select across treatments plus a notes field built for recombination ("T2's opening with T4's ending" is a legal answer). Options in any ballot must never be prose stand-ins for alternatives that should have been rendered. Only after the fan converges (the funnel: deliberate, cited convergence) does a composed version exist, naming which treatments fed it. Worked example: [sketches-heard/fan/](https://redfish.acequia.io/guerin/.agents/c2ca1e60-1c8c-4bfa-a55d-2f82ef0aa796/repo/sketches-heard/fan/).
   - **Ballot mechanics** (supersedes the earlier request/-dock flow and the uploads/answers PUT): the shared in-page component [`ballot.js`](https://redfish.acequia.io/guerin/.agents/3bf89750-6b01-41ba-8a98-3db7136d0f56/repo/sketches/ballot.js) (canonical home: bead `3bf89750`; point it at any bead via `data-bead`). Checkboxes multi-select, an **✱ Other option always present**, **notes-only ballots must cast** (the notes are vectors: readers answer a question with another question, a decision, or a push the letters miss), one json ballot per voter per sketch into the bead's anonymous-readable `feedback/` (last-write-wins; ambient authority interim), with a 📊 results panel tallying everyone's letters AND notes live. Draining the ballot box into a distilled note is a bead-step.
   - **Anonymous voting** (Stephen 2026-07-12; standing option, ballot.js v0.5.0+): when a fan should take votes from visitors with no acequia identity, pass `data-token="<jwt>"` on the ballot.js script tag. The write ladder keeps Stephen's grid-layout-v13 rule: own identity first; the embedded key is spent **only** after the visitor's own write is 401/403-rejected, never on transient errors. **The token is always a SPECIALIZED mint — never a broad or reused key — to limit blast radius:** server-attested via `POST /auth/create-token` (owner bearer; [Token Management API](https://acequia.io/documentation/platform/token-management-api.md)), `paths`+`writePaths` scoped to **exactly that one bead's `feedback/*`**, ~180-day expiry, revocable by tokenId (`DELETE /auth/tokens/{id}`). One key per ballot box — a new fan in a new bead gets a fresh mint — and the wallet (`.ai/acequia-wallet.md`) records each as PUBLIC-BY-DESIGN with tokenId and expiry. Verify every mint before embedding it: PUT into `feedback/` → 201, PUT anywhere else → 403, anon read → 200. Precedents: `hxhs9al8o865ljoj3ijet4d9` (grid-layout v13, bead `65783732`) · `n8m54das6uk5ef90lbwmupa3` (taos-projection fan, bead `461d7aea`).
   - Put sketch files in the bead's `artifacts/sketches/`; the note frames them · for each, name the **question** it probes, its **forks**, and the **transition** it shows · and links the rendered file.
   - **Hand the fan as a LAUNCH link** (2026-07-22, Stephen via Andy, after the projected-map link opened as raw HTML in the editor): when delivering sketches to the human in chat, the link is the canonical `https://` URL (sync on their ask) or a temporary-localhost URL · NEVER a workspace-relative path to the `.html`, which IDE harnesses open as source. Rule of record: [.ai/conventions.md "Links Must Be Clickable AND Runnable"](https://redfish.acequia.io/.ai/conventions.md).
   - **UX-designer subagents** generate divergent options in parallel · have them write *rendered* HTML sketches with transitions, not ASCII.
   - `AskUserQuestion` `preview` is acceptable only for a quick *textual* fork comparison; it is not a substitute for a rendered sketch.
5. Only after the right design is chosen, **refine** (prototype) it · and *now* apply Tufte.
6. **Keep the log.** After every sketch session, append an entry to Debbie's cross-app
   ledger [`sketch-log.md`](https://redfish.acequia.io/skills/sketch-ux/sketch-log.md)
   (newest first): date, bead, links to the rendered sketch + framing note, the
   questions/forks, the first-cut recommendation, and a **decision status**
   (`open` / `first-cut` / `ratified` / `superseded`). When a bead's answer-dock
   (`uploads/answers/`) is drained, record the ratified fork choices back in the log under
   *Decisions made*. The per-bead note holds the detail; the log is the cross-bead index +
   decision trail, so design stays consistent across apps rather than re-litigated per app.

## The three lenses

- **Bill Buxton · *Sketching User Experiences*.** A **sketch** is quick, disposable, ambiguous, *suggests* not confirms → it's for **"getting the right design"** (divergent exploration). A **prototype** is for **"getting the design right"** (convergent refinement). Don't prototype while you should still be sketching.
  - *Give a good sketch:* keep it rough on purpose; show **several** alternatives; annotate the **decisions/questions**, not the pixels; make it cheap to discard.
  - *Read a good sketch:* engage the **question** it raises; don't nitpick rendering fidelity; **fork/extend** it rather than approve-or-reject.
  - ***Sketch the transitions, not just the states.*** Buxton's core point: interaction design is the experience **over time** · the dynamics and the transitions between states are where the design lives. A good UX sketch shows before → action → after (storyboard, flip-book, animation, or an interactive sketch with a replay), not a gallery of static frames. Architecture sketches likewise: animate the data **moving through the loop**, don't just draw boxes.
- **Stephen Ervin · "what a drawing is"** (Harvard GSD, digital landscape architecture). A drawing is a **representation and a thinking tool**, not the thing itself. It deliberately chooses a **level of abstraction** and what to **leave out** · and the omissions are exactly where the design questions live. So make *drawings* (selective, question-bearing), not pixel-perfect mockups posing as the answer.
- **Edward Tufte · data-ink / minimal extraneous pixels.** The **refinement** lens (use once the right design is chosen): make the user's key question **big**, demote reference detail, colour only the data, no chartjunk. Worked example: the calibrator stats panel (`74c30681` `dev/through-the-lens-test-v2.html`) · "calibrated? how close?" as the big headline; a quiet `shot | solved | Δ` table below.

## Consumers / context

- Design-system bead **`geospatial-ux-ui`** `f80f1929` (the geo UI grammar) · its `bead-bind-startup` points here for *method*.
- The image-pose calibrator **`74c30681`** is the first place this was applied (the Tufte panel).
