Make design/diagrams a diagram kit with templates and a re-token tool
What does this MR do and why?
I want design/diagrams/ to be a working diagram kit, because sites draw diagrams as SVG on the design tokens and the directory held only a README promising files that did not exist. It now holds the kit.
METHOD.mdis the method an agent follows, adapted from diagram-design: decide whether to draw, choose one of eight types, state the plan, hold the budget, build from primitives under six connector rules, run the checklist, and redraw a mermaid block from its structure, never render it.conventions.mdholds the rules: every color a docs chrome token asvar(--token, #hex)with the token's light value as the fallback, every plate 960 wide, Inter and JetBrains Mono only, strokes of 1 and 1.5, the 4px grid, 8 by 8 arrowheads, ids prefixed with the slug and starting with a letter, a viewBox-sized--bgbackground as the first drawn element, and<title>and<desc>first. The frame paints itself--bgtoo, so on the site the background does not show; shown as a markdown image on GitLab, where no page token reaches it, the light fallback colors sit on their own light background instead of a dark page. Accent stays off text, since neither--accent(2.9:1) nor--accent-link(4.1:1) clears AA for small text on--bg. A plate inlines only on a docs chrome page. The lab and book chromes run ondesign/tokens/colors.css, which defines--bg,--surfaceand--accentwith dark values of its own and none of the plate's other tokens, so inline there in the dark theme the labels sit at about 1.1:1 on their ground; on those pages a plate is shown as an image.templates/has one plate per type: flowchart, process, timeline, architecture, sequence, train, layers and state. Between them they cover the trunk-based development guide's four diagrams: a flowchart across two zones with a loop, linear metric spans, a merge train, and a linear revert path.retoken.pymoves an existing SVG onto the tokens, and with--checkfails a plate on every rule inconventions.mdthat a script can test. It needs Python 3.9 and nothing else.NOTICEcarries diagram-design's MIT notice verbatim. The README, the design language brief and the diagrams page said the project was unlicensed; it has been MIT since before the brief cited it, and all three now say so.- On a screen narrower than 900px the docs chrome's figure frame now scrolls sideways instead of shrinking the drawing. The SVG keeps its authored width there, up to 960px, so a 960-wide plate's smallest label renders at 11px on a 390px phone, where it rendered at 3.6px, and the caption stays in view as the drawing scrolls. The content column sets
min-width: 0so the frame scrolls rather than the page. Above 900px the frame renders as before. A frame takestabindex="0"and its caption as its name so a keyboard can reach and scroll it. - The docs template's figure rule and its architecture page point at the kit, and the architecture figure drops its 1.25 strokes and background grid to match. The template's rule against mermaid is unchanged.
What retoken.py does to a file
flowchart LR
input["existing SVG<br/>bare hex, inner style"] --> moved["style rules moved<br/>onto matching elements"]
moved --> lookup{"color in the<br/>token files?"}
tokens["chrome/docs/tokens.css<br/>tokens/colors.css"] --> lookup
lookup -- "docs token" --> attr["var(--token, #hex)<br/>on the attribute"]
lookup -- "colors.css token" --> snap["snapped to the docs<br/>token for that role"]
snap --> attr
lookup -- "no token" --> report
attr --> ids["ids prefixed<br/>with the slug"]
ids --> report["report<br/>exit 1 on anything unmapped"]--check writes nothing. It exits 1 on anything the rewrite would change and on every rule in conventions.md that a script can test, and names the file, the element's line and the rule for each:
- the root's
role="img"andaria-label, noaria-labelledby,<title>and<desc>as its first two children with slug-prefixed ids, a title of 60 characters at most, and a<desc>with thearia-label's sentences; - a viewBox 960 wide, with a height that is a multiple of 4;
- no comment,
styleattribute, filter, animation, emoji,<script>,<foreignObject>,<image>, event handler or reference outside the file; - the two font stacks written exactly, a family and a size on every
<text>, sizes of 11, 12 and 14, weights of 400 and 600, andletter-spacing="0.08em"only on a JetBrains Mono 11 eyebrow in capitals; - strokes of 1 or 1.5 outside markers, and no dash but
4 4; - no text filled with
--accentor--accent-link; - outside markers, every rect, line, circle, ellipse, polygon, polyline and path point on the 4px grid, rect radii of 2, 4, 8, 12 or half the height, and no diagonal segment on a path or line that carries an arrowhead.
Accent on more than two drawn elements is a warning that leaves the exit status alone, until the budget says how small multiples count. In the rewrite, a color no token holds, a font outside the two stacks, or an element a plate may not carry keeps the exit status at 1; --map '#hex=--token' decides a color once its role is known. The rewrite also adds a missing background or corrects one filled or sized otherwise, and a slug that starts with a digit takes a d in front, since an XML id cannot start with one.
References
diagram-design by Cathryn Lavery, MIT, read at f4547ee95f88e5b28a52517feff6b6c11cc657f9. templates/docs/AGENTS.md, the figure rule.
Standards affected
None. No check.sh, tier or status changes.
Exemption implications
None. No existing figure changes until its site re-tokens it.
Test plan
-
just shippasses:21 standard(s) passed, 0 exempt, 0 failed. - Each template passes the plate sanitizer from !146 (merged) with nothing removed, keeping
<title>,<desc>and their ids. A copy carrying an inner<style>andid="title"loses both and fails, so the check is not empty. - A copy of !146 (merged)'s docs template builds all eight through
Plate; each built page keeps<title>and<desc>and takes itsaria-labelfrom the caption. - Rendered as an
<img>on#1f1f1fand on white, and inline in the frame light and dark, a template and a trunk plate read in all four: as an image the plate shows its own light background, and in the frame the background is the frame's color in both themes. -
retoken.py --checkreports all eight templates clean and exits 0. A fixture that breaks each rule fails on every one, and a copy of an evidence-factory plate with one size, one stroke and one coordinate changed fails on exactly those three. - On the two sites that already draw on the kit, read at named commits: evidence-factory's profile at
40fdcea0passes all 12 diagrams with no warning. The trunk exhibit's profile ateab40f7fpasses its four guide plates, drawn on the kit, and fails the 16 plates drawn before it, which took only the kit's background and ids: each is 1000 wide with no<title>or<desc>, and they carry comments,styleattributes, accent text, type from 9 to 34 at weight 700, strokes from 0.6 to 2.5, five other dashes and coordinates off the grid. Those are defects in the plates, not in the check. - Rendered light and dark at 1280 and 390 wide. At 1280 the smallest label renders at 10.6px, and a before and after render of the same page differs only in the antialiasing of one dashed hairline. At 390 the architecture template sits at 960px in a 348px frame that scrolls, with its smallest label at 11.0px.
- At 390 the page measures 414px wide with the figure and 414px with it removed: the header navigation's overflow, which !150 (merged) fixes, and to which the figure adds nothing. The figure is focusable and named by its caption in the accessibility tree, and axe reports no violations on it.
- On copies, never the source repos: bulkhead's
decision-flow.svgmaps 28 colors with none unmapped and moves 13 rules; the-diode'stwo-plane.svgmaps 62 with none unmapped and moves 20 rules. A second pass over either rewrite changes nothing, and both pass the plate sanitizer, where each source lost its<style>. manifold'spipeline-flow.svgexits 1, naming 4 colors no token holds (37 uses) and 15 IBM Plex Mono labels. In copies of the trunk exhibit's profile, the 19 older SVGs each report their background (18 filled--surface, one missing); the four guide plates, as first drawn without one, report the background missing, and the two whose file names start with07report ids that start with a digit with or without it. A second pass over any of the 27 rewrites changes nothing, everyurl(#)andhrefresolves, and the sanitizer removes nothing.
An AI tool wrote this change and ran the checks above.