Skip to content

feat(diagrams): bring the hand-drawn diagrams onto the same palette - #12647

Open
jd wants to merge 2 commits into
mainfrom
devs/jd/jd/ship-diagram-token-system/bring-hand-drawn-diagrams-onto-same-palette--6bdb5b9f
Open

feat(diagrams): bring the hand-drawn diagrams onto the same palette#12647
jd wants to merge 2 commits into
mainfrom
devs/jd/jd/ship-diagram-token-system/bring-hand-drawn-diagrams-onto-same-palette--6bdb5b9f

Conversation

@jd

@jd jd commented Sep 1, 2026

Copy link
Copy Markdown
Member

<GitGraph> was a second Graphviz pipeline running beside the dot fences,
with its own COLORS map, its own EDGE_COLOR, and its own string-replace for
dark mode. <StackMapping> was a third, with five more hex literals. Three
surfaces, three private palettes, all drifting apart — which is how a page like
merge-queue/stacks ends up rendering a themed diagram and a baked one side by
side.

All three now name roles. src/util/diagramSvg.ts holds the post-processing
both Graphviz surfaces share — drop the canvas, strip the inline paint, mark a
borderless shape as a caption — so there is one place to change and no second
list of hex strings to fall out of date. The hand-placed SVG in GitGraph's
linear mode and in StackMapping emits the same node / edge groups and the
same role classes, so .dg paints all four kinds of diagram from one
stylesheet. --theme-diagram-edge is deleted: it was the old surfaces' single
diagram token and --dg-a-chrome now says the same thing.

This also fixes the bug that made the case for it. GitGraph marks every node
style=filled, which reaches a shape=plaintext node too, so the main
branch label sat on an opaque pale box — barely noticeable in light mode and
glaring in dark, on seven pages. It is a caption, so it now carries plain and
the box is gone.

Two things changed while I was in there:

  • <StackMapping> sizes its columns to their content. They were fixed at
    160px and the generated branch names did not fit; the overflow was invisible
    while the label was white on a solid fill, and would have been plainly
    visible once the label became dark text on a tint.
  • Graph-mode commit graphs are typeset at the same sizes as the fences (13/10
    rather than Graphviz's default 14 and a hand-set 9), so the two kinds of
    diagram on one page no longer disagree about how big a label is.

A call site names a role rather than a color: color: "green" becomes
role: "queued", commitColor="green" becomes commitRole="queued". The
prop is typed as DiagramRole, so a color name no longer compiles.

@mergify
mergify Bot had a problem deploying to Mergify Merge Protections September 1, 2026 13:17 Failure
@jd

jd commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 feat(diagrams): resolve every diagram color from tokens, at paint time #12646
2 feat(diagrams): bring the hand-drawn diagrams onto the same palette #12647 👈
3 feat(diagrams): let each diagram name its own roles, and lock the door #12648
4 docs(design): write the diagram system into DESIGN.md #12649

@mergify

mergify Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 2 of 6 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 👀 Review Requirements 👀 reviews
🔴 🔎 Reviews 👀 reviews
🟢 🤖 Continuous Integration
🟢 Enforce conventional commit
🟢 📕 PR description
🟢 🚦 Auto-queue

🔴 👀 Review Requirements

Waiting for

  • #approved-reviews-by >= 2
This rule is failing.
  • any of:
    • #approved-reviews-by >= 2
    • author = dependabot[bot]
    • author = renovate[bot]
    • all of:
      • author = mergify-ci-bot
      • -head ~= ^docs-agent/

🔴 🔎 Reviews

Waiting for

  • #review-requested = 0
This rule is failing.
  • #review-requested = 0
  • #changes-requested-reviews-by = 0
  • #review-threads-unresolved = 0

Show 4 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success = build
    • check-success = lint
    • check-success = test
    • any of:
      • check-success = test-broken-links
      • label = ignore-broken-links
    • any of:
      • check-success=Cloudflare Pages
      • -head-repo-full-name~=^Mergifyio/

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

@jd
jd marked this pull request as ready for review September 1, 2026 15:33
Copilot AI lite review requested due to automatic review settings September 1, 2026 15:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes shared diagram rendering and styling across many pages, so a final human review with visual verification is advisable.

Pull request overview

This PR unifies all diagram rendering (Graphviz fences, <GitGraph>, and <StackMapping>) under a single role-based palette and shared SVG post-processing, so diagrams stay consistent across themes and pages.

Changes:

  • Introduces finishDiagramSvg() as a shared Graphviz SVG post-processor and a single source of truth for diagram roles.
  • Refactors <GitGraph> and the remark Graphviz pipeline to emit role classes (instead of hard-coded colors) and rely on .dg styling.
  • Updates hand-drawn SVG diagrams (<StackMapping>, GitGraph linear mode) and docs call sites to use roles (commitRole, role) instead of colors.
File summaries
File Description
src/util/diagramSvg.ts Adds shared SVG post-processing and centralized DiagramRole vocabulary.
src/styles/theme.css Removes the legacy --theme-diagram-edge token in favor of role accents.
src/styles/index.css Extends .dg painting rules to cover hand-placed shapes and sets sizing for fixed-size diagrams.
src/content/docs/stacks/updating.mdx Updates <GitGraph> usage from commitColor to commitRole.
src/content/docs/stacks/concepts.mdx Updates <GitGraph> usage from commitColor to commitRole.
src/content/docs/stacks/compare/graphite.mdx Migrates node objects from color to role.
src/content/docs/stacks/compare/gh-stack.mdx Migrates node objects from color to role.
src/content/docs/stacks.mdx Migrates PR/node coloring from color/commitColor to role-based props.
src/content/docs/merge-queue/stacks.mdx Updates <GitGraph> usage from commitColor to commitRole.
src/content/docs/merge-queue/merge-strategies.mdx Migrates node objects from color to role.
src/components/StacksLocalModel.astro Updates <GitGraph> usage from commitColor to commitRole.
src/components/StackMapping.astro Refactors hand-placed SVG to use .dg roles and content-sized columns (removes hex literals/styles).
src/components/GitGraph.astro Refactors both linear and Graphviz modes to emit role classes and use shared SVG post-processing.
plugins/remark-graphviz.ts Switches to shared SVG post-processing and keeps legacy color-to-role mapping via roleFor.
Review details

Suppressed comments (1)

plugins/remark-graphviz.ts:140

  • To keep the finishDiagramSvg(..., { roleFor }) contract type-safe, legacyRoleFor should return DiagramRole | undefined (matching the roles actually used in LEGACY_ROLES). This prevents accidentally returning an unsupported role string that .dg can't style.
function legacyRoleFor(kind: DiagramKind, { fill, stroke }: ShapePaint): string | undefined {
  if (kind === 'edge') return stroke ? LEGACY_ROLES[stroke.toLowerCase()] : undefined;
  const table = kind === 'cluster' ? LEGACY_CLUSTER_ROLES : LEGACY_ROLES;
  const color = !fill || fill === 'none' ? (kind === 'cluster' ? stroke : undefined) : fill;
  return color ? table[color.toLowerCase()] : undefined;
  • Files reviewed: 14/14 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/util/diagramSvg.ts
Comment thread plugins/remark-graphviz.ts Outdated
Comment thread src/util/diagramSvg.ts
jd added 2 commits September 2, 2026 02:57
The diagrams were not ugly because Graphviz is ugly. They were ugly because 63
hand-typed colors across 18 pages had no palette to be consistent with, and
their dark mode was a hardcoded list of six strings the plugin string-matched.
Four dialects had grown — queue-green, emoji-pastel, nineties-pastel and
near-white-blueprint — and `enterprise/architecture` rendered as a stack of
white slabs on the dark page, because the plugin deliberately skips a cluster
that has a fill and every fill on that page is near-white.

Graphviz supports a `class` attribute on graphs, nodes, edges and clusters and
copies it verbatim into the SVG. So the plugin stops handling color entirely.
It injects shape and spacing defaults, drops the opaque canvas, tags each
element with a *role*, strips the inline paint, and one stylesheet resolves
surface, border and label at paint time. Dark mode then arrives through the
same `:root.theme-dark` block as every other surface on the site — no second
render, no flash, no string matching — and the built SVGs now contain no color
at all.

The 19 fences are not touched. A table in the plugin maps the colors the docs
were drawn with onto roles, so the whole corpus is recolored with zero MDX
edits and this reverts in one commit. The table maps by hue family, so elements
drawn alike still read alike; it is lossy the other way — PostgreSQL and Redis
both land on `datastore` — and that is paid back one page at a time as each
fence names its own roles. It is a shim with a known end: when no fence spells
a color, nothing reaches it.

Three things change that are worth knowing before reviewing screenshots:

- A graph-level caption moves above the figure. Graphviz's default is below;
  `labelloc="t"` is injected, so every fence with a `label=` that does not set
  `labelloc` itself now captions on top.
- Diagram text is painted in Inter rather than the browser's default sans.
  Graphviz still measures in Helvetica, so widths drift by about 3%; the
  injected node margins absorb it.
- Borders lift toward white in dark mode. The product accents themselves are
  untouched, as DESIGN.md requires — what changes is a value derived from them,
  because a #347d39 outline on the dark page surface is too dim to read.

Two roles deliberately share an accent (`queued` and `mergify` are both Merge
Queue teal): the same color under two names, because "waiting in the queue"
and "a service we run" are the same idea on two kinds of diagram, and a role
name that lies is worse than a duplicated accent.

`--color-green-700` is not a new color. It is the green nine diagrams already
had hardcoded, promoted so it has a name.

Verified by rendering all 35 diagrams on the site in both themes and comparing
them against the same page before the change.

Change-Id: I4100df168b1a98d79cd2f0eca15697cb2a9db1cb
`<GitGraph>` was a second Graphviz pipeline running beside the `dot` fences,
with its own `COLORS` map, its own `EDGE_COLOR`, and its own string-replace for
dark mode. `<StackMapping>` was a third, with five more hex literals. Three
surfaces, three private palettes, all drifting apart — which is how a page like
merge-queue/stacks ends up rendering a themed diagram and a baked one side by
side.

All three now name roles. `src/util/diagramSvg.ts` holds the post-processing
both Graphviz surfaces share — drop the canvas, strip the inline paint, mark a
borderless shape as a caption — so there is one place to change and no second
list of hex strings to fall out of date. The hand-placed SVG in GitGraph's
linear mode and in StackMapping emits the same `node` / `edge` groups and the
same role classes, so `.dg` paints all four kinds of diagram from one
stylesheet. `--theme-diagram-edge` is deleted: it was the old surfaces' single
diagram token and `--dg-a-chrome` now says the same thing.

This also fixes the bug that made the case for it. GitGraph marks every node
`style=filled`, which reaches a `shape=plaintext` node too, so the `main`
branch label sat on an opaque pale box — barely noticeable in light mode and
glaring in dark, on seven pages. It is a caption, so it now carries `plain` and
the box is gone.

Two things changed while I was in there:

- `<StackMapping>` sizes its columns to their content. They were fixed at
  160px and the generated branch names did not fit; the overflow was invisible
  while the label was white on a solid fill, and would have been plainly
  visible once the label became dark text on a tint.
- Graph-mode commit graphs are typeset at the same sizes as the fences (13/10
  rather than Graphviz's default 14 and a hand-set 9), so the two kinds of
  diagram on one page no longer disagree about how big a label is.

A call site names a role rather than a color: `color: "green"` becomes
`role: "queued"`, `commitColor="green"` becomes `commitRole="queued"`. The
prop is typed as `DiagramRole`, so a color name no longer compiles.

Change-Id: I6bdb5b9fbd6574a37172fa067e81b0103282725f
@jd
jd force-pushed the devs/jd/jd/ship-diagram-token-system/bring-hand-drawn-diagrams-onto-same-palette--6bdb5b9f branch from 204561e to e2b246d Compare September 2, 2026 00:57
@jd

jd commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Revision history

# Type Changes Reason Date
1 initial 204561e 2026-09-02 00:57 UTC
2 content 204561e → e2b246d review (#12647): type roleFor and the legacy tables as DiagramRole; unit-test the shared SVG post-processor 2026-09-02 00:57 UTC

@mergify
mergify Bot had a problem deploying to Mergify Merge Protections September 2, 2026 00:57 Failure
@jd

jd commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Re-pushed to address the review: 204561ee2b246d (compare).

  • roleFor returns DiagramRole | undefined, and the legacy tables are Record<string, DiagramRole> — a typo in one of the ~40 role names used to compile and produce an unstyled element, and now fails the build.
  • DiagramRole imported alongside DiagramKind / ShapePaint.
  • New src/util/diagramSvg.test.ts: 7 cases on the shared post-processor, driven on hand-written SVG rather than through Graphviz. The one that earns its place is direct-children-only paint stripping, which find() instead of children() would break while passing every existing test.

pnpm check, pnpm test and pnpm build green on this commit on its own.

Base automatically changed from devs/jd/jd/ship-diagram-token-system/resolve-diagram-color-tokens-paint-time--4100df16 to main September 3, 2026 07:47
@mergify

mergify Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

@jd this pull request is now in conflict 😩

@mergify mergify Bot added the conflict label Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants