Bristlenose · codebook v2 · working mockup

Codebook v2

The working surface. We iterate here and the doc records what this settles — docs/design-codebook-v2.md is the record, not the driver.

Baselines below are the shipped lens rendered faithfully, so each v2 slot has something to be measured against. Nothing here is a proposal yet.

Palette Light / dark follows your OS
Artefact — real pixels, what ships Commentary — why, never the product .is-new — invented, not inherited

Scope of v2, as agreed

Baseline — what ships today

Rendered from the shipped tokens and component recipes, not redrawn. This is the thing v2 iterates against.

B1 · framework section header
shipped · framework installed, applied, enabled
The Elements of User Experience
Jesse James Garrett5 tags · 142 coded
Strategy
user needs site objectives
Structure
interaction design information architecture
Commentary

Three controls, permanently present. Apply, Uninstall and the switch share one row. The Library spec had Apply morph into the switch once spent — a one-way handoff — and had the Uninstall button leave the lens entirely for the Library tile. Neither happened, so the row carries all three lifecycles at once: run, install, enable.

Apply carries no number. The spec string was Apply to {{count}} quotes. Shipped is bare Apply — the one control that spends money does not say what it will cost.

B2 · sidebar rows — status only, never a control
shipped
Manual tags
project-ikea tags
Default
Emotional and cognitive signals
Bristlenose UXR
Library
The Elements of User Experience
The Design of Everyday Things
Commentary

Three encodings, one column. Blue dot on, grey dot off, transparent slot available — and the section heading is the only thing separating “installed” from “installable”.

The floor gets a bare slot so labels stay left-aligned. Rows are navigation for installed codebooks and a Library door for the rest — the same affordance doing two jobs.

v2 — iterations

Empty until the issues and fixes land. Each iteration gets its own frame here, captioned in the chrome bar, with its reasoning in a commentary block below it.

V1 · the detail pane, after D1 · D3 · D4
v2 · detail pane · D1 + D3 + D4
The Elements of User Experience
Jesse James Garrett5 tags · 142 coded
Strategy
user needs site objectives
Structure
interaction design information architecture
Commentary · what changed

The header emptied itself. Three decisions, each removing one control, none adding any: D1 said Apply and Uninstall must not be twin buttons; D3 moved the enable toggle into the sidebar row; D4 deleted Apply outright, because installing now is applying. What is left is identity, and one irreversible button a level deeper — which is Safari's shape exactly.

Nothing here wears .is-new. Four decisions in and the count is still zero: every step has been subtraction or relocation of something already shipped.

The space this frees is the point. An emptied header is room for the description — and author_bio and author_links, which today exist only in the pre-install preview and vanish the moment you adopt a codebook (I4), now have somewhere to live that does not disappear.

Not shown, deliberately: where the install cost is stated. D4 moves register B1's missing {{count}} onto the install control, which is now the spending one. That control lives on the browse surface, which is still undecided.

V2 · the master list — the dot, promoted
v2 · 320px · installed only · author shown
Your codebook
project-ikea tags
Installed
Emotional and cognitive signals
Bristlenose UXR
The Elements of User ExperienceJesse James Garrett
The Design of Everyday ThingsDon Norman
Browse codebooks …
shipped · 280px · dots, no author
Manual tags
project-ikea tags
Default
Emotional and cognitive signals
Bristlenose UXR
Library
The Elements of User Experience
The Design of Everyday Things
Commentary · the dot becomes the control, and the row gains a byline

Same place, same size, now live. The dot was already first-line aligned in the right column — it just was not operable. Promoting it beats deleting it and adding a control beside it: one element, one meaning, and the row does not grow horizontally.

The mini toggle is the first thing to wear .is-new, deliberately — and it is the mildest kind, a size modifier on the shipped .sw. 26×15 preserves the 38×22 track ratio exactly (1.73). Marking it keeps the counter honest; excusing it would make the counter useless.

The width was already 280px. This mockup previously drew 230 and was flattering the problem — the right frame is now the shipped --bn-sidebar-width. The v2 rail is 320, +40, which is what the byline and the toggle need before titles start wrapping.

The author earns its place twice. It is how a researcher recognises a framework — "Norman" lands faster than "The Design of Everyday Things" — and it puts provenance in the list rather than only on the page, which is the same information loss I4 describes, one surface up. The toggle stays aligned to the title line, not centred on the block: the bullet rule the shipped dot already follows.

V3 · the same control, full size, on the codebook page
v2 · codebook page · selected in the rail
The Elements of User Experience
Jesse James Garrett · 5 tags · 142 coded
Strategy
user needs site objectives
Structure
interaction design information architecture
Commentary · one control, two scales

Full-size .sw, unmodified. The page gets the shipped 38×22 macOS-matched switch; only the rail needed a smaller variant. The new thing is the mini; the canonical control stays untouched.

Two entry points, one state. Both read and write the same disabledFrameworks value, so they cannot disagree. Chrome does exactly this — toggle on the card and on the details page; Safari does not repeat it. Repeating is right here, because the page is where "am I working with this?" gets decided, and returning to the rail to act on the answer would be a wasted trip.

Toggle before button, in that order. The header reads reversible-then-irreversible left to right, matching the cost gradient in D5.

V3b · version, rendered only when present
cli-ux · has version
Command-line usability
Built in · v1.0 · 6 tags · 88 coded
garrett · no version · shows nothing
The Elements of User Experience
Jesse James Garrett · 5 tags · 142 coded
Commentary · version is optional, and absence is silent

Render if present, omit if not — no "unversioned" label, no placeholder, no dash. Two of the nine YAMLs carry version: "1.0" (cli-ux, sentiment); the other seven have none and show none.

It needs one field, not a schema change. The YAML already parses it — TemplateOut simply does not declare it, so it is dropped at the model boundary. Adding version: str | None surfaces what already exists. That is the smallest possible step outside presentation-only, and worth taking.

V4 · the browse page — card density ladder
v2 · browse · four densities, same card
The Elements of User Experience
The Design of Everyday Things
Don Norman
Affordances, signifiers, feedback and the gulfs of execution and evaluation.
10 Usability Heuristics
Jakob Nielsen
Ten general principles for interaction design — visibility of system status, match to the real world, user control and freedom, consistency, error prevention, recognition over recall.
system status user control error prevention
142 quotes
The UX Honeycomb
Peter Morville · Semantic Studios · v1.2
Useful, usable, desirable, findable, accessible, credible, valuable — seven facets for judging an experience beyond usability alone.
142 quotes
Bristlenose UXR
Built in
The recommended pour — general-purpose research codes that work on any study.
Commentary · the verb, and what the card carries

Install, not Get — and this is settled, not preference. glossary.csv registers Install across 20 locales, noted as "Apple's imperative, measured", replacing Import codebook on 26 Jul 2026. Choosing Get would reopen a measured 20-locale decision.

And there is a reason beyond inertia. The stores say Get because getting is free — the Mac App Store uses it for free apps and shows a price otherwise; Edge Add-ons uses it; Chrome says Add to Chrome; Claude's directory uses a bare +. Under D4 installing spends tokens, so borrowing Get would import an idiom that specifically signals this costs nothing. Claude's bare + is the most cost-silent of the four and is the worst fit for the same reason.

So the card states the cost. That is register B1 — the missing {{count}} — landing where D4 moved it. Shown here as a quiet figure beside the button rather than inside the label, so the button stays one word in 21 languages.

Version and publisher are drawn but marked .is-new, because they do not exist. version is present in exactly two of the nine YAMLs (cli-ux, sentiment, both "1.0") and TemplateOut has no version field at all — it is dropped at the model boundary and rendered nowhere. Publisher does not exist in any form. Both are forward slots for the far-future community library, and wiring either is a schema change, which is outside this scope.

The installed card carries the toggle, not just the button. Same mini control as the rail, so enable is reachable from the catalogue without a trip to the codebook page — and the card shows both axes exactly as D8 assigns them: toggle for enable, button for install.

V5 · size ladder — trim to fit
v2 · true pixel widths · left: no visual · right: with
minimum · 200px · the tightest grid that ships — codebook-panel.css:908
10 Usability Heuristics
142
10 Usability Heuristics
142
minimal · 240px · the codebook grid min — codebook-panel.css:9
10 Usability Heuristics
Jakob Nielsen
142
10 Usability Heuristics
Jakob Nielsen
142
slightly larger · 300px · the v2 browse grid min drawn earlier
10 Usability Heuristics
Jakob Nielsen · v1.0
Ten general principles for interaction design.
142
10 Usability Heuristics
Jakob Nielsen
Ten general principles for interaction design.
142
quote-card sized · 416px · 26rem — the analysis card min, analysis.css:9
10 Usability Heuristics
Jakob Nielsen · v1.0
Ten general principles for interaction design.
142
10 Usability Heuristics
Jakob Nielsen
Ten general principles for interaction design.
142
full content width · 832px · --bn-max-width 52rem; the cap binds before a 14in screen does
10 Usability Heuristics
Jakob Nielsen · v1.0
Ten general principles for interaction design.
142
10 Usability Heuristics
Jakob Nielsen
Ten general principles for interaction design.
142
Commentary · where content drops out

Every width is a shipped one. Not invented for this drawing: 200px and 240px are the two auto-fill minimums already in codebook-panel.css, 416px is the analysis card's 26rem, and 832px is --bn-max-width (52rem).

832px is "full width" on a 14-inch Mac. 1512pt of screen, less the ~280pt project sidebar and the 320pt codebook rail, leaves ~912 — so the content cap binds before the display does. Drawing anything wider would be drawing a case that cannot occur.

What drops as it narrows. Description goes below 300; author goes below 240; at 200 only the title and the control survive. That is the trim order, and it says the minimum viable card is title + Install — which is what you proposed, now with a width attached to it.

On the visual. Book jackets are not hypothetical — Assets.xcassets already ships welcome-book-nielsen, welcome-book-norman, welcome-book-braun-clarke and welcome-book-lazarus for the Welcome screen. So a jacket for the frameworks with a book behind them is inherited, not commissioned. The blocks here are stand-ins, not artwork.

Corrected 29 Aug — where the jackets actually live. They are on the Welcome shelf (WelcomeIllustrations.swift), not on the codebook details page, which renders no image of any kind. The shelf is richer than a jacket: each book carries a spine colour as well as artwork — Norman #334155, Nielsen #0f5c9e, Braun & Clarke #7c3aed, Lazarus #b45309.

The overlap with our codebooks is two, not four. Norman and Nielsen are shipped codebooks; Braun & Clarke (thematic analysis) and Lazarus (appraisal theory) are method credits, not codebooks. So of nine codebooks, two have a jacket and seven do not — and a grid where two cards have artwork and seven have a gap reads as broken, not varied.

The spine colour is the way out. It is a per-book brand token that exists independently of the artwork, so it can dress a card that has no jacket — a coloured spine edge or a tinted initial for the seven, the real jacket for the two, on the full page where there is room to earn it. That inherits an existing decision rather than commissioning seven covers. Still needs a call; the ladder shows both so the gap is visible at each width.

V6 · the reserved slot — space decided, fill deferred
v2 · one slot, several possible fills
candidate fills · none chosen · a codebook may have a book, a site, a face, or none
book jacket 2:3
JN
initials 1:1
headshot 1:1
G
neutral 2:3
the aspect problem · the two shapes cannot share one box
JN
2:3 slot, circle fill
dead space above and below
1:1 slot, jacket fill
jacket shrinks to fit
in place · card and page, slot reserved and neutral
G
The Elements of User Experience
Jesse James Garrett
142
G
The Elements of User Experience
Jesse James Garrett · 5 tags · 142 coded
Commentary · reserve the space, defer the fill

The slot is the durable decision; the fill is not. The earlier pass committed to an assigned colour per codebook — a whole generated palette — which was a commitment to one answer when what the grid actually needs is a consistent footprint. Reserving the space fixes the rhythm; what goes in it can change later without redrawing anything.

Every fill stays open. A codebook may have a book, a website, an author with a face, or none of those. Jacket, initials, headshot, neutral monogram — all fit the same reservation, and which one applies can be per-codebook rather than systematic.

One thing cannot be deferred: the aspect. A jacket is 2:3 portrait, a headshot or an initials disc is 1:1 — they do not share a box. A 2:3 slot leaves a circle floating in dead space; a 1:1 slot shrinks the jacket, and jackets are the richest asset we have. Picking the ratio now costs nothing and keeps every fill viable; discovering it later means redrawing both surfaces.

The safe default needs no decision. Neutral surface, monogram in --bn-colour-badge-bg — existing tokens, no new colour, no artwork. It ships as-is and gets replaced fill by fill as assets arrive.

V7 · rail closed — next / previous · REJECTED
v2 · hover-revealed · move the pointer over the page
N
10 Usability Heuristics
Jakob Nielsen · 10 groups · 36 tags · 214 coded
Visibility of system status
progress shown silent failure
User control and freedom
no undo trapped
v2 · always present · for comparison
N
10 Usability Heuristics
Jakob Nielsen · 10 groups · 36 tags · 214 coded
Visibility of system status
progress shown silent failure
User control and freedom
no undo trapped
Commentary · REJECTED 29 Aug — kept as the record

Dropped: the chevrons are a complexity that is not earning its keep. They existed only for the rail-closed case, which is Focus Mode — a reading mode, not a navigating one. If you want to move to another codebook, reopening the rail is one keystroke and shows you where you are going. Arrow-key traversal stays, because it costs no chrome. The frames below are kept as the record of what was considered.

Taken from the Welcome slot rotator (WelcomeHomeView.swift:707): the frosted disk, hairline, soft shadow, hover-reveal — and critically inert-until-revealed. That file uses allowsHitTesting(revealed) so an invisible edge column never shadows the content beneath; here it is pointer-events:none while hidden. Forgetting it would reintroduce a bug already designed out once.

Left behind: the page dots and the cross-fade. Dots say "small unordered set", and next/prev only exists when the rail is closed — so dots would re-implement the rail, badly, in the one situation the rail is absent. The title is the better position cue. The in-place cross-fade suits a slot and not a whole codebook page, where it would read as a slideshow rather than navigation.

Two things did not survive the port. .regularMaterial has no true CSS equivalent — backdrop-filter: blur() approximates it without vibrancy, guarded here by prefers-reduced-transparency. And SF Symbols are unavailable to CSS, so the glyph is a Lucide chevron. Acceptable: the rule is don't fake a symbol at the seam, and this lens is fully web content.

The open choice, drawn both ways. Hover-revealed is quieter and matches the house precedent exactly; always-present never leaves a keyboard or touch user hunting for an affordance that only appears on hover. Both are reachable by :focus-visible.

V8 · G1 — the review badge finds a home
rail · awareness
Your codebook
project-ikea tags
Installed
10 Usability HeuristicsJakob Nielsen12
The Elements of User ExperienceJesse James Garrett
Bristlenose UXR3
Browse codebooks …
page · the door
N
10 Usability Heuristics
Jakob Nielsen · 10 groups · 36 tags · 214 coded
Commentary · a chip is progress; a badge is a door

The regression, precisely. D4 fires the job on install and hands progress to the activity chip — but a chip is transient. Dismiss it, come back tomorrow, and v1's persistent "View Report · 12" is gone with nothing in its place. Pending proposals become unreachable. That is function lost, not chrome lost.

Two homes, because they answer different questions. The rail badge answers "where is there work?" — scannable across every installed codebook at once, without navigating. The page button answers "take me to it." Mail's split exactly: unread counts in the sidebar, the door in the content pane.

It does not reintroduce D1's problem. D1 objected to a routine and a destructive control being the same shape, weight and colour. Review is accent-filled, Uninstall is neutral — the shipped .apply-btn / .add-btn pair. Primary beside secondary reads correctly; twin neutrals did not.

Nothing invented. The pill is .proposed-count, already shipped. But it carries a defect worth fixing in the same pass: the real rule hardcodes rgba(37,99,235,.08) — light-mode accent. Dark mode uses #0a84ff and palette-edo uses #0f5c9e, so the tint is wrong on two of the four theme combinations. color-mix() against the token fixes it, exactly as island-doc decision 6 did for .merge-target.

Deliberately not decided here: whether Review opens a modal or a route. The door works either way, and the last-modal-standing question stays open.

V9 · each control appears exactly once
v2 · browse cards · not installed / installed / installed but off
N
The Design of Everyday Things
Don Norman
142 quotes
U
10 Usability Heuristics
Jakob Nielsen
Installed
B
Bristlenose UXR
Built in
Installed · off
Commentary · corrected — state is not enough

The first version of this frame was wrong. It showed installed cards with a green check and no control, reading Claude's directory too literally. Claude can do that because its directory has no uninstall anywhere on the card — removal lives on a different surface entirely. Ours has to be reachable, so an installed card shows Uninstall.

What survives from that pass, and it was the actual complaint: no enable toggle on the card or the page. The toggle lives in the rail, once. That is untouched.

So the card carries one button that swaps verb — Install out, Uninstall in, on the shipped .picker-card-toggle with its min-width so the control column never shifts. That is the "one footprint" rule the Library doc already settled, and V10 had it right while this frame did not.

Future enhancement, noted not built: a transition on the button as Install becomes Uninstall — the moment the card changes state is the one moment worth animating here, because it is the only feedback that the (paid) install actually took. Deferred.

Open, and it needs a call: if the card carries Uninstall, does the page still? Having it in both places undercuts D1's gradient (irreversible act a level deeper). The cleaner split is card owns lifecycle, page owns content — which would leave Review as the page's only button. Not decided here.

V10 · the card, to spec
v2 · not installed / installed & on / installed & off
T
The Elements of User Experience
Jesse James Garrett
Five mutually exclusive planes from abstract strategy to concrete surface design.
 
1
10 Usability Heuristics
Jakob Nielsen
Ten broad rules of thumb for interaction design, refined from a factor analysis of 249 usability problems.
14 tags on 34 quotes
C
Command-line usability v1.0
Built in
Tags for research on command-line tools, developer tools and sysadmin workflows.
9 tags on 12 quotes
Commentary · built to spec, and two things the spec needs that do not exist

To spec: title, author, version (rendered only where present — Garrett and Nielsen have none), a 9–18 word description, a status line for installed codebooks, no enable toggle, no "New" badge, and grey/low-contrast when disabled. The whole card navigates to the full page; only the Install/Uninstall button does not — it sits at z-index:1 above the card's own click target, which is how the shipped tile already keeps its stopPropagation honest.

One button that swaps verb, one footprint. Install when out, Uninstall when in — the shipped .picker-card-toggle with its min-width, so the control column never shifts between states. That also satisfies the Claude precedent: an installed codebook never shows an add affordance.

Gap 1 — the descriptions do not fit, and truncation will not save them. All nine shipped descriptions run 44–75 words (Yablonski 75, Plato 72, Nielsen 61) against a 9–18 word budget. First-sentence-only lands in budget for just 5 of 9: sentiment (7w) and uxr (8w) fall short, cli-ux (19w) and Plato (25w) overrun. So the card needs a dedicated short field — nine hand-written lines. First sentences make a decent starting draft for five of them, not a rule.

Gap 2 — "on 34 quotes" cannot be computed today. total_quotes is len(seen_quotes) — distinct within a group. But summariseFramework sums those across groups, so a quote carrying tags from two groups of the same framework is counted twice. The framework-level distinct count the card needs is not exposed by the API. The shipped foldedSummary ("N tags · M coded") has the same flaw, so this is an existing overstatement, not a new one.

V11 · the graphic gutter — fixed width, free height
v2 · nothing / circle 1:1 / jacket 2:3 · blue rule = shared text edge
Bristlenose UXR
Built in
A practitioner-oriented codebook for any user research study.
14 tags on 34 quotes
G
The Elements of User Experience
Jesse James Garrett
Five mutually exclusive planes from abstract strategy to concrete surface design.
14 tags on 34 quotes
10 Usability Heuristics
Jakob Nielsen
Ten broad rules of thumb for interaction design, refined from a factor analysis of 249 problems.
14 tags on 34 quotes
Commentary · the invariant is the text edge, not the silhouette

This dissolves a problem I raised wrongly. I argued the aspect ratio could not be deferred — that a 2:3 slot would leave a circle floating in dead space, and a 1:1 slot would shrink the jacket. Both follow from assuming a fixed box. Fix the width and let the height be free, and the conflict disappears: a circle is 44×44, a jacket is 44×66, nothing is 44×0, and the text starts at the same x in all three.

The blue rule is the point. It marks the shared left edge of the text column, held across all three fills. That alignment is what makes a grid read as coherent — not whether every card's graphic is the same shape. A commentary device, not product chrome.

Top-aligned, so nothing reflows. The graphic hangs from the top of the row; the title sits on the same baseline whether there is a jacket, a disc, or nothing beside it.

And "nothing" is a real option, not a fallback. Reserving the width even when there is no graphic is what keeps a bookless codebook from looking broken next to one with a jacket. No colour has to be invented, and no artwork commissioned, for the grid to hold together — which is what the earlier assigned-palette attempt was reaching for and overshot.

V12 · the full details page
v2 · codebook page · installed, enabled · real content
10 Usability Heuristics
Jakob Nielsen
14 tags on 34 quotes
Ten broad rules of thumb for interaction design, refined from a factor analysis of 249 usability problems. Originally published as an expert evaluation framework, adapted here for participant quote-coding. The heuristics cover system communication, user control, error handling, cognitive load, and design discipline.
Status visibility
progress shownsilent failurestale state
Real-world matching
jargonfamiliar metaphor
Control and freedom
no undotrappedescape hatch
Consistency and standards
breaks conventioninternal mismatch
Error prevention
easy mistakedestructive default
Recognition over recall
hidden optionmemory burden
Jakob Nielsen
Co-founder of Nielsen Norman Group and one of the most cited researchers in human–computer interaction. Coined "discount usability" and developed the heuristic evaluation method that became standard practice in UX. PhD from the Technical University of Denmark (1988).
Commentary · the page I4 was asking for

Everything here is real. The description, the bio, and all four links are the shipped nielsen.yaml — including the two Amazon links, which is the "purchase links" half of the rich page. The group names and layout are the shipped .preview-* classes, lifted verbatim: two columns, tag groups left, author card right.

And it no longer disappears on install. That is I4 closing in one frame: today this layout exists only in the pre-install preview, so author_bio and author_links vanish the moment you adopt a codebook. One page, reached from the rail or from a browse card, differing only in state and controls.

Uninstall on the page as well as the card — confirmed. Chrome and Edge both do this (Remove on the card and on the details page). It costs D1's strict "irreversible act one level deeper" gradient, but that gradient was always about not putting Uninstall beside a routine button in the always-visible rail — and it is not in the rail. Review is accent, Uninstall is neutral; primary beside secondary still reads correctly.

No enable toggle, per D11 — the rail owns it. The page shows enabled state by not being greyed.

The gutter scales, the rule holds. 72px wide here against 44px on the card; the jacket is 108px tall because 2:3 is what a jacket is, and the text still starts at a fixed x. Same D13 rule at a different size, no second decision needed.