| name | commit-graph-figures |
|---|---|
| description | Draw commit-graph comparison figures (hand-written SVG in HTML) for articles, PR descriptions, and docs. Use when the user wants a git graph diagram showing which two commits/refs get compared (baselines, merge refs, fork points), wants multi-panel figures of the same graph with different comparisons highlighted, or asks to visualize CI/merge-ref behavior. |
One topology, many panels. The graph (commits, branches, synthetic merge commits) is defined once as data; each panel re-renders that identical topology and varies only its spotlight — which pair is compared, what is dimmed — and its verdict. Readers keep a single mental model across panels; hand-drawing any panel separately breaks that and is the primary failure to avoid.
-
Define the topology as data. Nodes (
{x, y, fill, label}) and edges ([from, to]pairs) in one JS object/array inside the HTML. Give nodes short stable names (M1..Mnfor main,A1base,B1head,T1/T2GitHub test commits,Sself-made merge) and reuse those names verbatim in the surrounding prose. Done when: every panel can render from this single source and moving one node moves it in all panels. -
Define panels as configs, not drawings. Each panel is
{title, pair: [a, b], dim: [...], verdict, caption}.pairgets double rings and the comparison arc;dimrenders at ~25% opacity; nodes irrelevant to the whole figure set are omitted, not dimmed. Done when: adding a panel is a config entry, zero new drawing code. -
Render with a small fixed vocabulary of primitives.
- Commit:
<circle r="15">; synthetic commits (test merges, CI-built merges) get a dashed stroke and pale fill — they are "not on any branch" and must look it. - Edge:
<line>, one neutral gray. - Comparison arc: quadratic
<path>with<marker>arrowheads on both ends, dashed, routed through empty canvas space. - Text halo:
paint-order: strokewith a thick background-colored stroke, so labels stay legible over edges. - Branch lanes: faint horizontal guide lines with italic lane labels at the left edge.
- Commit:
-
Fix the verdict position across panels. One line, bottom-center, same coordinates in every panel: what the diff contains ("diff = B1 only — ..."). Floating verdicts near their arcs collide with lane labels and read differently per panel.
-
Ship as screenshot-ready cards. Each panel sits on a fixed white card (
background:#fff, border, radius) regardless of page theme, so a screenshot looks identical wherever it lands — most publishing targets render neither mermaid nor raw SVG. Colors must pass a CVD (color-blindness) check; do not eyeball palettes — a validated safe set: orange#f08c00(head), blue#1971c2(base), red#e03131(drift/noise), violet#9c36b5(synthetic), gray#868e96(shared history). -
Render it and look at it. Coordinates and arc control points are hand-tuned guesses until a human (or screenshot) confirms them. Done when: at full size, no text overlaps any other text or node — a halo partially hiding another label counts as overlap, not as acceptable layering.
<script>
const NODES = { M1:{x:160,y:470,fill:"#868e96",label:"M1"}, /* ... */ };
const EDGES = [["M1","M2"],["M1","A1"],["A1","B1"] /* ... */];
const PANELS = [
{ title:"Today ❌", pair:["A1","T2"], dim:["S"],
verdict:"diff = B1 + M2·M3 — drift leaks in", caption:"..." },
// one entry per comparison approach
];
// render(): map EDGES→<line>, NODES→<circle>+label, pair→rings+arc, verdict→fixed bottom text
document.getElementById("figs").innerHTML = PANELS.map(render).join("");
</script>- Verdict/label collisions hide behind the halo: the white stroke makes an overlapped label look like corrupted ghost text rather than an obvious crash. This is why step 6 is a real step.
- Prose drift: if the article says "the base branch tip" while the figure says
A1, the figure stops paying rent. Introduce the node names once in prose, then use them everywhere. - Per-panel graphs: the temptation is to simplify each panel's graph to "just what it needs". Resist — the shared topology is the point; use
diminstead.