bob viz Design Checklist
bob viz Design Checklist
Section titled “bob viz Design Checklist”Every region on /bob follows these rules. A new pane copies this list into
its requirement and ticks each box before it merges. The reasons behind the
rules are in bob viz: Design (#2074).
tests/test-bob-viz-page.js checks every box marked (tested).
The same list is what the briefing page (/briefings, #2244) is held to by
tests/test-briefings-page.js — the boxes below plus one column at phone
width with every long line wrapping — and what a pane on the per-project
monitor (/warp) cites. /warp is one column of regions — Needs you, Run,
Where it is, Acceptance · Time by phase · Activity, the context tabs (its
PANES registry, #1734) and the Sources line — drawn by
scripts/dashboard/warp-regions.js from the build spec
warp-viz-spec.md; see
warp viz. A /warp region
is held to the boxes below with one difference, the type scale (decision
#4350, in the Type and spacing box), and its assertions live in
tests/test-warp-regions.js.
Data-ink
Section titled “Data-ink”- No border around a tile, a row or a list entry. Whitespace separates them (tested)
- A hairline rule (
--hairline,--border) sits only under a section head or a table head (tested) - No background fill except the page ground, a control and a hovered link (tested)
- No gridline, axis, frame or legend box on a word-sized chart
- Every figure in the pane is a value from its document. The pane renders; it does not compute
Small multiples
Section titled “Small multiples”- A region that shows a project shows every project the same way: the same rows, in the same order, at the same width
- Machines follow
machines.jsonorder. Projects within a machine follow the viewer’s sort key (the grid’s default isrecent, #2477), with name as the tiebreak (tested) - Stale or unpublished data is dimmed, and still listed
- No row label takes more than two fifths of a tile (#3582). A repo tile labels each checkout’s row by its machine, so a long label is cut with an ellipsis and carried whole in its title. The
todorow sits under its label at the tile’s full width: priority, wait, then the words, which stop at four lines and are whole in the line’s title and in Notices (tested in a browser)
Colour is state
Section titled “Colour is state”- Only
--state-active(a run in flight) and--state-bad(what is wrong) colour anything, on.active,.badand.feed-error(tested) - The normal case (
ready,live, a link) reads in plain ink (tested forready) - Every coloured value is also a word, so colour is never the only channel
- No theme overrides the state tokens, and the pair passes the dataviz palette validator on every theme, dark and light (tested). Run the validator with
DATAVIZ_VALIDATOR=<skill>/scripts/validate_palette.js node tests/test-bob-viz-page.js - A new state colour is added as a
--state-*token and re-validated with the others. It never borrows an accent or an extended-palette hue - The tile’s state mark is the one non-text use of a state token (#2477): a dot before a
runningorattentiontile’s name, coloured only through.active/.bad, titled with the feed’sreasons[]. Anidletile has no mark, and no tile has a background fill (tested). A new--state-*token the mark ever needs is validated with the pair, in both themes - The needs-you mark (#3038) is a hollow ring (
○) and a word —todo,2 todos,2 todos · 1 p1— after the name of a tile an open todo waits on. It is plain ink, never a state token, no border and no fill, so it stays distinct from therunningandattentiondots in both themes; the card’stodorow gives the oldest todo and its exact command (tested)
Sparklines
Section titled “Sparklines”- One series, stroked in
--viz-linewith no fill; the last known point is a dot in--viz-point(tested) - Word-sized: 64×16 in a table, 40×12 on a tile. A 1-unit line and a dot of radius 1.5
- Scaled from 0 (or the lowest value, when negative) to the highest, so a flat line is never exaggerated
- The value beside it is the label. The tooltip names the range, the point count and the maximum
- A missing point is a gap, never a zero. An unread series says
not measuredwith its reason, never an empty chart
Type and spacing
Section titled “Type and spacing”- A page uses one type scale from
design-tokens.js:/bobuses dense (--text-dense-*),/warpuses large (--text-*), read from across the room (decision #4350). A page-local multiplier is allowed when it multiplies tokens and never adds a px literal —/warp’s--warp-scale, stepped by its A− / A+ control. Spacing comes from--space-*,--hairlineand--radius-*. No px literal in the stylesheet (tested) - Figures and labels in a pane use
--font-mono; headings and prose use--font-body - A long value is truncated with an ellipsis and keeps its full text in a
title
Both themes
Section titled “Both themes”- The page paints its own ground, ink and face (
--bg,--text,--font-body), because the server substitutes only the tokens (tested) - State colours and sparkline ink clear 3:1 on the page ground in every theme, dark and light (tested)
- The pane looks right in light and in dark. Regenerate the screenshots with
node scripts/dashboard/bob-viz-shots.jsand view both
Page controls
Section titled “Page controls”Built once in scripts/dashboard/bob-controls.js (#2922); a region reuses them, never its own. The reasons are in bob viz: Page controls.
- The region is a native
<details>/<summary>rendered byrenderSection, open unless the viewer collapsed it, operable from the keyboard (tested) - The summary gives the count in words (
4 need you, 1 blocked), so a collapsed region still says what it holds (tested) - The count is coloured with a state token only when it holds something running or something wrong, and never reads “nothing needs you” while a source could not be read (tested)
- Each list declares its sort keys in
SORTS, the default first, and the select names the active key in words (tested) - The sort is stable, in codepoint order, and
not measuredsorts last in either direction, never as zero (tested) - A list longer than
FOLD_FIRST(6) folds after the sort, revealsFOLD_STEP(10) more per click, then offersshow fewer; the footer counts the rows still hidden (tested) - What needs Paul is pinned past the fold (in Notices, a
blockedrun and ap1notice) (tested) - A filter never lies: when it hides any row, the head says
N of M; a problem count (blocked) is over every row; “nothing needs you” only when the unfiltered count is zero; each active filter has a chip that clears it; a filter is session-only, never stored or in the URL (#2477) (tested) - Identity is carried by linked selection, never by a hue: a tile’s name filters Notices to its project, and a notice’s
machine / projectreaches its tile with a brief--borderoutline and no fill (#2477) (tested) - The view persists per viewer under
bob-viz-view/1with every storage call in try/catch, and the sort keys are mirrored in the URL fragment, which wins over storage (tested) - A push or a re-poll repaints with the viewer’s open state, sort and revealed count (tested)
- At 390 wide the heads wrap and every control is touch-sized (
min-height: var(--space-2xl)) (tested)
Expanded card
Section titled “Expanded card”Held by the card on /bob (#2925), and by any region that opens a row into
detail. The rendering is in scripts/dashboard/bob-card.js, and the reasons
are in bob viz: Expanded card.
- The compact rows stay on the card. The expanded view opens them up underneath, in place, never on a separate page (tested)
- The disclosure control is a
<button>witharia-expandedandaria-controls, operable from the keyboard (tested) - The expanded view shows
loadinguntil its document lands, never an empty card (tested) - A push re-renders an open card from the new row and never collapses it. The cap never hides it (tested)
- Every section the document could not fill says
not measuredorunavailablewith its reason, and every null field carries its reason as a tooltip (tested) - Every link opens its source, and a link with no URL is left out, never shown dead (tested)
- No fill, no border and no rule inside the card. Whitespace separates the sections (tested)
- It spans two grid columns wide and the full row on a narrow screen, and it is legible in both themes at 390 wide. Regenerate
bob-viz-card-*.pngwithnode scripts/dashboard/bob-viz-shots.jsand view them
Honesty
Section titled “Honesty”-
not measuredis never a zero, a blank or an idle state - Every source that was not fully read is named under the pane, with its reason
- Every value from another document is HTML-escaped
Known gap
Section titled “Known gap”Light --accent is 4.22:1 on the light ground. It clears the 3:1 mark rule but
not the 4.5:1 WCAG small-text rule. /bob colours its active state with
--state-active instead, which has the same value. Raising both is a shared
token change for every dashboard, and is not part of #2074.