Skip to content

๐Ÿ“ TikZ layout scaffolds

One known-good starting file per layout metaphor in docs/TIKZ-STYLE.md. That document tells an author to commit to a metaphor before placing a node; these are what the choice hands you, so a figure starts from a file rather than from an empty tikzpicture.

File Metaphor Reach for it when
pipeline.tex Pipeline the thing is a sequence and the question is "what happens next"
map.tex Map the point is how things compare on two named axes, not how they connect
layered-stack.tex Layered stack the question is what is allowed to depend on what
control-loop.tex Control loop the whole claim is that the cycle closes
branching-tree.tex Branching tree one thing divides into cases and no case rejoins another
hub-and-spoke-network.tex Hub-and-spoke network everything going through one place is the claim
zoned-spine.tex Zoned spine one storyline, with parallel commentaries on points along it
state-machine.tex State machine it is in one state at a time, and a state can recur, stay put or be sent back
comparison.tex Comparison two things made of the same parts, and the point is the part that differs
sequence.tex Sequence parties exchange messages and the order of the exchanges is the claim
timeline.tex Timeline when things happen, and how far apart, is the claim

Two more things live here that are not scaffolds:

  • cg-figstyle.tex is the house figure style: the palette plus node roles, zone cards, edges, tags, badges, a legend swatch and a two-step label ramp. Every scaffold carries a verbatim copy of it, so you never copy it by hand; see below.
  • exemplars/ holds seven figures drawn with that block, at a wider page (the render's 453pt) than the scaffolds: three from one paper redrawn, and a comparison, a Markov chain, a sequence and a timeline drawn for this project. They show what the vocabulary is for: zone cards, step badges, a legend, the house pics, lettered panels, an accented state, lifelines and eras placed in time. pump-markov-chain.tex is the reference book's pump as a Markov chain, the state-machine layout with an accented state and no initial or accepting one. Read them; start from a scaffold.

๐Ÿš€ Using one

Start a figure from it beside the draft that needs it, then re-label the nodes. figure new copies the scaffold, syncs its house block and never overwrites a figure that exists:

1
chitragupta figure new content/drafts/<topic>/figures <name> --layout pipeline

Its first line, % cg-layout: pipeline, names the layout, and chitragupta figure check reads it to print the figure's size and counts beside that layout's reference ranges, and to skip the connector rules that layout exempts (a hub's diagonal spokes, say). Keep it, and change it if you change the layout.

๐ŸŽจ The house style comes with the file

Every scaffold carries the house figure-style block (cg-figstyle.tex, described in TIKZ-STYLE.md) between two marker comments, and draws with it: \begin{tikzpicture}[cg], then cgbox, cgkey, cgedge and the rest, so a copied file is already in house colours, weights and corners and you re-label rather than re-decide. Keep the block inside the figure when you edit it: the renderer injects only \usepackage{tikz}, and a thesis-chapter-writer fragment is \input into the user's own thesis, which has never heard of this project. A figure depending on a style defined elsewhere compiles here and fails there.

Do not edit inside the markers. Every figure in a book carries the same copy, and an edited one forks the house style without anyone noticing. A style only your figure needs goes in the picture's own options. Repeating the block in every figure of one document is safe: it is all \tikzset and \providecommand, so a second copy re-defines the same keys to the same values.

The colour roles, in one line each: cgInk borders and labels, cgFlow the primary path, cgAccent the one thing the figure is about, cgAlt a second class, cgAux what happens off to the side, cgWarm and cgRose a third and fourth zone. Fills are tints of the palette name; strokes and coloured text take its darker shade, cg<Hue>Line or cg<Hue>Text (draw=cgAltLine, text=cgAccentText), which clear WCAG contrast where the light hues do not. docs/TIKZ-STYLE.md has the table, and figure check's k1-stroke and k2-text report a figure that draws or writes in a light hue instead.

Labels are set at the body size, all of them. Node names and zone titles are \normalsize\bfseries and everything else is \normalsize, which [cg] sets explicitly. Each scaffold is laid out to fit the article class's text width at that size, so \input it bare: a \resizebox around it prints the type at whatever the scale factor happens to be.

Then write the ASCII twin at figures/<name>.txt and reference the pair from the draft with a single marker line. docs/WRITING-STANDARDS.md ยง10 owns that contract, and your genre skill's figure step spells the marker for your draft's language. Every scaffold and exemplar here ships as such a pair: copy its .txt beside the .tex and edit both. chitragupta figure check reports a twin that is missing or that lacks a name, tag or panel letter the TikZ has (twin-missing, t1-labels, t2-tags, t3-panels), and tests/test_tikz_scaffolds.py holds every pair here clean under those rules. A twin is the clearest 7-bit form of what the figure says, not necessarily a tracing of it: state-machine.txt is a transition table, because a self-loop and a curved pair draw badly in characters and the table is more precise.

A panelled figure is still one file. Copy the same scaffold once per panel into a single tikzpicture (or two different ones, if the panels are different shapes), and give each panel a (<letter>) <short title> label node, lettered by its position in reading order: (a) first, (b) next, on through the alphabet. docs/TIKZ-STYLE.md's "Panels in one figure" section has the worked example and the rule for a row that stops fitting. These files carry no figure float, so the float and the \caption are added to your copy, not found in it.

Each file carries its own \usetikzlibrary line at the top. Keep it: the renderer collects those lines across a draft's figures and loads the union in the preamble (#781), so the line is a no-op in a rendered draft -- but it is what makes the file compile on its own, which is how you are told to check one, and what thesis-chapter-writer's fragment needs inside a thesis this pipeline never sees. A picture that reaches for below=4mm of store with no load anywhere fails the whole render, with a message naming neither the library nor the figure.

Do not add anything else about loading: no clearing of \tikz@library@...@loaded, no saving or restoring of \tikz@node@reset@hook. Inside a figure float those workarounds multiply every node's placement shift, silently. See docs/TIKZ-STYLE.md.

โœ… What "known-good" means here

Every scaffold compiles on its own and reports no finding from figure check:

1
chitragupta figure check assets/tikz/pipeline.tex

The tests hold parts of that on every run, so a scaffold cannot quietly rot. tests/test_tikz_scaffolds.py checks that no scaffold has a node overlap, a protrusion or node text past 15 words, and reads the metaphor table in docs/TIKZ-STYLE.md, so adding a row there without adding a file here fails. tests/test_figure_check.py checks that each scaffold compiles, accents one node, sets no stray space and fits the width. What each rule means is in docs/figure-checks/README.md.

tests/test_tikz_scaffolds.py also checks four more things, for the scaffolds and the exemplars alike:

  • every copy of the block is byte-identical to cg-figstyle.tex. After editing that file, bump the v<N> in its first line, add the new version's digest to cg-figstyle.versions.toml, and run python -m chitragupta figure sync assets/tikz/*.tex assets/tikz/exemplars/*.tex to refresh every scaffold and exemplar instead of copying the block by hand;
  • \input of the file sets nothing but its picture: the block, the \usetikzlibrary line and the picture's last line all end in %;
  • no glyph prints below the body size, read back out of the compiled PDF (a subscript or exponent may go to TeX's own script size, and no further);
  • each scaffold fits the article text width unscaled.

Every node is named, and that matters. A finding names a node by its (name), and an unnamed node only by its centre in millimetres. A picture that names no node at all is reported as nothing-measurable. Keep the names when you re-label.

โœ Editing one without breaking it

The scaffolds place every node relative to another node. None of them places a node at a coordinate in millimetres, and that is the property to preserve (the block's pics are the one exception, and docs/TIKZ-STYLE.md says why): a figure laid out in hand-computed absolute millimetres cannot express "do not collide", so changing one label's length re-opens every adjacency in the picture at once.

Three limits worth knowing before you edit:

  • Gaps are bounded by the protrusion check. A tall empty horizontal band (more than a third of the figure's height with no node in it) is reported as content-protrusion, because LaTeX sets a figure as a rectangular box and one element stranded above the rest wastes every inch beside it. Spreading a two-row layout out generously is the usual way to trip this.
  • A containing box is not a collision. layered-stack.tex relies on it: a fit layer wholly enclosing its members is grouping, which node-overlap exempts, whereas two layers partially overlapping is a finding.
  • A tree reports no edges. branching-tree.tex uses child, which draws its edges internally rather than as \draw statements, so the edge list and budget-edges come back empty for it. The connector rules still measure the lines it drew. Confirm a tree's structure from the source's own nesting.