diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json
index c564a39..a87f2bb 100644
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
"metadata": {
- "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling."
+ "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, DP security matrix, sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, or database schema diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling."
},
"owner": {
"name": "Cathryn Lavery"
diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 383133c..0b43756 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
- "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
- "version": "2.5.6",
+ "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, DP security matrix, sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, or database schema diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
+ "version": "2.5.10",
"author": {
"name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery"
diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json
index aedf73f..59f8046 100644
--- a/.codex-plugin/plugin.json
+++ b/.codex-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
- "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
- "version": "2.5.6",
+ "description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, DP security matrix, sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, or database schema diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
+ "version": "2.5.10",
"author": {
"name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery"
@@ -26,7 +26,7 @@
"interface": {
"displayName": "Diagram Design",
"shortDescription": "Create editorial technical and product diagrams as standalone HTML.",
- "longDescription": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
+ "longDescription": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, DP security matrix, Sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, or database schema diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
"developerName": "Cathryn Lavery",
"category": "Productivity",
"capabilities": [
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 58e3005..370d2a7 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,6 +2,22 @@
+## Visual proof
+
+
+
+| Variant | Rendered preview |
+|---|---|
+| Light | |
+| Dark | |
+| Full editorial | |
+
## Validation gates
@@ -19,8 +35,9 @@
- [ ] No new entries added to `scripts/lint-skin-baseline.txt`
- [ ] Generated and source files are consistent (extractor ↔ verifier ↔ reference ↔ command)
- [ ] Accessible SVG contract satisfied for new/changed examples
+- [ ] Rendered screenshots are attached for every new/changed diagram variant, or visual proof is marked not applicable
- [ ] Code of Conduct respected
## Related issues
-
\ No newline at end of file
+
diff --git a/.github/pr-previews/editorial-diagrams-2.5.10.jpg b/.github/pr-previews/editorial-diagrams-2.5.10.jpg
new file mode 100644
index 0000000..ec66de7
Binary files /dev/null and b/.github/pr-previews/editorial-diagrams-2.5.10.jpg differ
diff --git a/.maintainer-policy.json b/.maintainer-policy.json
new file mode 100644
index 0000000..56861dd
--- /dev/null
+++ b/.maintainer-policy.json
@@ -0,0 +1,99 @@
+{
+ "schema_version": 1,
+ "repository": "cathrynlavery/diagram-design",
+ "base_branch": "main",
+ "default_merge_method": "squash",
+ "versioning": {
+ "enabled": true,
+ "strategy": "semver",
+ "increment": "patch",
+ "manifests": [
+ {
+ "path": ".claude-plugin/plugin.json",
+ "json_pointer": "/version"
+ },
+ {
+ "path": ".codex-plugin/plugin.json",
+ "json_pointer": "/version"
+ }
+ ],
+ "require_synchronized": true,
+ "require_unique_across_open_prs": true,
+ "bump_command": "python3 scripts/bump-plugin-version.py"
+ },
+ "gates": {
+ "local_commands": [
+ "python3 scripts/test-plugin-package.py",
+ "python3 scripts/verify-plugin-package.py origin/main",
+ "npx --yes @anthropic-ai/claude-code@2.1.229 plugin validate . --strict",
+ "python3 scripts/test-lint-a11y.py",
+ "python3 scripts/verify-semantic-motion.py --markdown-only",
+ "python3 scripts/verify-semantic-motion.py --example-only",
+ "python3 scripts/verify-motion.py --shipped",
+ "python3 scripts/test-build-icons-quoted-attributes.py",
+ "python3 scripts/test-build-icons-devicon.py",
+ "python3 scripts/test-fix-mojibake.py",
+ "python3 scripts/lint-skin.py --all --baseline",
+ "python3 scripts/verify-sequence-oauth.py",
+ "python3 scripts/verify-drawio-import.py",
+ "python3 scripts/test-verify-drawio-import.py",
+ "python3 scripts/verify-mermaid-import.py",
+ "python3 scripts/test-verify-motion.py",
+ "python3 scripts/verify-docs-sync.py",
+ "python3 scripts/test-verify-docs-sync.py",
+ "python3 scripts/test-self-check.py",
+ "python3 scripts/verify-geometry.py --all",
+ "python3 scripts/test-verify-geometry.py",
+ "python3 scripts/verify-treemap.py --all",
+ "python3 scripts/test-verify-treemap.py",
+ "python3 scripts/verify-dumbbell.py",
+ "python3 scripts/test-verify-dumbbell.py",
+ "python3 scripts/verify-slopegraph.py --all",
+ "python3 scripts/test-verify-slopegraph.py",
+ "python3 scripts/build-icons.py && git diff --ignore-space-at-eol --exit-code -- skills/diagram-design/assets/icons.html skills/diagram-design/references/primitive-icons.md"
+ ],
+ "required_check_names": [],
+ "review": {
+ "provider": "none",
+ "minimum_score": "",
+ "require_same_head": true
+ },
+ "require_current_base": true,
+ "require_conflict_free": true,
+ "require_resolved_threads": true,
+ "require_no_requested_changes": true,
+ "post_merge_workflows": [
+ "CI",
+ "Deploy gallery to GitHub Pages"
+ ]
+ },
+ "issue_policy": {
+ "read_complete_threads": true,
+ "search_competing_prs": true,
+ "reproduce_on_current_main": true,
+ "inspect_history_for_intent": true,
+ "max_maintainer_authored_prs_per_run": 1
+ },
+ "pr_policy": {
+ "process_versioned_prs_serially": true,
+ "inspect_first_time_fork_workflows": true,
+ "split_large_or_mixed_scope": true,
+ "run_complete_suite_on_exact_head": true,
+ "wait_for_post_merge_before_next": true
+ },
+ "human_gates": [
+ "product_priority",
+ "large_or_mixed_scope",
+ "first_time_workflow_approval",
+ "ambiguous_issue_closure",
+ "security_disclosure",
+ "merge_authorization"
+ ],
+ "report": {
+ "path": ".context/maintainer/{timestamp}/report.md",
+ "live_urls": [
+ "https://cathrynlavery.github.io/diagram-design/"
+ ],
+ "require_worklog": true
+ }
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b921b64..82a2b46 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ Please read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) first. All contributions ar
## What this project is
-Diagram Design is an agent skill (Claude Code, Codex, Pi) that produces editorial-quality diagrams as self-contained HTML files. The repo is documentation-first: `skills/diagram-design/SKILL.md` is the index, each of the 28 visual types has its own reference file, and the extractor scripts in `skills/diagram-design/scripts/` turn draw.io and Mermaid sources into a structured IR.
+Diagram Design is an agent skill (Claude Code, Codex, Pi) that produces editorial-quality diagrams as self-contained HTML files. The repo is documentation-first: `skills/diagram-design/SKILL.md` is the index, each of the 38 visual types has its own reference file, and the extractor scripts in `skills/diagram-design/scripts/` turn draw.io and Mermaid sources into a structured IR.
See [README.md](README.md) for the full picture, including the design system and the import/export flows.
diff --git a/README.md b/README.md
index ab6987d..ba97ef4 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,9 @@
*New in 2.3: semantic system patterns and optional accessible motion, while static output stays the default.*
-28 visual types. One agent skill for Claude Code, Codex, and Pi. Semantic patterns describe behavior separately from layout, so a queue, policy trace, or trust boundary can use the nearest existing type without expanding the type count. Static HTML remains the default; optional motion is available for ordered explanations. The skill also redraws draw.io or Mermaid sources at a chosen format, size, and detail level.
+*New in 2.5.10: ten more layout grammars — Sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, and database schema.*
+
+38 visual types. One agent skill for Claude Code, Codex, and Pi. Semantic patterns describe behavior separately from layout, so a queue, policy trace, or trust boundary can use the nearest existing type without expanding the type count. Static HTML remains the default; optional motion is available for ordered explanations. The skill also redraws draw.io or Mermaid sources at a chosen format, size, and detail level.
No Figma. No generic rounded boxes. No 30-minute color-picking sessions.
@@ -22,7 +24,7 @@ No Figma. No generic rounded boxes. No 30-minute color-picking sessions.
I write at [littlemight.com](https://littlemight.com?utm_source=diagram-design&utm_medium=readme&utm_campaign=github&utm_content=intro) (and run [BestSelf.co](https://bestself.co?utm_source=diagram-design&utm_medium=readme&utm_campaign=github&utm_content=intro) on the side). Every time I needed a diagram — an architecture sketch, a flowchart, a pyramid of what matters most — I'd ask Claude and get back a generic rounded-box thing that looked nothing like the rest of the site. I'd either fight with Figma for 30 minutes or just skip the diagram.
-So I built a Claude Code skill for it. Twenty-eight visual types, editorial quality, matches your brand in 60 seconds by reading your website.
+So I built a Claude Code skill for it. Thirty-eight visual types, editorial quality, matches your brand in 60 seconds by reading your website.
> *The highest-quality move is usually deletion.* Every node earns its place. The accent color is reserved for the 1–2 things the reader should look at first. Target density: 4/10.
@@ -30,7 +32,7 @@ So I built a Claude Code skill for it. Twenty-eight visual types, editorial qual
## What it makes
-All 28 visual types ship in three static variants: minimal light, minimal dark, and full-editorial. Open any of them directly in a browser. There is no build step, JavaScript, or external image dependency.
+All 38 visual types ship in three static variants: minimal light, minimal dark, and full-editorial. Open any of them directly in a browser. There is no build step, JavaScript, or external image dependency.
@@ -85,7 +87,22 @@ All 28 visual types ship in three static variants: minimal light, minimal dark,
-**Browse the live gallery:** [cathrynlavery.github.io/diagram-design](https://cathrynlavery.github.io/diagram-design/) — or open [`skills/diagram-design/assets/index.html`](skills/diagram-design/assets/index.html) locally to flip through all 28 diagrams with light / dark / full-editorial tabs.
+**New in 2.5.10 — ten layout grammars nothing else covered.** Open the examples directly or compare every light, dark, and full-editorial render in the [30-variant contact sheet](.github/pr-previews/editorial-diagrams-2.5.10.jpg).
+
+| Type | Shows | Example |
+|---|---|---|
+| **Sankey** | A quantity splitting and merging across stages — band width is the amount | [`example-sankey.html`](skills/diagram-design/assets/example-sankey.html) |
+| **Fishbone** | Causes of one observed effect, grouped by category — root-cause analysis | [`example-fishbone.html`](skills/diagram-design/assets/example-fishbone.html) |
+| **Wardley map** | Value chain against evolution — what to build, what to buy, what is moving | [`example-wardley.html`](skills/diagram-design/assets/example-wardley.html) |
+| **Kanban** | Work-in-progress by state, with WIP limits and blocked items | [`example-kanban.html`](skills/diagram-design/assets/example-kanban.html) |
+| **User journey** | What a person does across stages of an experience, and how it feels | [`example-journey.html`](skills/diagram-design/assets/example-journey.html) |
+| **Deployment** | Where software runs — zones, hosts, artifacts, replicas, ports | [`example-deployment.html`](skills/diagram-design/assets/example-deployment.html) |
+| **Dependency graph** | What depends on what — fan-in and cycles a tree cannot express | [`example-dependency.html`](skills/diagram-design/assets/example-dependency.html) |
+| **UML class** | Classes with operations, inheritance and composition (other UML routes to existing types) | [`example-uml-class.html`](skills/diagram-design/assets/example-uml-class.html) |
+| **Story map** | Narrative backbone sliced into releases, with the release cut line | [`example-story-map.html`](skills/diagram-design/assets/example-story-map.html) |
+| **Database schema** | Physical tables: SQL types, constraints, indexes, column-level foreign keys | [`example-db-schema.html`](skills/diagram-design/assets/example-db-schema.html) |
+
+**Browse the live gallery:** [cathrynlavery.github.io/diagram-design](https://cathrynlavery.github.io/diagram-design/) — or open [`skills/diagram-design/assets/index.html`](skills/diagram-design/assets/index.html) locally to flip through all 38 diagrams with light / dark / full-editorial tabs.
---
@@ -185,7 +202,7 @@ Every diagram template gives the inline SVG an accessible name and description:
### Manual override
-Prefer to set tokens by hand? Open [`skills/diagram-design/references/style-guide.md`](skills/diagram-design/references/style-guide.md) and edit the table. Everything downstream reads from there — all 28 diagrams, the annotation primitive, and the gallery all inherit semantic role names (`accent`, not `#eb6c36`).
+Prefer to set tokens by hand? Open [`skills/diagram-design/references/style-guide.md`](skills/diagram-design/references/style-guide.md) and edit the table. Everything downstream reads from there — all 38 diagrams, the annotation primitive, and the gallery all inherit semantic role names (`accent`, not `#eb6c36`).
### First-run gate
@@ -206,7 +223,7 @@ The profile library is shared across Claude Code, Codex, and Pi. Use `/diagram-d
## Quickstart
```bash
-# From a cloned checkout, open the gallery to see all 28 diagrams
+# From a cloned checkout, open the gallery to see all 38 diagrams
open skills/diagram-design/assets/index.html # macOS
xdg-open skills/diagram-design/assets/index.html # Linux
@@ -360,6 +377,16 @@ diagram-design/
│ │ ├── type-layers.md
│ │ ├── type-venn.md
│ │ ├── type-pyramid.md
+│ │ ├── type-sankey.md
+│ │ ├── type-fishbone.md
+│ │ ├── type-wardley.md
+│ │ ├── type-kanban.md
+│ │ ├── type-journey.md
+│ │ ├── type-deployment.md
+│ │ ├── type-dependency.md
+│ │ ├── type-uml-class.md
+│ │ ├── type-story-map.md
+│ │ ├── type-db-schema.md
│ │ ├── primitive-annotation.md
│ │ ├── primitive-sketchy.md
│ │ └── primitive-terminal.md
@@ -370,7 +397,7 @@ diagram-design/
│ └── assets/
│ ├── index.html — live gallery, tabbed
│ ├── template*.html — scaffolds for new diagrams
-│ ├── example-.html — 3 variants × 28 types
+│ ├── example-.html — 3 variants × 38 types
│ ├── example-loop-terminal.html
│ ├── example-quadrant-consultant.html
│ ├── example-import-drawio.html
@@ -429,7 +456,7 @@ At startup, the agent sees only the skill name and description. When a request m
| "Give me a terminal / CLI-window version" | `SKILL.md` + `references/primitive-terminal.md` |
| "Redraw this .drawio file for my deck" | `SKILL.md` + `references/import-drawio.md` + `references/output-spec.md` + the chosen type's reference |
| "Redraw this Mermaid block for my deck" | `SKILL.md` + `references/import-mermaid.md` + `references/output-spec.md` + the chosen type's reference |
-| Routine static diagram-making (any of the 28 visual types) | Only `SKILL.md` + that one type's reference |
+| Routine static diagram-making (any of the 38 visual types) | Only `SKILL.md` + that one type's reference |
No matter how many types exist, the agent only reads the one you need. Add a new type tomorrow and nothing else changes.
diff --git a/commands/import-drawio.md b/commands/import-drawio.md
index ffc6686..2725bd7 100644
--- a/commands/import-drawio.md
+++ b/commands/import-drawio.md
@@ -22,7 +22,7 @@ Accepts `.drawio`, `.drawio.xml`, `.xml`, `.drawio.png`, and `.drawio.svg`.
- `--detail=balanced` · `--audience=mixed`.
- `--variant=light` — the minimal light template.
- A single-page file selects its only page; a multi-page file lists pages and asks which to use.
-- Type is chosen from the extracted structure; `--type` forces one of the 27.
+- Type is chosen from the extracted structure; `--type` forces one of the 37.
## Flags
diff --git a/commands/import-mermaid.md b/commands/import-mermaid.md
index 1e994a0..fef80ab 100644
--- a/commands/import-mermaid.md
+++ b/commands/import-mermaid.md
@@ -22,7 +22,7 @@ Accepts `.mmd`, `.mermaid`, and Markdown files containing fenced `mermaid` block
- `--detail=balanced` · `--audience=mixed`.
- `--variant=light` — the minimal light template.
- A single diagram selects diagram 0; a multi-block Markdown file lists blocks and asks which to use.
-- Type is chosen from the extracted grammar and structure; `--type` forces one of the 27.
+- Type is chosen from the extracted grammar and structure; `--type` forces one of the 37.
## Flags
diff --git a/docs/adr/0002-semantic-patterns-do-not-expand-the-taxonomy.md b/docs/adr/0002-semantic-patterns-do-not-expand-the-taxonomy.md
index 389cc80..79e8a26 100644
--- a/docs/adr/0002-semantic-patterns-do-not-expand-the-taxonomy.md
+++ b/docs/adr/0002-semantic-patterns-do-not-expand-the-taxonomy.md
@@ -1,4 +1,4 @@
-# ADR 0002 — Semantic patterns never expand the 27-type taxonomy
+# ADR 0002 — Semantic patterns never expand the visual-type taxonomy
**Status:** accepted (v2.3)
@@ -8,7 +8,7 @@ Auditing behavior-rich figures (queues, policy traces, trust boundaries) showed
## Decision
-Behavior is a separate axis. The seven semantic patterns in `references/semantic-patterns.md` each route to the **nearest existing visual type** for layout; a pattern owns semantic primitives and a tighter budget, never a second layout grammar. The visual-type count stays at 27 unless a genuinely new *layout* grammar appears.
+Behavior is a separate axis. The seven semantic patterns in `references/semantic-patterns.md` each route to the **nearest existing visual type** for layout; a pattern owns semantic primitives and a tighter budget, never a second layout grammar. The visual-type count only moves when a genuinely new *layout* grammar appears (it did in v2.5.10 — see [ADR 0007](0007-new-layout-grammars.md), 28 → 38).
## Consequences
@@ -21,3 +21,5 @@ Behavior is a separate axis. The seven semantic patterns in `references/semantic
**2026-08-18 — the count is 28.** Treemap was admitted under the escape clause above: recursive area subdivision is a layout grammar no existing type provides (bar encodes with length, nested with containment and no quantity, pyramid with rank). It shipped the full §10 set, and the counters named above moved 27 → 28 together with the prose.
The decision itself is unchanged — semantic patterns still never add a type, and the count still moves only for a new *layout* grammar. What this amendment records is the procedure: the two counters are this ADR's enforcement, so a PR that edits them without amending this file has quietly made itself the authority. Amend here in the same PR, or the number in the test is just whatever the last contributor typed.
+
+**2026-08-19 — the count is 38.** Ten additional visual grammars were admitted under the same escape clause: Sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, and database schema. The per-type argument is in [ADR 0007](0007-new-layout-grammars.md); each ships the full §10 set, and the two counters move 28 → 38 together with the prose.
diff --git a/docs/adr/0007-new-layout-grammars.md b/docs/adr/0007-new-layout-grammars.md
new file mode 100644
index 0000000..85766cd
--- /dev/null
+++ b/docs/adr/0007-new-layout-grammars.md
@@ -0,0 +1,64 @@
+# ADR 0007 — Ten new layout grammars (28 → 38 visual types)
+
+**Status:** accepted (v2.5.10)
+
+## Context
+
+ADR 0002 fixed the taxonomy at 27 and set the bar for growth: a new type is justified only when a **genuinely new layout grammar** appears, not when a new *behavior* does — behavior is a semantic pattern routed onto an existing type.
+
+Three coverage audits ran against that bar. The first compared the skill to the Mermaid 2026 taxonomy (29 diagram types) plus current practitioner writing. The second worked through a 20-item request list covering architecture, flows, API/integration, database, and process figures. The third covered UML, story mapping, and physical database diagrams. Between them, ten figures turned out to be undrawable with any existing grammar.
+
+## Decision
+
+Add ten types, each with the full §10 shipping set (type reference + light/dark/full examples + gallery tab + routing row + budget row):
+
+| Type | The grammar that did not exist | Nearest existing type, and why it fails |
+|---|---|---|
+| **Sankey** | Band width encodes a quantity that splits and merges | Pyramid shows drop-off but not splits/merges; process shows steps, not amounts |
+| **Fishbone** | Angled category bones converging on one effect | Tree is parent→children, not cause→effect at a fixed angle with sub-cause ticks |
+| **Wardley map** | Two ordinal axes (value chain × evolution) with dependency links and movement | Quadrant positions items but has no dependency chain and no evolution bands |
+| **Kanban** | State census in columns with WIP limits and **no connectors** | Swimlane is lanes plus a flow crossing them; a board deliberately has no flow |
+| **User journey** | Stage grid plus a sentiment curve as the load-bearing element | Timeline places events on an axis; line charts plot data, neither carries per-stage rows |
+| **Deployment** | Physical placement: zones containing hosts containing versioned artifacts, with replica counts and protocol:port paths | Architecture is logical components and relations; high-level is one fixed stack shape, not an arbitrary environment topology |
+| **Dependency graph** | Ranked DAG where a node has **many parents** and a **cycle** is representable | Tree structurally forbids both — a single parent per node, and no back-edges |
+| **UML class** | Three-compartment boxes with an operations list, plus the typed relationship vocabulary where the arrowhead carries the meaning (triangle, filled diamond, hollow diamond) | ER has no operations compartment and no inheritance or ownership semantics |
+| **Story map** | Narrative-ordered backbone crossed by release slices, with a release cut line | Kanban's columns are state, not narrative order, and it does not slice; journey carries sentiment, not scope |
+| **Database schema** | Foreign keys that anchor **column row to column row**, with SQL types, constraint chips, and index compartments | ER joins *boxes* and stops at cardinality — it cannot point at a column |
+
+## Rejected, with reason
+
+Kept out on purpose, so the next audit does not relitigate them.
+
+**Already covered by an existing type — the request names a use case, not a grammar:**
+
+| Requested | Covered by |
+|---|---|
+| System context, component, API interaction | **Architecture** (a boundary or a zoom level, not a new grammar) |
+| UML sequence, request lifecycle, sequence/state combination | **Sequence** |
+| UML state machine | **State** |
+| UML activity, activity diagram | **Swimlane** + **flowchart** — the fork/join bar alone does not earn a type |
+| UML component, UML deployment | **Architecture**, **deployment** |
+| Data flow diagram (DFD) | **Data flow** |
+| Event flow (producer → broker → consumers) | **Data flow** via the fan-in queue / bottleneck semantic pattern (ADR 0002) |
+| Integration diagram | **DP integration** |
+| Data model, conceptual ER | **ER** |
+| Decision tree | **Flowchart** |
+
+**Rejected on the ADR 0002 bar or on editorial fit:**
+
+- **C4 (context / container / component)** — a zoom-level convention over the architecture grammar, not a new one. Semantic-pattern territory.
+- **AI-agent / RAG architecture** — same: boxes and arrows with a decision loop. A pattern over architecture, not a layout.
+- **Mindmap** — radial restatement of tree. Same information, same grammar, different projection.
+- **UML use case** — stick-figure actors and ovals inside a system boundary. A real grammar, but the ovals carry no structure and the figure rarely survives an editorial cut.
+- **Pie / donut** — the repository's own rule ("lists of anything → a table") already rejects it.
+- **Git graph and packet / bit-field** — real grammars, but narrow audiences and weak editorial fit. Revisit only on demand.
+- **Treemap** — originally rejected here, then overtaken by the implementation admitted in #87 under ADR 0002's escape clause. The 28 → 38 count includes it.
+
+## Consequences
+
+- The verifiable count moves to 38. `verify-docs-sync.py` and `verify-semantic-motion.py` both hardcode it, by design: adding a type must be a conscious edit, not a silent drift.
+- Four of the ten carry a documented, narrow exemption from §6 rule 1 (orthogonal elbows): sankey ribbons, fishbone bones, wardley dependency links, journey sentiment curves. Each exemption is scoped in its own type reference and covers that element only. The other six obey §6 in full; kanban and story map simply have no connectors.
+- **ER's scope was narrowed, not duplicated.** `type-er.md` now states that it is entity-level and points at `type-db-schema.md` for the physical schema. Without that edit the two types would have overlapping "Best for" claims and the router would be ambiguous.
+- The ADR 0004 byte cap became binding. Adding these types required trimming SKILL.md body prose: the §11 import consequences were compressed, the terminal-variant and typography paragraphs were tightened, and §4's six connector anti-pattern rows collapsed into one row pointing at §6 — that table was the third statement of rules already given in full in §6 and checked one by one in §9. `SKILL.md` sits at ~39.2 KB against the 40 KB cap. The next type must be paid for the same way, never by trimming the frontmatter description.
+- Per-type budget rows stayed in SKILL.md §7 rather than moving into the type references, because several older references (venn, pyramid, layers, ER, swimlane, timeline) do not state their own limits. Moving the rows out would have lost those numbers.
+- `docs/screenshots/` has no PNGs for the new types yet; the README lists them in a text table instead of the image grid until the screenshots are generated.
diff --git a/scripts/test-verify-motion.py b/scripts/test-verify-motion.py
index c601af4..35bc02e 100644
--- a/scripts/test-verify-motion.py
+++ b/scripts/test-verify-motion.py
@@ -402,7 +402,7 @@ def main() -> int:
missing_guide = directory / "missing-guide.md"
missing_guide.write_text(
original_skill.read_text(encoding="utf-8").replace(
- "### Visual-type guide (28)", "### Visual guide"
+ "### Visual-type guide (38)", "### Visual guide"
),
encoding="utf-8",
)
@@ -410,7 +410,7 @@ def main() -> int:
markdown_errors = semantic_module.verify_markdown()
finally:
semantic_module.SKILL = original_skill
- if not any("must contain the 28-row visual-type guide" in error for error in markdown_errors):
+ if not any("must contain the 38-row visual-type guide" in error for error in markdown_errors):
raise AssertionError(f"missing visual-guide anchor was accepted: {markdown_errors}")
print("OK: missing visual-type guide anchor is rejected")
diff --git a/scripts/verify-docs-sync.py b/scripts/verify-docs-sync.py
index e72571c..ac145fd 100644
--- a/scripts/verify-docs-sync.py
+++ b/scripts/verify-docs-sync.py
@@ -72,8 +72,8 @@ def check_description(errors: list[str]) -> None:
errors.append("SKILL.md frontmatter description is missing")
return
types = selection_table_types(markdown)
- if len(types) != 28:
- errors.append(f"expected 28 visual types in the selection table; found {len(types)}")
+ if len(types) != 38:
+ errors.append(f"expected 38 visual types in the selection table; found {len(types)}")
for name in types:
key = normalized(name)
key = DESCRIPTION_ALIASES.get(key, key)
diff --git a/scripts/verify-semantic-motion.py b/scripts/verify-semantic-motion.py
index 28d70f6..5c6450c 100644
--- a/scripts/verify-semantic-motion.py
+++ b/scripts/verify-semantic-motion.py
@@ -191,18 +191,18 @@ def verify_markdown() -> list[str]:
if "Selection: semantic pattern, then visual type" not in skill:
errors.append("SKILL.md must choose semantic pattern before visual type")
router_position = skill.find("semantic-patterns.md")
- guide_position = skill.find("### Visual-type guide (28)")
+ guide_position = skill.find("### Visual-type guide (38)")
if router_position < 0:
errors.append("SKILL.md must link to semantic-patterns.md")
if guide_position < 0:
- errors.append("SKILL.md must contain the 28-row visual-type guide")
+ errors.append("SKILL.md must contain the 38-row visual-type guide")
if router_position >= 0 and guide_position >= 0 and router_position > guide_position:
errors.append("semantic-pattern router must precede the visual-type guide")
- visual_guide = section(skill, "### Visual-type guide (28)", "Rules of thumb:")
+ visual_guide = section(skill, "### Visual-type guide (38)", "Rules of thumb:")
visual_rows = re.findall(r"^\|.*\[type-[^)]+\.md\]", visual_guide, re.MULTILINE)
- if len(visual_rows) != 28:
- errors.append(f"visual-type guide must preserve 28 rows; found {len(visual_rows)}")
+ if len(visual_rows) != 38:
+ errors.append(f"visual-type guide must preserve 38 rows; found {len(visual_rows)}")
for index, name in enumerate(PATTERN_NAMES, 1):
if name not in skill:
@@ -419,7 +419,7 @@ def main() -> int:
print(f"- {error}")
return 1
if not args.example_only:
- print("OK: 7 semantic patterns route independently to the preserved 28 visual types")
+ print("OK: 7 semantic patterns route independently to the preserved 38 visual types")
print("OK: animation modes, primitives, static fallback, and accessibility contract")
if not args.markdown_only:
print("OK: policy-trace example controls, structure, reduced motion, and unique IDs")
diff --git a/skills/diagram-design/SKILL.md b/skills/diagram-design/SKILL.md
index 8c50579..f37d2a0 100644
--- a/skills/diagram-design/SKILL.md
+++ b/skills/diagram-design/SKILL.md
@@ -1,16 +1,16 @@
---
name: diagram-design
-description: Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.
+description: Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, treemap, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, DP security matrix, Sankey, fishbone, Wardley map, kanban, user journey, deployment, dependency graph, UML class, story map, or database schema diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.
license: MIT
metadata:
- version: "2.4"
+ version: "2.5"
---
# Diagram Design
Create visual diagrams as self-contained HTML files with inline SVG and CSS, following an opinionated editorial design system.
-Twenty-eight visual types. Semantic patterns describe behavior independently; type references describe layout. Details load from `references/` only when selected.
+Thirty-eight visual types. Semantic patterns describe behavior independently; type references describe layout. Details load from `references/` only when selected.
---
@@ -49,7 +49,7 @@ Applied to schematics:
## 2. When to Use
-Use for any of the 28 visual types (§3) when a reader will learn more from a visual than from prose, a table, or a bulleted list.
+Use for any of the 38 visual types (§3) when a reader will learn more from a visual than from prose, a table, or a bulleted list.
**Don't use for:**
@@ -78,7 +78,7 @@ When behavior, state, enforcement, or risk carries the meaning, first load [`ref
The pattern owns semantic primitives and its tighter budget; the type owns layout grammar. Use [`references/animation.md`](references/animation.md) only when motion is requested or materially clarifies ordered change; static remains the default.
-### Visual-type guide (28)
+### Visual-type guide (38)
| If you're showing… | Use | Reference |
|---|---|---|
@@ -110,6 +110,16 @@ The pattern owns semantic primitives and its tighter budget; the type owns layou
| Role-scoped data flow: who does what at each pipeline step | **Data flow** | [type-data-flow.md](references/type-data-flow.md) |
| Integration topology of a data platform — sources → core → consumers | **DP integration** | [type-dp-integration.md](references/type-dp-integration.md) |
| Per-role / per-component access permissions matrix | **DP security matrix** | [type-dp-security-matrix.md](references/type-dp-security-matrix.md) |
+| A quantity splitting and merging across stages, band width = amount | **Sankey** | [type-sankey.md](references/type-sankey.md) |
+| Causes of one observed effect, grouped by category (root-cause analysis) | **Fishbone** | [type-fishbone.md](references/type-fishbone.md) |
+| Value chain against evolution — what to build, buy, and what is moving | **Wardley map** | [type-wardley.md](references/type-wardley.md) |
+| Work-in-progress by state, with WIP limits and blocked items | **Kanban** | [type-kanban.md](references/type-kanban.md) |
+| What a person does across stages of an experience, and how it feels | **User journey** | [type-journey.md](references/type-journey.md) |
+| Where software runs — zones, hosts, artifacts, replicas, ports | **Deployment** | [type-deployment.md](references/type-deployment.md) |
+| What depends on what, with fan-in and cycles a tree cannot express | **Dependency graph** | [type-dependency.md](references/type-dependency.md) |
+| Classes with operations, inheritance, composition (other UML routes elsewhere) | **UML class** | [type-uml-class.md](references/type-uml-class.md) |
+| Narrative backbone sliced into releases, with the cut line | **Story map** | [type-story-map.md](references/type-story-map.md) |
+| Physical tables: SQL types, constraints, indexes, column-level FKs | **Database schema** | [type-db-schema.md](references/type-db-schema.md) |
Rules of thumb:
@@ -142,12 +152,7 @@ These mark "AI slop" schematics of any type:
| `rounded-2xl` on boxes | Max radius 6–10px or none |
| Coral on every "important" node | Coral is 1–2 editorial accents, not a signaling system |
| Reproducing Mermaid's renderer layout | Imports automatic spacing and routing instead of making an editorial layout |
-| Diagonal / slanted connectors between off-axis nodes | Rounded right-angle (orthogonal) elbows are mandatory — see §6 Mandatory connector rules |
-| Arrow label sitting on or touching its connector | Label must have a 6–10px gap above the line so the connector stays visible |
-| Arrow label mask overlapping a node box | Nodes paint after labels — the fill clips the text into a fragment on the border. See §6 rule 6 |
-| Two connectors overlapping or running on the same path | Each connection must be independently traceable — bridge crossings, offset parallels |
-| Two connectors sharing a single attach point on a box | Fan attach points along the edge (≥12px apart) so every arrow is clearly distinct — see §6 rule 4 |
-| Connector routed behind a non-endpoint box without need | Reroute around intervening boxes; the dashed-transit exception (§6 rule 5) only applies when an unavoidable intervening box sits on the direct path |
+| Any breach of the six §6 connector rules | Diagonal slants, labels touching their stroke, masks clipped by a later node, overlapping paths, shared attach points, transit behind a non-endpoint box — each is an automatic fail; §6 states them in full |
Type-specific anti-patterns live in each `references/type-*.md`.
@@ -193,7 +198,7 @@ Type-specific anti-patterns live in each `references/type-*.md`.
- **Arrow label** — Geist Mono, 8px — annotation on arrows
- **Editorial aside** — Instrument Serif *italic*, 14px — callouts only
-**Mono is for technical content.** Names are Geist sans. Page title is Instrument Serif. Italic Instrument Serif is reserved for annotation callouts. Never JetBrains Mono as a blanket "dev" font.
+**Mono is for technical content only** — never as a blanket "dev" font, and never JetBrains Mono.
```html
@@ -383,6 +388,16 @@ Quick check: if a coordinate ends in 1, 2, 3, 5, 6, 7, 9 — fix it.
| Max series (line chart) | 5 |
| Max tasks (Gantt) | 12 |
| Max points (scatter plot) | 30 |
+| Max stages / nodes / flows (sankey) | 3 / 8 / 12 |
+| Max categories (fishbone) | 6 bones, 3 sub-causes each |
+| Max components / links (wardley) | 9 / 12, 2 movement arrows |
+| Max columns / cards (kanban) | 5 / 12 total, 4 per column |
+| Max stages / rows (user journey) | 6 / 3, 2 pain markers |
+| Max zones / nodes / paths (deployment) | 3 / 6 / 8, 9 artifacts |
+| Max nodes / edges (dependency) | 9 / 14, 4 ranks, 1 cycle |
+| Max classes / relationships (UML class) | 7 / 8, 5 members per compartment |
+| Max activities / slices / cards (story map) | 5 / 3 / 12 |
+| Max tables / columns / FKs (db schema) | 5 / 8 shown / 6 |
| Max annotation callouts | 2 |
| Max motion (optional) | 8 steps, 12 marked items, 2 simultaneous items — see [animation.md](references/animation.md) |
@@ -493,7 +508,7 @@ Every diagram ships in three variants (see `assets/`):
**Sketchy variant** (optional, applied to any of the above) — see [primitive-sketchy.md](references/primitive-sketchy.md). SVG turbulence filter wobbles strokes for a hand-drawn feel. Good for essays, not for technical docs.
-**Terminal variant** (optional, replaces any of the above) — see [primitive-terminal.md](references/primitive-terminal.md). `template-terminal.html`, `example--terminal.html`. Charcoal-black CLI-window chrome, monospace type, one red-orange accent. Good for dev-tool / CLI-product posts and technical social cards; not brand-tokenized, so skip it for onboarded/brand-matched output.
+**Terminal variant** (optional, replaces any of the above) — see [primitive-terminal.md](references/primitive-terminal.md). `template-terminal.html`, `example--terminal.html`. Charcoal CLI-window chrome, monospace, one red-orange accent. Good for dev-tool posts; not brand-tokenized, so skip it for onboarded output.
**Animation** (optional presentation layer) — see [animation.md](references/animation.md). Modes are `none` (default), `reveal`, `step`, and `loop`; motion never changes the static meaning or raises the complexity budget.
@@ -531,10 +546,7 @@ Every imported diagram is shaped by four decisions. Full spec in [`references/ou
| **Detail** | `faithful` (≤24 nodes, zoned) · `balanced` (≤12) · `simplified` (≤7) | `balanced` |
| **Audience** | `engineer` · `mixed` · `executive` — governs wording, not count | `mixed` |
-Two consequences worth remembering here:
-
-- The size preset sets the `viewBox` **and** the type ramp. A slide gets 16px node names, not 12px — scaling the canvas without scaling the type is how projected diagrams end up unreadable.
-- `faithful` is the one documented exemption from the §7 complexity budget, and it's conditional: above 9 nodes the layout must be zoned, above 24 it must split into overview + detail. The connector rules in §6 never relax.
+Two consequences: the size preset sets the `viewBox` **and** the type ramp (a slide gets 16px node names, not 12px), and `faithful` is the only exemption from the §7 budget — conditional, zoned above 9 nodes, split above 24. The §6 connector rules never relax.
---
diff --git a/skills/diagram-design/assets/example-db-schema-dark.html b/skills/diagram-design/assets/example-db-schema-dark.html
new file mode 100644
index 0000000..b3d5a12
--- /dev/null
+++ b/skills/diagram-design/assets/example-db-schema-dark.html
@@ -0,0 +1,302 @@
+
+
+
+
+
+ Commerce schema · database schema
+
+
+
+
+
The physical schema behind checkout: five tables, real SQL types, and foreign keys that anchor column to column, not box to box. The dashed group marks the non-default `billing` schema.
+
+
+
+
+
+
+
+
+
THE DESTRUCTIVE EDGE
+
Deleting an order cascades
+
`order_items.order_id` is the one `ON DELETE CASCADE` in this schema — remove an order and its line items go with it. Every other foreign key is `RESTRICT`.
+
+
+
Column to column, not box to box
+
Every FK anchors to a specific row on both ends
Fixed 24px row height keeps anchors predictable
The `ON DELETE` label is the point of the edge
+
+
+
Scoped to the subsystem
+
`products` truncates to a `+ 3 more columns` row rather than dumping every column. This is checkout, not a `\d+` of the whole database.
Nine packages, ranked by dependency depth. A tree can't show what matters here — that shared-types has four dependents, or that utils depends back on it. Coral is spent on exactly that cycle.
+
+
+
+
+
+
+
+
+
THE HEADLINE
+
One cycle, spent deliberately
+
Coral appears exactly twice: the dashed back-edge from utils into shared-types, and its CYCLE label. Everything else — including the four-dependent fan-in on shared-types — stays ink and muted, because only the cycle is the editorial point.
+
+
+
Why not a tree
+
shared-types has four parents, not one
utils depends back on its own ancestor
a tree can render neither honestly
+
+
+
Read the badges
+
The small N IN chip on every node is the fan-in count. It's the fastest way to spot where a change ripples widest before reading a single arrow.
Edge caching absorbs the reads, three ingress-fronted API pods handle the writes, and a single Postgres primary streams WAL to a standby in the data zone.
+
+
+
+
+
+
+
+
+
THE HEADLINE
+
One primary, one point of failure
+
Every write lands on `rds-primary`. The standby streams WAL continuously but isn't hot — a primary failure is the one scenario this topology hasn't automated away yet.
+
+
+
Three replicas behind one ingress
+
`checkout-api` runs 3 pod replicas
`sidecar-otel` ships traces from the same pod
nginx-ingress fans requests across all three
+
+
+
Edge absorbs static reads
+
Cloudflare's edge cache serves cached responses directly; only cache misses and writes reach the ingress zone.
Five candidate cause categories investigated after a 90-minute checkout latency incident. The confirmed root cause carries the diagram's only accent — everything else stays in the neutral ink/muted palette so the reader's eye lands on the answer, not the investigation.
+
+
+
+
+
+
+
+
+
ROOT CAUSE
+
Data — missing index
+
No index on orders.created_at; the query planner fell back to a sequential scan once the table crossed 3x its forecast size. The single confirmed cause — every other category was ruled out.
+
+
+
Contributing categories
+
Deploy (canary skipped, config drift), Runtime (pool cap 20, GC pauses), and Observability (no p99 alert, 5-minute dashboard sampling) all slowed detection but didn't cause the regression themselves.
+
+
+
People
+
A mid-incident on-call handover cost roughly ten minutes of context — worth fixing, not the root cause.
+
+
diff --git a/skills/diagram-design/assets/example-journey-dark.html b/skills/diagram-design/assets/example-journey-dark.html
new file mode 100644
index 0000000..1111ff0
--- /dev/null
+++ b/skills/diagram-design/assets/example-journey-dark.html
@@ -0,0 +1,148 @@
+
+
+
+
+
+ Trial to paid: the first week · User journey map
+
+
+
+
+
+
User journey · Diagram Design
+
Trial to paid: the first week
+
+
+
+
+
diff --git a/skills/diagram-design/assets/example-journey-full.html b/skills/diagram-design/assets/example-journey-full.html
new file mode 100644
index 0000000..58c6e2f
--- /dev/null
+++ b/skills/diagram-design/assets/example-journey-full.html
@@ -0,0 +1,142 @@
+
+
+
+
+
+ Trial to paid: the first week · User journey map
+
+
+
+
+
+
+
User journey · Diagram Design
+
Trial to paid: the first week
+
One persona, five stages from signup to upgrade. The sentiment curve is the point: a confident start, a dip when the free-tier export limit hits with no warning, and a recovery once the team upgrades.
+
+
+
+
+
+
+
+
+
TROUGH
+
Hit the limit
+
The export cap arrives with zero warning at 80% usage, and the only way out is a pricing page that's three clicks from the blocked screen. This is the one stage worth fixing before anything else.
+
+
+
Recovery, not just relief
+
Sentiment climbs back to neutral at upgrade rather than back to high — the friction is remembered. Track this cohort's 90-day retention separately from users who never hit the limit.
+
+
+
Early signal
+
Sign up and invite team both read high. The trial's first impression is working; the problem is entirely mid-funnel.
+
+
+
+
+
+
+
diff --git a/skills/diagram-design/assets/example-journey.html b/skills/diagram-design/assets/example-journey.html
new file mode 100644
index 0000000..c7aed44
--- /dev/null
+++ b/skills/diagram-design/assets/example-journey.html
@@ -0,0 +1,148 @@
+
+
+
+
+
+ Trial to paid: the first week · User journey map
+
+
+
+
+
A state census of platform-team work, not a flow — no connectors, just where each ticket sits and whether a column is over its WIP limit. In progress is running one over budget, and one ticket is stuck on a vendor maintenance window.
+
+
+
+
+
+
+
+
+
OVER LIMIT
+
In progress · 4/3
+
One ticket over the stated cap, and the reason isn't throughput — it's Postgres 16 upgrade, blocked on a vendor maintenance window. Pulling more work in won't help until that window opens.
+
+
+
Review · 2/3
+
Under limit, but one of the two cards is waiting on an external vendor SSO integration rather than internal review time — worth tracking separately from cards actually being reviewed.
+
+
+
Done
+
Capped at two visible entries; older completions roll off the board rather than accumulating indefinitely.
12,000 CI minutes split across four pipeline stages, then merge into three outcomes. Band thickness is the data — the flaky-rerun path is the only colored ribbon, because it's the line item worth cutting.
+
+
+
+
+
+
+
+
+
EDITORIAL POINT
+
Flaky reruns
+
1,000 of the 12,000 monthly minutes — about 8% of the whole budget — go to tests that failed once and passed on rerun. That's the one line item this diagram argues for cutting.
+
+
+
Where the minutes go
+
Unit tests and E2E together are three-quarters of the budget (9,200 of 12,000 minutes). Build and lint are comparatively cheap at 1,900 and 900.
+
+
+
Net outcome
+
9,400 minutes pass clean, 1,600 fail for real. The remaining 1,000 are pure overhead — neither signal nor failure, just retries.
+
+
diff --git a/skills/diagram-design/assets/example-story-map-dark.html b/skills/diagram-design/assets/example-story-map-dark.html
new file mode 100644
index 0000000..2815f1b
--- /dev/null
+++ b/skills/diagram-design/assets/example-story-map-dark.html
@@ -0,0 +1,184 @@
+
+
+
+
+
+ Reporting, first release · User story map
+
+
+
+
+
+
User story map · Diagram Design
+
Reporting, first release
+
+
+
+
+
diff --git a/skills/diagram-design/assets/example-story-map-full.html b/skills/diagram-design/assets/example-story-map-full.html
new file mode 100644
index 0000000..05c1854
--- /dev/null
+++ b/skills/diagram-design/assets/example-story-map-full.html
@@ -0,0 +1,188 @@
+
+
+
+
+
+ Reporting, first release · User story map
+
+
+
+
+
+
+
User story map · Diagram Design
+
Reporting, first release
+
Narrative order runs left to right — find the data, build the report, share it, trust it — while priority runs top to bottom. The release-cut line under MVP is the editorial point: everything above it ships first, and the riskiest bet, row-level permissions, lands in Release 2.
+
+
+
+
+
+
+
+
+
RELEASE CUT
+
MVP · 4 stories
+
Keyword search, a table with one chart, a public link, and a last-updated stamp — enough to answer "what is the whole story" without shipping every activity's full depth. Everything below the cut line waits.
+
+
+
Release 2 · 3 stories
+
Saved filters and scheduled email round out the workflow, but row-level permissions is the riskiest bet in the map — untested access-control logic sitting right after the cut, not buried in "Later".
+
+
+
Later · 2 stories
+
Natural-language query and anomaly alerting are named and ordered, not promised — three slices is the ceiling before nobody believes the sequencing anymore.
+
+
+
+
+
+
+
diff --git a/skills/diagram-design/assets/example-story-map.html b/skills/diagram-design/assets/example-story-map.html
new file mode 100644
index 0000000..cb8c810
--- /dev/null
+++ b/skills/diagram-design/assets/example-story-map.html
@@ -0,0 +1,184 @@
+
+
+
+
+
+ Reporting, first release · User story map
+
+
+
+
+
PaymentMethod is the contract two payment methods realize. Order composes its line items and references a customer. PaymentService only depends on the interface, never the concrete methods.
+
+
+
+
+
+
+
+
+
THE HEADLINE
+
PaymentMethod is the contract
+
Card and BankTransfer both realize the interface — the dashed line with the hollow triangle. PaymentService only ever talks to the interface, never to a concrete method.
+
+
+
Composition means it dies with the whole
+
OrderLine has no life outside an Order
Filled diamond sits at Order, the owner
Order also just references Customer — no shared lifecycle there
+
+
+
What's deliberately left out
+
No getters or setters, no full attribute lists. Every member shown earns its place in the argument this diagram is making.
The value chain behind an AI assistant, from the user-facing need down to raw infrastructure, positioned against how evolved each component is. The one arrow is the map's point: agent orchestration is commoditising, so betting engineering time on a bespoke orchestrator is a shrinking advantage.
+
+
+
+
+
+
+
+
+
MOVEMENT
+
Agent orchestration
+
Still custom-built today, but the open-source orchestration frameworks maturing this year push it toward product. Betting differentiation here has a shrinking half-life.
+
+
+
Eval harness
+
Genesis-stage and specific to this product's failure modes. No off-the-shelf harness captures what "good" means for this assistant yet — worth the custom build.
+
+
+
GPU compute · Object storage
+
Fully commoditised. Buy, don't build — any engineering time spent here is time not spent on the parts of the chain that are still genesis or custom-built.
+
+
diff --git a/skills/diagram-design/assets/index.html b/skills/diagram-design/assets/index.html
index f1ec0b0..c3a0431 100644
--- a/skills/diagram-design/assets/index.html
+++ b/skills/diagram-design/assets/index.html
@@ -288,29 +288,59 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/skills/diagram-design/references/onboarding.md b/skills/diagram-design/references/onboarding.md
index f0c6ec8..4786cd3 100644
--- a/skills/diagram-design/references/onboarding.md
+++ b/skills/diagram-design/references/onboarding.md
@@ -159,7 +159,7 @@ Write the new tokens to `style-guide.md`. Suggest running the `/regenerate-examp
After onboarding, the user should:
-1. Open `assets/index.html` (gallery) and confirm the new palette feels coherent across all 28 types.
+1. Open `assets/index.html` (gallery) and confirm the new palette feels coherent across all 38 types.
2. If any type looks off, they usually need to tune `muted` (often too dark or too light against the new `paper`).
---
diff --git a/skills/diagram-design/references/semantic-patterns.md b/skills/diagram-design/references/semantic-patterns.md
index 96b6274..d44598c 100644
--- a/skills/diagram-design/references/semantic-patterns.md
+++ b/skills/diagram-design/references/semantic-patterns.md
@@ -1,6 +1,6 @@
# Semantic patterns
-Semantic patterns describe **what a system does**; the 28 visual types describe **how information is arranged**. Choose a pattern first when behavior, state, enforcement, or risk is load-bearing, then use its nearest visual type as the layout grammar. If no pattern matches, choose a visual type directly.
+Semantic patterns describe **what a system does**; the 38 visual types describe **how information is arranged**. Choose a pattern first when behavior, state, enforcement, or risk is load-bearing, then use its nearest visual type as the layout grammar. If no pattern matches, choose a visual type directly.
Use one primary pattern per figure. A second pattern may supply at most one supporting primitive; if both need full treatment, split overview and detail. Labels and outcomes must remain complete in a static frame.
diff --git a/skills/diagram-design/references/type-db-schema.md b/skills/diagram-design/references/type-db-schema.md
new file mode 100644
index 0000000..0f0a815
--- /dev/null
+++ b/skills/diagram-design/references/type-db-schema.md
@@ -0,0 +1,48 @@
+# Database Schema
+
+**Best for:** the *physical* schema — real tables, real SQL types, real constraints, real indexes, and foreign keys that connect one column to another column. It's the DDL made legible: migrations, review of a real database, and anything where the column type or the `ON DELETE` behavior is the point.
+
+**Not for domain modeling.** [ER / data model](type-er.md) is entity-level: relationship lines join *boxes* and carry cardinality, fields are a plain list, and it's the right tool for a conceptual or domain conversation. Database schema is column-level: the FK connector anchors to the specific column row on both ends — the one capability ER doesn't have, and the reason this type exists. If you're discussing what an Order *is*, use ER. If you're discussing what happens when a row is deleted, use this.
+
+## Layout conventions
+
+### Table box
+
+- **Header band** — `schema.table` (e.g. `public.orders`) in Geist sans 12px weight 600, with a rectangular type tag (`rx=2`, NOT a pill) reading `TABLE`. A hairline separates it from the body.
+- **Column rows** — fixed 24px row height so connectors can anchor predictably. Each row: column name in Geist sans 12px anchored left, SQL type in Geist Mono 9px `muted` anchored right (`uuid`, `text`, `numeric(12,2)`, `timestamptz`), and constraint chips between them as small `rx=2` tags in Geist Mono 8px: `PK`, `FK`, `UQ`, `NN`. Alternate row background `ink @ 0.02` on even rows for scannability.
+- **Overflow row** — when a table has more columns than the budget allows, the last row is a Geist Mono 9px `muted` line: `+ N more columns`. Never silently truncate a table without saying so.
+- **Index compartment** — an optional final compartment separated by a hairline, labelled with a Geist Mono 8px uppercase `INDEXES` eyebrow, listing index names in Geist Mono 9px (`idx_orders_customer_id`, `uq_products_sku`). List only the indexes that matter to the story, not every index on the table.
+
+### Foreign-key connectors — the defining rule
+
+Each FK edge starts at the **vertical centre of its source column row** and ends at the **vertical centre of the referenced column row**, routed with orthogonal rounded elbows (see SKILL.md §6 and [type-architecture.md](type-architecture.md) for the elbow formula and bridge/hop primitive). Label each edge in Geist Mono 8px with its referential action — `ON DELETE CASCADE`, `ON DELETE RESTRICT`, `ON DELETE SET NULL` — masked with the standard 6–10px gap. Fixed 24px row height guarantees ≥12px separation only when two FKs attach to *different* rows on the same table edge — the row spacing itself is the fan. When two or more FKs attach to the *same* row on the same edge (e.g. two child tables both referencing the same parent's primary key), anchoring all of them at the exact row centre would collide at a single point, which SKILL.md §6 rule 4 forbids. Offset each attach point symmetrically around the row's vertical centre instead — ±8px for two edges, keeping every point inside the row's 24px band and ≥12px from its neighbor — so each connector still reads as attaching to that row while remaining independently traceable.
+
+### Schema grouping
+
+Tables in a non-default schema sit inside a containment rect (`rx=8`, `ink @ 0.02` fill, `ink @ 0.20` stroke dashed `4,4`) with a Geist Mono 8px uppercase tracked schema label in its top-left corner. Draw the group rect first so tables paint over it.
+
+### Focal rule
+
+The 2 accent elements are: (1) the one destructive FK (`ON DELETE CASCADE`) — the edge and its label count together, since a labelled edge is one thing; and (2) the table that FK cascades into, carrying `accent-tint` on its **header band only**, never on the whole box. Nothing else on the diagram is `accent`.
+
+If a schema has no destructive FK, it has no focal element. Leave it unaccented rather than promoting an arbitrary table.
+
+## Complexity budget
+
+Max 5 tables, max 8 column rows shown per table, max 6 FK edges, max 2 accent elements. Over budget → show the subsystem, not the database, and say so in a caption.
+
+## Anti-patterns
+
+- Drawing every column of every table — a schema diagram is an argument about a subsystem, not a `\d+` dump.
+- FK lines that connect box to box instead of column to column — that's ER, use ER instead.
+- Missing SQL types — the type is half the content.
+- Unlabelled FK edges — the `ON DELETE` behavior is what a reviewer is looking for.
+- Constraint chips on every row until the chips are the noise.
+- Index compartments listing every index rather than the ones that matter to the story.
+- Mixing conceptual entity names with physical table names in one diagram.
+
+## Examples
+
+- `assets/example-db-schema.html` — minimal light
+- `assets/example-db-schema-dark.html` — minimal dark
+- `assets/example-db-schema-full.html` — full editorial
diff --git a/skills/diagram-design/references/type-dependency.md b/skills/diagram-design/references/type-dependency.md
new file mode 100644
index 0000000..249ec8f
--- /dev/null
+++ b/skills/diagram-design/references/type-dependency.md
@@ -0,0 +1,44 @@
+# Dependency Graph
+
+**Best for:** what depends on what, across packages, modules, or services — specifically to show two things a **tree** cannot structurally express: (a) a node with **more than one parent** (a shared dependency that several things converge on), and (b) a **cycle**. If neither appears in the data — every node has exactly one parent and nothing points backward — use [Tree](type-tree.md) instead; say so explicitly rather than forcing a graph layout on tree-shaped data.
+
+## Layout conventions
+
+- **Ranked layers.** Nodes sit in horizontal rank rows by dependency depth: rank 0 (entry points nothing depends on) at the top, deeper ranks below. Forward edges point downward across ranks, or run horizontal within a single rank row when a dependency compresses to the same depth as its dependent (e.g. a shallow sibling dependency) — never upward outside the one marked cycle. Rank rows are 120px apart.
+- Nodes are the standard node-box pattern (§6): `rx=6`, 160px wide, 56px tall.
+- **Fan-in badge.** Every node carries a Geist Mono 8px badge in its top-right corner, inside a small `rx=2` box, showing how many nodes depend on it (`4 in`). A mask fully inside a node is a badge chip, not a label — legitimate under §6 rule 6. The node with the highest fan-in is the diagram's structural story; size nothing else to compete with it.
+- **Node treatments** (§5 Node type → treatment):
+ - Internal package/service → white fill + `ink` stroke.
+ - External / third-party → `ink @ 0.03` fill + `ink @ 0.30` stroke (the External/Cloud treatment).
+ - Leaf with no outgoing edges → `ink @ 0.05` fill + `muted` stroke.
+- **The cycle.** At most one back-edge points upward against rank order. It is the editorial point of the diagram: `accent` stroke, dashed `5,4`, `marker-end="url(#arrow-accent)"`, routed **around the outside** of the node stack — never straight through the middle, and never behind a node it doesn't connect to — with a masked Geist Mono 8px `CYCLE` label at its visible end. The two nodes the cycle touches stay in their normal node treatment (§5) — no accent stroke or fill on the nodes themselves, or the 2-accent budget is blown on the wrong elements.
+- **Focal rule:** the 2 accent elements permitted per diagram are the back-edge and its `CYCLE` label. Nothing else in a dependency graph is accent.
+- All six §6 Mandatory connector rules apply in full, no exemptions: rounded right-angle elbows (`r=8`) between off-axis nodes, 6–10px label-margin, no overlapping connectors (bridge/hop at crossings), fanned attach points (≥12px apart) where multiple edges share a box edge, no connector passing behind a non-endpoint box, no label mask clipped by a later-painted node.
+
+## Complexity budget
+
+| Limit | Rule |
+|---|---|
+| Max nodes | 9 |
+| Max edges | 14 |
+| Max rank layers | 4 |
+| Max highlighted cycles | 1 |
+| Max accent elements | 2 |
+
+Over budget: collapse a leaf cluster into one aggregate node labelled with its count (e.g. `+6 leaves`), and say so in a caption — don't silently drop nodes.
+
+## Anti-patterns
+
+- Drawing a dependency graph when the data is actually a tree (single parent everywhere, no cycles) — use Tree instead.
+- Forward edges that point upward without being the one marked cycle.
+- A hairball layout with no rank ordering — rank first, always; ranking is what makes the graph readable, not an optional polish pass.
+- One node per file instead of per package/module/service — the graph is about dependency structure, not the filesystem.
+- Unlabelled external dependencies — version or registry belongs in the Geist Mono sublabel (`v3.23 · npm`), not left implicit.
+- Highlighting more than one cycle in a single diagram — pick the one that matters editorially; a second cycle competes with the first and neither reads.
+- Omitting the fan-in badges — without them the reader can't see at a glance where dependencies concentrate, which is the entire reason this type exists over a plain tree.
+
+## Examples
+
+- `assets/example-dependency.html` — minimal light
+- `assets/example-dependency-dark.html` — minimal dark
+- `assets/example-dependency-full.html` — full editorial
diff --git a/skills/diagram-design/references/type-deployment.md b/skills/diagram-design/references/type-deployment.md
new file mode 100644
index 0000000..8907ccb
--- /dev/null
+++ b/skills/diagram-design/references/type-deployment.md
@@ -0,0 +1,45 @@
+# Deployment
+
+**Best for:** where the software actually *runs* — hosts, VMs, pods, and managed services placed inside environment or network-boundary zones, with replica counts and versioned artifacts called out. Architecture answers "what talks to what"; deployment answers "what is installed on which host, in which environment, behind which network boundary, at how many replicas." If the diagram has no physical-placement decision to show — no zone boundary, no replica count, no version that matters — use `type-architecture.md` instead; redrawing the logical architecture with hostnames bolted on is the most common deployment anti-pattern.
+
+## Layout conventions
+
+Three nesting levels, outermost to innermost — reuses the containment grammar from `type-nested.md`, specialized for infrastructure:
+
+1. **Zone** — an environment or network boundary (`edge`, `prod / eu-west-1`, `data`). A large rect, `rx=8`, fill `ink @ 0.02`, stroke `ink @ 0.20` dashed `4,4`. A Geist Mono 8px (or 7px for tight layouts) uppercase tracked eyebrow label sits inside the top-left corner, on a paper-colored mask over the border. Zones are drawn **first** — before arrows and nodes — so labels and boxes paint over them (z-order: bg → zones → arrows → labels → nodes).
+2. **Infrastructure node** — a host, VM, pod, or managed service inside a zone. The §6 node-box pattern (SKILL.md) at `rx=6`, with a rectangular type tag (`rx=2`, **not** a pill) carrying `POD` / `VM` / `MANAGED` / `CDN` in the top-left corner.
+3. **Artifact chip** — what is deployed onto that node. A small 24px-tall rect `rx=4`, fill `ink @ 0.05`, stroke `muted`, holding the image or service name in Geist sans 12px (left-aligned) plus a Geist Mono 9px version tag (right-aligned, e.g. `v2.4.1`). A node can carry more than one chip (stacked with an 8px gap) when more than one artifact is co-located (a sidecar, for example).
+
+**Replica badge.** A node running N copies carries a right-aligned Geist Mono 8px badge (`x3`) inside its own small `rx=2` box in the node's top-right corner. A mask fully inside a node is a badge chip and is a legitimate exception to the "mask must not overlap a later node" rule (SKILL.md §6 rule 6) — it's part of that same node.
+
+**Network paths.** Orthogonal elbows between nodes (SKILL.md §6, elbow formula and port-selection rules in `type-architecture.md`), labelled with protocol and port in Geist Mono 8px (`HTTPS:443`, `TLS:5432`). A path that crosses a zone boundary is `link`-blue; a path that stays inside one zone is `muted`. Async or replication paths are dashed `5,4`.
+
+**Focal rule.** The 2 accent elements are the single-point-of-failure or the newly-introduced piece — never more than 2. In the canonical example: the RDS primary (accent-tint fill, accent stroke) and the replication path to its standby (accent, dashed).
+
+## Complexity budget
+
+| Limit | Rule |
+|---|---|
+| Max zones | 3 |
+| Max infrastructure nodes | 6 |
+| Max artifact chips | 9 |
+| Max network paths | 8 |
+| Max accent elements | 2 |
+
+Over budget → split into one deployment diagram per environment.
+
+## Anti-patterns
+
+- Redrawing the logical architecture with hostnames bolted on. If no placement decision is visible (which host, which zone, how many replicas), use `type-architecture.md` instead.
+- Zones that are just visual grouping with no boundary meaning — a zone must be a real environment or network boundary, not a layout convenience.
+- Artifact chips without a version tag. The version is why the diagram exists; an unversioned chip is a wasted box.
+- One node drawn per replica instead of a single node with a replica badge.
+- Cloud-vendor icon soup standing in for named nodes — name the host or service, don't decorate it.
+- Unlabelled network paths. Protocol and port are the content of a deployment diagram, not decoration.
+- Mixing two environments in one diagram (e.g. staging and production nodes side by side without a zone boundary that actually separates them).
+
+## Examples
+
+- `assets/example-deployment.html` — minimal light
+- `assets/example-deployment-dark.html` — minimal dark
+- `assets/example-deployment-full.html` — full editorial
diff --git a/skills/diagram-design/references/type-er.md b/skills/diagram-design/references/type-er.md
index 7d91ffe..5def3a7 100644
--- a/skills/diagram-design/references/type-er.md
+++ b/skills/diagram-design/references/type-er.md
@@ -1,6 +1,8 @@
# ER / Data Model
-**Best for:** database schemas, API resource relationships, domain models.
+**Best for:** conceptual and logical data models, API resource relationships, domain models — anything where the story is *entities and cardinality*.
+
+**Not for the physical schema.** ER is entity-level: relationship lines join *boxes* and carry cardinality at each end. When the point is real tables with SQL types, constraint chips, indexes, and foreign keys that anchor **column to column**, use [`type-db-schema.md`](type-db-schema.md) instead.
## Layout conventions
- Each entity is a two-section box:
diff --git a/skills/diagram-design/references/type-fishbone.md b/skills/diagram-design/references/type-fishbone.md
new file mode 100644
index 0000000..f4a0a4c
--- /dev/null
+++ b/skills/diagram-design/references/type-fishbone.md
@@ -0,0 +1,75 @@
+# Fishbone / Ishikawa (root-cause)
+
+**Best for:** structured root-cause analysis. One observed effect, causes grouped by category, sub-causes hanging off each category. The standard artefact of an incident post-mortem — use it when a reader needs to see *what was investigated*, not just the conclusion.
+
+## Layout conventions
+
+- **Spine.** A horizontal line (`ink`, 1.2px) runs left→right at the vertical centre `CY`, terminating with an arrowhead into an **effect box** at the right head — the node-box pattern from SKILL.md §6, the observed-effect statement inside.
+- **Bones.** Category lines are straight diagonals at a fixed **60°** to the spine, alternating above and below, evenly spaced along it. Each bone carries its category name at the outer end in a small tag-style box (`rx=4`, not a pill) — Geist sans 12px weight 600.
+- **Sub-causes.** Short horizontal ticks (32px, `soft`) branch off each bone at fixed points along its length, each with a sub-cause label in Geist Mono 9px sitting past the open end of the tick.
+- **Diagonal exemption.** SKILL.md §6 rule 1 (mandatory rounded right-angle elbows) does not apply to the 60° bones — they are this type's defining grammar. The exemption covers **bones and sub-cause ticks only**; any other connector in a fishbone diagram (e.g. a callout leader, a cross-reference arrow) still uses rounded right-angle elbows.
+- **Focal rule.** Exactly one bone is the confirmed root cause: its line is `accent`, and its category tag uses `accent-tint` fill + `accent` stroke. The effect box is styled the same way (`accent-tint` fill, `accent` stroke) since it's the diagram's headline. That pair — root-cause bone and effect box — is the full 2-accent budget; every other bone, tag, and tick stays `ink` / `muted` / `soft`.
+- **Drawing order:** background → spine → bones → sub-cause ticks → category tag boxes → effect box → legend. Lines before boxes, so box fills cap the line ends cleanly.
+
+## Math
+
+For a spine at `y = CY` with the effect box's left edge at `x = HEAD`, bone `k` (1-indexed, k = 1..6) attaches to the spine at:
+
+```
+attach_x(k) = HEAD - 160 - k * 160
+```
+
+Bones alternate above (`k` odd) and below (`k` even) the spine. A bone's far endpoint — where the category tag sits — is the integer-rounded 60° offset from its attach point:
+
+```
+dx = -96
+dy = ∓168 (minus = above, plus = below)
+far_x(k) = attach_x(k) + dx
+far_y(k) = CY ∓ 168
+```
+
+### Pre-computed reference (5-bone layout, HEAD=1200, CY=320)
+
+| Bone `k` | Category slot | Side | `attach_x` | `far_x, far_y` |
+|---|---|---|---|---|
+| 1 | first | above | 880 | 784, 152 |
+| 2 | second | below | 720 | 624, 488 |
+| 3 | third | above | 560 | 464, 152 |
+| 4 | fourth | below | 400 | 304, 488 |
+| 5 | fifth | above | 240 | 144, 152 |
+
+A 6th bone (below) would attach at `x=80`, far endpoint `(-16, 488)`, and its category tag would run from `x=-76` to `x=44` against a viewBox that starts at `x=-40`. It clips. **Five is the ceiling at `HEAD=1200`**: to draw a 6th, widen `HEAD` *and* the viewBox width by at least 160 each, keeping the viewBox origin at `-40`. Both have to move together — widening `HEAD` alone pushes the 200px effect box to `1360..1560` past the `1440` right edge, trading a clipped tag on the left for a clipped effect on the right. Or drop a category.
+
+**Sub-cause ticks** sit at fractions `m/6` along the bone (`m = 2, 4` for two ticks; `m = 3` for one), so their coordinates stay on the 4px grid:
+
+```
+tick_x(k, m) = attach_x(k) - 16 * m
+tick_y(k, m) = CY ∓ 28 * m
+```
+
+The tick itself is a 32px horizontal line from `(tick_x, tick_y)` to `(tick_x - 32, tick_y)`; the label sits past its open end, `text-anchor="end"` at `x = tick_x - 36`, `y = tick_y - 4` (above-bones) or `tick_y + 12` (below-bones).
+
+## Complexity budget
+
+| Limit | Rule |
+|---|---|
+| Max categories (bones) | 5 at `HEAD=1200`. A 6th requires a widened canvas — see Geometry |
+| Max sub-causes per bone | 3 |
+| Max sub-causes total | 18 |
+| Max accent elements | 2 (root-cause bone+tag, effect box) |
+
+## Anti-patterns
+
+- **More than 5 bones on the default canvas.** The 6th tag clips the viewBox. Widen `HEAD` and the viewBox width together and deliberately, or split by subsystem into two fishbones.
+- **Sub-causes that restate the category.** A "Deploy" bone with a sub-cause labeled "deployment issue" adds a node without adding information.
+- **A bone with zero sub-causes.** An empty category is a placeholder, not a finding — delete the bone or don't draw it until there's something under it.
+- **Accenting more than one root cause.** If two categories are both confirmed, that's two diagrams (or a merged cause) — not two accent bones. The 2-accent budget is load-bearing for the "this is the answer" signal.
+- **Using fishbone for a sequence of failures.** A chain of things that happened in order is a timeline or sequence diagram — fishbone is for causes of *one* effect, not a chronology.
+- **Pasting in the classic 6M template (Man/Machine/Material/Method/Measurement/Environment) with empty categories.** Name categories from the actual investigation, not a generic checklist waiting to be filled in later.
+- **Effect box phrased as a solution.** "Add a p99 alert" is a fix, not an observed effect. The box states what was seen — a symptom, a measurement, an incident — never the remedy.
+
+## Examples
+
+- `assets/example-fishbone.html` — minimal light. Checkout p99 latency incident, 5 categories, Data confirmed as root cause.
+- `assets/example-fishbone-dark.html` — minimal dark, same data.
+- `assets/example-fishbone-full.html` — full editorial: container framing + 3 summary cards of varied widths + footer.
diff --git a/skills/diagram-design/references/type-journey.md b/skills/diagram-design/references/type-journey.md
new file mode 100644
index 0000000..a53101b
--- /dev/null
+++ b/skills/diagram-design/references/type-journey.md
@@ -0,0 +1,53 @@
+# User Journey Map
+
+**Best for:** what a person does across the stages of an experience and how it *feels* at each one. The sentiment curve is the load-bearing element — without it this is just a process diagram with extra rows, so if you can't name a sentiment for every stage, use **Process** or **Timeline** instead.
+
+## Layout conventions
+
+Vertical stack, top to bottom, for one persona:
+
+- **Stage headers** — 5 equal columns, 200px wide, 24px gutters (max 6 stages). Each column: a Geist Mono 8px uppercase tracked eyebrow (`STAGE 1` … `STAGE 5`) over the stage name in Geist sans 12px weight 600, both centered on the column.
+- **Sentiment band (the differentiator)** — a 160px-tall plot area directly under the headers. 3 horizontal reference hairlines at `rule` 0.10 opacity mark the levels `HIGH` / `NEUTRAL` / `LOW` — Geist Mono 8px `muted`, anchored `end` in a 64px left margin. **Never emoji, never `writing-mode` vertical text for these labels.** A smooth `muted` 1.5px polyline runs through one `r=5` dot per stage, each value snapped to one of five ordinal levels (`HIGH`, `MED-HIGH`, `NEUTRAL`, `MED-LOW`, `LOW`) — only the three that are actually used need a labeled hairline. The trough stage's dot and its incoming segment are `accent`; everything else on the curve is `muted`.
+- **Content rows** — up to 3 labelled bands below the sentiment band, each with a Geist Mono 8px uppercase row label sitting in the left margin (same column as the sentiment level labels, never rotated):
+ - `ACTIONS` — what the user does, Geist sans 12px, one short line per stage.
+ - `TOUCHPOINTS` — the surface the action happens on (email, app, docs…), Geist Mono 9px `muted`.
+ - An optional third row for a metric or owner, same treatment as touchpoints.
+ Rows are separated by hairlines that span the full plot width (from the left margin edge to the last stage's right edge).
+- **Pain markers** — on stages where sentiment drops, a small dashed-stroke tag box (`rx=2`, `accent @ 0.50` stroke dashed `3,3`, no fill or a faint accent tint) sits under that stage's actions cell, with a Geist Mono 8px label naming the friction. Max 2 per diagram, and only on the trough — tagging every stage erases the signal.
+- **Legend** — horizontal strip at the bottom per the global rule (hairline separator above, 160–180px between entries): three keys, in order — the sentiment line, the trough-stage highlight, and the pain-marker tag. The trough key is not optional: the dip is the finding, so the reader needs the highlight named.
+
+## Connector note
+
+The sentiment polyline is a **data curve**, not a connector between nodes — §6 rule 1 (mandatory orthogonal elbows) does not apply to it. This exemption covers the sentiment curve **only**; any other connector in a journey map (there normally are none) still follows the standard connector rules.
+
+## Geometry
+
+- Stage grid: left margin 64px, then 5 columns of 200px with 24px gutters (`col_left = 64 + i·224`).
+- Sentiment band: 160px tall. Hairlines at the top (`HIGH`), middle (`NEUTRAL`), and bottom (`LOW`) of the band, 80px apart.
+- Dot x = the horizontal center of its stage column. Dot y = the snapped level's hairline y (or the interpolated position for an unlabeled level).
+- Row height: enough for one line of text plus, in the `ACTIONS` row only, up to two stacked 16px-tall pain-marker boxes.
+
+## Focal rule
+
+Exactly 2 accent elements: the trough dot + its incoming curve segment (counts as one), and its pain marker(s) (counts as the other). Nothing else on the map is `accent`.
+
+## Complexity budget
+
+Max 6 stages · max 3 content rows · 5 sentiment levels (ordinal, named — never numeric) · max 2 pain markers · max 2 accent elements.
+
+## Anti-patterns
+
+- **No sentiment curve.** If every stage feels the same, or you can't name a feeling, you're drawing a process — use **Process** or **Timeline**.
+- **More than 6 stages.** Split into two journeys (e.g. acquisition and retention) rather than cramming a wide funnel into one map.
+- **Numeric sentiment axis** (a 0–100 score). Sentiment here is ordinal — five named levels, not a chart of a continuous metric.
+- **Emoji as sentiment markers.** Use the named levels and hairlines; emoji don't localize, print, or hold up at small sizes.
+- **Multiple personas on one map.** Overlaying two sentiment curves erases both. One map per persona.
+- **Pain markers on every stage.** If nothing is un-marked, nothing is focal.
+- **`writing-mode` vertical row labels.** Horizontal only, in the left margin — same rule as every other type in this skill.
+- **Using it for an internal system flow with no human in it.** No person, no sentiment, no journey map — that's an architecture or data-flow diagram.
+
+## Examples
+
+- `assets/example-journey.html` — minimal light. *Trial to paid: the first week*, 5 stages, trough at "Hit the limit".
+- `assets/example-journey-dark.html` — minimal dark, same data.
+- `assets/example-journey-full.html` — full editorial: container framing + 3 varied-width summary cards + footer.
diff --git a/skills/diagram-design/references/type-kanban.md b/skills/diagram-design/references/type-kanban.md
new file mode 100644
index 0000000..400dafc
--- /dev/null
+++ b/skills/diagram-design/references/type-kanban.md
@@ -0,0 +1,49 @@
+# Kanban Board
+
+**Best for:** a snapshot of work-in-progress by state — what is queued, what is moving, what is stuck, and where the WIP limit is being breached. This is a *state census*, not a flow: a kanban board has **no connectors at all**. That is exactly what separates it from swimlane (lanes plus a flow crossing them, with handoffs as the load-bearing edges) and from process (ordered steps with directional handoffs). If the diagram needs an arrow anywhere, it isn't a kanban board anymore — reach for swimlane or process instead.
+
+## Layout conventions
+
+- **Up to 5 vertical columns of equal width (240px), 32px gutters.** Column background is `ink @ 0.02`; no column border.
+- **Header band per column:** column name in Geist sans 12px weight 600, anchored left. A right-anchored **WIP chip** — a rectangular tag (`rx=2`, **never** a pill) holding `n/limit` in Geist Mono 8px — or bare `n` on a queue or terminal column, which carries no limit. Every in-process column states one. A hairline `rule` separator sits directly under the header band, full column width.
+- **Cards:** the §6 node-box pattern at `rx=6`, column width minus 16px padding on each side, 56px tall, 12px vertical gap between cards. Content: title in Geist sans 12px weight 600, and a Geist Mono 9px `muted` sublabel line for `TICKET-ID · owner` (e.g. `AVA-214 · nadia`).
+- **Drawing order:** background → column fills → header text + WIP chips → header rules → cards (each: box, then left accent bar if blocked, then title, then sublabel) → legend.
+
+## Card states — the type's semantic vocabulary
+
+Every card renders in exactly one of four states. Document and use all four when the board has enough cards to show them:
+
+| State | Fill | Stroke | Extra |
+|---|---|---|---|
+| `default` | white | `ink` | — |
+| `blocked` | `accent @ 0.05` | `accent` (full opacity) dashed `4,4` | 4px `accent` bar on the card's left edge |
+| `waiting / external` | `ink @ 0.02` | `ink @ 0.20` dashed `4,3` | — |
+| `done` | `ink @ 0.05` | `muted` | — |
+
+These map directly onto the SKILL.md §5 node-treatment table (`security` → blocked, `optional` → waiting/external, `store` → done) — the board reuses the system's existing semantic fills rather than inventing new ones.
+
+## Over-limit column
+
+When a column's card count `n` exceeds its stated `limit`, the WIP chip's stroke and text go `accent`. That plus one blocked card is the full 2-accent budget for the diagram — don't spend the budget anywhere else.
+
+## Complexity budget
+
+- Max 5 columns, max 4 cards per column, max 12 cards total.
+- Max 2 accent elements (the over-limit chip counts as one; a blocked card counts as one).
+- Over budget on a single column → aggregate the backlog into one count card (`+14 more`) rather than listing every item.
+
+## Anti-patterns
+
+- **Drawing arrows between cards.** A board shows state, not flow — if the flow itself needs to be visible, use swimlane or process instead.
+- **More than 4 cards in a column.** Aggregate into a count card; don't let a column scroll off the canvas.
+- **One card per person.** That's an org chart wearing a kanban skin.
+- **In-process columns without WIP limits.** The limit is half the point of the type — a column work flows *through* with no stated limit can't show that it's over budget. The entry queue and the terminal column are the exception: nothing is constrained by holding more done work, so they show a bare count.
+- **Accenting every blocked card.** One or two blocked cards read as signal; a column full of accent reads as noise and erases the focal rule.
+- **A "Done" column that grows without bound.** Cap it and note the archive point in the sublabel or a footnote — an unbounded Done column just becomes a second Backlog.
+- **Pill-shaped WIP tags.** The chip is a rectangle at `rx=2`, matching the type-tag primitive in §6 — pills read as status badges from an unrelated design language.
+
+## Examples
+
+- `assets/example-kanban.html` — minimal light. Platform-team board: Backlog (3), In progress (4/3, over limit), Review (2/3), Done (2), one blocked card.
+- `assets/example-kanban-dark.html` — minimal dark, same data.
+- `assets/example-kanban-full.html` — full editorial: container framing + 3 summary cards of varied widths + footer.
diff --git a/skills/diagram-design/references/type-sankey.md b/skills/diagram-design/references/type-sankey.md
new file mode 100644
index 0000000..f76c0b9
--- /dev/null
+++ b/skills/diagram-design/references/type-sankey.md
@@ -0,0 +1,72 @@
+# Sankey / Flow-Quantity
+
+**Best for:** showing where a *quantity* goes as it splits and merges across a small number of stages — CI compute budgets, funnel-adjacent volume flows, cost or headcount allocation. This is the one type where band **thickness carries data**; if the reader doesn't need to compare magnitudes, use process or pyramid instead.
+
+## Layout conventions
+
+- **Exactly 3 stage columns**, left → right. No more, no less — above 3 stages, split into two linked diagrams.
+- **Nodes are vertical bars**, `width=12`, solid `ink` fill, no stroke. Height is proportional to the quantity passing through, rounded to the nearest 4px so it stays on-grid — the rounding is a rendering step, not a data change; the true value still prints in the quantity sublabel.
+- **Flows are filled ribbons**, not stroked lines: a single closed `` per flow. Top edge is a cubic Bézier from the source node's top-offset to the target node's top-offset; bottom edge is the same curve run in reverse from target-bottom back to source-bottom. **Both** control points sit at the horizontal midpoint between the two columns, each at the y of the end it belongs to: `C midX,y0 midX,y1 targetX,y1`. That is what makes the band leave and arrive **horizontally**, so it plugs into each bar square-on. Putting the second control on the target's x instead (`C midX,y0 targetX,y1 targetX,y1`) collapses it onto the endpoint, the arrival tangent degenerates, and every ribbon meets its bar at a visible slant — it looks like the band is not attached.
+- **No arrowheads, ever.** Direction is implied by the left-to-right column order. This is a deliberate, explicit exemption from SKILL.md §6's orthogonal-elbow-and-arrowhead rule: ribbons are area encodings, not connectors, and a marker on a filled band reads as clutter, not information.
+- **Ribbon fill:** `muted` at `0.18` opacity for ordinary flows. The one editorial focal path (see below) uses `accent` at `0.28` opacity. A focal path may span more than one ribbon segment (e.g. two flows that both feed the same downstream node as halves of one story) — accenting every ribbon that belongs to that single path still counts as **one** focal element, not one per ribbon. Never per-flow rainbow coloring — color is reserved for the one path that deserves attention.
+- **Node ordering minimizes crossings.** Order nodes within each column so that flows converging on (or diverging from) the same node stay in a consistent top-to-bottom sequence across columns. If two ribbons still cross more than once, reorder the nodes — don't let them tangle.
+- **Labels:** node name in Geist sans 12px 600, quantity directly under it in Geist Mono 9px `muted`. Placement is column-specific: column 1 sits outside the bar, `text-anchor="end"`; column 2 sits in the gutter above its bar, `text-anchor="middle"`, **vertically centred in that gutter** rather than flush to the top, or the cap line grazes the bar above; column 3 sits outside the bar, `text-anchor="start"`.
+
+ Centring the column-2 label in its gutter is what makes it legible: the gutter is the gap the bands themselves leave between two nodes, so a centred label sits on clean paper and needs no backing at all. Don't reach for a mask rect here — over a filled band it reads as a hole punched in the diagram, and if the label already sits on paper it is solving nothing. If a label genuinely has nowhere clear to sit, the column is over budget: drop a node or split the diagram.
+- **Column headers:** Geist Mono 8px, uppercase, tracked, centered above each column — "CI COMPUTE BUDGET / TEST STAGE / OUTCOME" style eyebrows, not full sentences.
+- **Drawing order:** background → column headers → ordinary ribbons → the accent path's ribbon(s) (painted last among ribbons so they read on top) → node bars → node labels → legend.
+- **Legend:** horizontal strip at the bottom per the global rule, viewBox extended ~60–100px to fit it (a Sankey's ribbons need more bottom clearance than a typical diagram because node stacks run tall). Swatches are 16×8 rectangles matching each ribbon treatment, plus an optional italic aside stating the editorial read.
+
+## Scale rule
+
+Pick **one px-per-unit constant `k`** for the whole diagram and apply it to every node and ribbon thickness — never a different scale per column. Round each resulting thickness to the nearest 4px (grid compliance) and reconcile the rounding at the node level, not the flow level, so a node's outgoing ribbons still sum exactly to its (rounded) height.
+
+**When you control the numbers, choose ones that land on the grid.** At `k`, a 4px step is `4/k` units; pick quantities that are whole multiples of it and the drawn area is then exactly the printed number. Rounding is the fallback for real data you cannot choose, and it is a real cost: at `k = 0.02` a 4px step is 200 minutes, so a rounded bar can misstate its own label by up to 100. In a chart whose entire premise is that area encodes quantity, a bar that disagrees with the number printed beside it spends credibility to buy grid compliance. Never let the rounding exceed one 4px step, and never round a flow so far that a node's ribbons no longer sum to its bar.
+
+**Minimum rendered ribbon thickness: 4px.** Anything that would round to less gets folded into an "other" band rather than drawn as an invisible hairline — a Sankey ribbon the reader can't see isn't communicating anything.
+
+### Worked reference (k = 0.02 px/unit, budget = 12,000 CI minutes)
+
+| Node | Quantity | Height (px) |
+|---|---|---|
+| CI minutes (col 1) | 12,000 | 240 |
+| Unit tests | 5,200 | 104 |
+| E2E | 4,000 | 80 |
+| Build | 2,000 | 40 |
+| Lint | 800 | 16 |
+| Passed | 9,400 | 188 |
+| Failed | 1,600 | 32 |
+| Flaked | 1,000 | 20 |
+
+Each column's node heights sum to the same 240px total — that invariant (total-in equals total-out) is what makes the diagram trustworthy at a glance. If your columns don't sum to the same total, the data has a leak or the layout has a bug.
+
+## Complexity budget
+
+| Limit | Rule |
+|---|---|
+| Max stage columns | 3 |
+| Max nodes | 8 |
+| Max flows (ribbons) | 12 |
+| Max accent elements | 2 (a focal path's ribbons count as one, regardless of how many segments it spans) |
+
+Over budget → split into two linked Sankeys (e.g. an overview stage-1→stage-2 diagram plus a detail stage-2→stage-3 diagram) rather than cramming a fourth column or a ninth node into one canvas.
+
+## Anti-patterns
+
+- **Ribbons that meet the bar at a slant.** The single most common way to get this type wrong, and it is a control-point mistake, not a layout one: both controls belong on the midpoint x. A band arriving at an angle reads as detached from its node, which undermines the one thing the diagram is asserting — that this quantity flows into that node.
+- **An opaque mask rect behind a column-2 label.** Over a filled band it reads as a hole punched in the diagram, and it erases any bar it overlaps. Centre the label in the gutter instead, where it sits on clean paper and needs nothing behind it.
+- **Column-2 labels flush to the top of their gutter.** Centre them, or the cap line touches the bar above and the label looks like it belongs to the wrong node.
+- **A bar whose height disagrees with the number printed beside it.** See the scale rule: choose grid-friendly quantities when the data is yours to choose.
+- **Ribbons crossing more than once.** Reorder the nodes in the offending column; a Sankey with a tangle in the middle is unreadable.
+- **Ribbons thinner than 4px.** Merge them into an "other" band instead of drawing a sliver no one can see.
+- **Per-flow rainbow coloring.** One `muted` treatment for ordinary flows, one `accent` treatment for the flow that carries the editorial point — never a distinct hue per ribbon.
+- **Using Sankey for a simple funnel.** A single narrowing quantity with no splits or merges is a pyramid/funnel, not a Sankey.
+- **Using Sankey for a plain step sequence.** If nothing splits, merges, or varies in thickness, it's a process diagram — the whole point of Sankey is quantity that branches.
+- **Stacking two flows at the same node-edge offset.** Every flow gets its own offset range within the node's height, in a consistent top-to-bottom order — never two ribbons overlapping at the same attach point.
+- **Percentages or quantities that don't sum to the source total.** Every node's outgoing (or incoming) flows must sum to that node's own height. A Sankey that doesn't balance reads as an error, not a design choice.
+
+## Examples
+
+- `assets/example-sankey.html` — minimal light. A month of CI compute (12,000 minutes) splitting into test/build/lint stages, merging into passed/failed/flaked outcomes; the flaky-rerun path is the one accent flow.
+- `assets/example-sankey-dark.html` — minimal dark, same data.
+- `assets/example-sankey-full.html` — full editorial: container framing + 3 summary cards of varied widths + footer.
diff --git a/skills/diagram-design/references/type-story-map.md b/skills/diagram-design/references/type-story-map.md
new file mode 100644
index 0000000..08fbccd
--- /dev/null
+++ b/skills/diagram-design/references/type-story-map.md
@@ -0,0 +1,46 @@
+# User Story Map
+
+**Best for:** the Jeff Patton user story map — it answers "what is the whole story, and where do we cut the first release?" Narrative order runs left to right; priority runs top to bottom. The **release cut** is the editorial point of the diagram: a map without one is just a backlog in a grid.
+
+This is neither **Kanban** nor **User journey**, and the distinction is load-bearing:
+
+- **Kanban** shows *state* — columns are Todo/Doing/Done, there is no narrative order and nothing to slice.
+- **User journey** shows *one persona's feelings* across stages via a sentiment curve.
+- A **story map** has neither state nor sentiment. Its columns are **narrative order** and its rows are **release slices**. If you aren't slicing releases, use one of those two instead.
+
+## Layout conventions
+
+Vertical stack, top to bottom:
+
+1. **Backbone** — up to 5 activities in left-to-right narrative order, as wide header cards (200px, `rx=6`, `ink @ 0.05` fill, `muted` stroke). Each card: the activity name in Geist sans 12px weight 600, above a Geist Mono 8px uppercase tracked eyebrow (`ACTIVITY 1` … `ACTIVITY 5`). 24px gutters between cards.
+2. **Walking skeleton row** — directly under each activity, its user *steps* as smaller cards (`rx=4`, 32px tall, white fill, `ink` stroke), Geist sans 12px. One or two per activity; reserve room for two so every activity's row bottom aligns even when it only has one step.
+3. **Release slices** — horizontal bands below the skeleton row, each a full-width lane with a Geist Mono 8px uppercase tracked label (`MVP`, `RELEASE 2`, `LATER`) sitting in a 96px left margin. Band background alternates `ink @ 0.02` / none. Inside each band, story cards (`rx=4`, 48px tall) sit in their activity's column: story title in Geist sans 12px weight 600, plus a Geist Mono 9px estimate/ticket sublabel (e.g. `RPT-114 · 3pt`). Whenever any slice has a gap (an activity with no card in that row), add `rule` hairline column separators (0.8px, dashed `4,4`, 0.10 opacity) running from just under the backbone down to the bottom of the last slice, drawn before the cards — without them, a gappy grid reads as scattered rather than mapped to its activity.
+4. **The release cut line** — a full-width horizontal `accent` rule (1.5px) immediately under the MVP band, with a masked Geist Mono 8px label `RELEASE CUT` at its right end. This is accent element one.
+5. **Legend** — horizontal strip at the bottom per the global rule (hairline separator above): one swatch for the default story card, one for the highest-risk treatment, one for the release-cut line.
+
+## Focal rule
+
+Exactly 2 accent elements: the release cut line with its `RELEASE CUT` label (counts as one), and the single riskiest story card — drawn with `accent @ 0.05` fill, `accent` dashed `4,4` stroke, and a small rectangular `RISK` tag (`rx=2`, matching the type-tag primitive) — counts as the other. Nothing else on the map is `accent`.
+
+## Complexity budget
+
+- Max 5 activities, max 3 release slices, max 12 story cards total, max 4 cards per slice.
+- Max 2 accent elements (the release cut counts as one; the riskiest card counts as the other).
+- Over budget on a single activity or slice → split into one map per activity, or collapse a slice into a count card rather than listing every item.
+
+## Anti-patterns
+
+- **No release cut.** A map with no cut line is a backlog in a grid, not a map — the cut is the whole point.
+- **Columns ordered by priority instead of narrative sequence.** The backbone is a story, left to right, in the order the user experiences it — not a ranked list.
+- **Story cards that are features, not user-visible outcomes.** "Add a chart" is a story; "Refactor the charting service" is not — it belongs in a backlog ticket, not the map.
+- **Slices named by date instead of by outcome.** `MVP` / `RELEASE 2` / `LATER` describe scope; `Q3` / `Q4` describe a calendar and drift the moment the schedule slips.
+- **More than 3 slices.** Beyond MVP, next, and later, nobody believes the ordering — collapse the tail into "Later."
+- **Mixing two personas in one map.** One map per persona, same as user journey.
+- **Adding state columns.** That turns it into a kanban board — this type has no state.
+- **Adding a sentiment curve.** That turns it into a user journey — this type has no feelings axis.
+
+## Examples
+
+- `assets/example-story-map.html` — minimal light. *Reporting, first release*: four activities (`Find the data`, `Build the report`, `Share it`, `Trust it`), MVP/Release 2/Later slices, release cut under MVP, `Row-level permissions` flagged as the riskiest story.
+- `assets/example-story-map-dark.html` — minimal dark, same data.
+- `assets/example-story-map-full.html` — full editorial: container framing + 3 summary cards of varied widths + footer.
diff --git a/skills/diagram-design/references/type-uml-class.md b/skills/diagram-design/references/type-uml-class.md
new file mode 100644
index 0000000..d9c3bdb
--- /dev/null
+++ b/skills/diagram-design/references/type-uml-class.md
@@ -0,0 +1,65 @@
+# UML Class Diagram
+
+**Best for:** the static structure of an object model — classes, what they own, what they inherit, and what they merely depend on. The distinguishing content is the **operations compartment** and the **typed relationship vocabulary** (the arrowheads carry meaning). ER cannot express either — use this type only when operations or the inheritance/composition vocabulary are the point of the diagram, and `type-er.md` when the story is entities and cardinality.
+
+**Other UML diagrams — route elsewhere.** UML is a family; only the class diagram gets its own grammar here:
+
+| UML diagram | Use instead |
+|---|---|
+| Sequence | [type-sequence.md](type-sequence.md) |
+| State machine | [type-state.md](type-state.md) |
+| Component | [type-architecture.md](type-architecture.md) |
+| Deployment | [type-architecture.md](type-architecture.md) |
+| Activity | [type-swimlane.md](type-swimlane.md) or [type-flowchart.md](type-flowchart.md) |
+| Conceptual / domain ER | [type-er.md](type-er.md) |
+
+## Layout conventions
+
+- Each class is a **single box** (`rx=6`), divided by full-width hairlines into up to three compartments. Compartment heights follow content — never pad to a uniform height.
+ 1. **Name** — class name in Geist sans, 12px, weight 600, **centered**. An interface carries a Geist Mono 8px `«interface»` stereotype line above the name. An abstract class sets the name in *italic*.
+ 2. **Attributes** — one line each, Geist Mono 9px, left-aligned: `+ name: Type`. Visibility markers: `+` public, `-` private, `#` protected.
+ 3. **Operations** — one line each, Geist Mono 9px, left-aligned: `+ method(arg): Return`.
+ Omit a compartment entirely when a class has no members in it (an interface with no attributes skips that compartment).
+- Attribute/operation lines are a single combined string, not the two-column field/type layout ER uses — that visual distinction keeps the two types from reading the same.
+- Coral (accent) is reserved for the class being implemented or extended (the focal type) — accent-tint fill, accent stroke. Its inbound inheritance/realization edges count as **one** additional accent element (treated as a group), for 2 accent elements total per diagram.
+
+## Relationship vocabulary
+
+Define every marker used in `` and show all six in the legend, even the ones not used in the diagram body — the legend is this type's complete grammar reference.
+
+| Relationship | Line | Ending (at the target/owner end) |
+|---|---|---|
+| Inheritance (`extends`) | solid | large **hollow triangle** — `paper` fill, `ink` stroke |
+| Realization (`implements`) | dashed `5,4` | same hollow triangle |
+| Composition (owns, cascades) | solid | **filled diamond** at the OWNER end, `ink` fill |
+| Aggregation (has, independent) | solid | **hollow diamond** at the OWNER end |
+| Association | solid | plain open arrowhead, multiplicity at BOTH ends |
+| Dependency (uses) | dashed `4,3` | plain open arrowhead |
+
+Multiplicities (`1`, `0..*`, `1..*`) sit in Geist Mono 8px, 10–12px off the box edge, on an opaque mask over the line — same convention as ER cardinality labels.
+
+## Connector rules
+
+All six SKILL.md §6 connector rules apply in full — orthogonal rounded elbows (`r=8`), no diagonals, bridge/hop for unavoidable crossings, fanned attach points ≥12px apart when several relationships share an edge, masked labels with the 6–10px gap, connectors drawn before boxes. Prefer laying classes out so relationships resolve to straight lines or single-elbow routes; a class diagram with every edge bridging is over budget — split by package instead.
+
+## Complexity budget
+
+Max 7 classes, max 8 relationships, max 5 members per compartment (overflow becomes a Geist Mono `…` line), max 2 accent elements. Over budget → split by package.
+
+Seven is the ceiling rather than the target. Three compartments per box makes a class diagram dense fast, so treat 4–5 classes as the normal size; the shipped example uses all seven only because it doubles as the legend for the full relationship vocabulary.
+
+## Anti-patterns
+
+- Getters and setters listed as operations — they're noise; show behavior that matters.
+- Every attribute and method dumped in — a class diagram is an argument, not a header file.
+- Composition and aggregation used interchangeably — the filled diamond means the part dies with the whole. Say so, or use the hollow diamond.
+- Association arrows with no multiplicity.
+- Drawing a class diagram when there's no inheritance and no operations — that's ER.
+- Stereotype guillemets on everything, not just the interfaces/abstracts that need them.
+- Boxes padded to equal height.
+
+## Examples
+
+- `assets/example-uml-class.html` — minimal light
+- `assets/example-uml-class-dark.html` — minimal dark
+- `assets/example-uml-class-full.html` — full editorial
diff --git a/skills/diagram-design/references/type-wardley.md b/skills/diagram-design/references/type-wardley.md
new file mode 100644
index 0000000..c0a4423
--- /dev/null
+++ b/skills/diagram-design/references/type-wardley.md
@@ -0,0 +1,39 @@
+# Wardley Map
+
+**Best for:** positioning the components of a value chain against how evolved (commoditised) each one is, so a reader can see what to build, what to buy, and what is about to move. A strategy artefact, not an architecture diagram — it says nothing about how components connect at runtime, only where each one sits on the genesis-to-commodity curve.
+
+## Layout conventions
+
+- **Y axis — value chain.** `Visible to the user` at the top, down to `Invisible` at the bottom. Label the axis as stacked separate `` lines flanking the axis endpoints — **never `writing-mode`** to rotate a label vertically. Axis line `rule-solid` at `0.20` opacity.
+- **X axis — evolution.** Four bands separated by three vertical hairlines: `Genesis | Custom-built | Product | Commodity`. Band separators are `rule` at `0.10` opacity, dashed `4,4`. Band labels sit along the bottom axis: Geist Mono 8px, uppercase, tracked, `muted`. Axis line `rule-solid` at `0.20` opacity.
+- **Components** are a small circle `r=6`, filled `paper` with an `ink` 1px stroke. Label in Geist sans 12px weight 600, placed 12px above the dot, `text-anchor="middle"`. An optional Geist Mono 9px `muted` sublabel can sit under the dot for a technical qualifier — use sparingly.
+- **Dependency links** are thin `muted` 0.8px straight lines from a component down to the component it depends on. **These are the one documented exemption from §6 rule 1 (mandatory orthogonal elbows) — dependency links only.** A component's y/x position on this map *is* the data; forcing it onto an axis to make an elbow route work would misplace it. No arrowhead — the line itself states the dependency.
+- **Movement** — a component that is evolving carries a short right-pointing arrow: `accent`, dashed `5,4`, `marker-end="url(#arrow-accent)"`, running from the dot's edge toward the next band. The arrow needs no on-arrow text label: the legend's "Evolving" swatch (accent dot + dashed accent arrow) already names what accent + dashes mean, and since arrows on this map can only ever point right (see Anti-patterns — a left-pointing movement arrow is a contradiction, not a design choice), the direction itself already says "toward commodity." A bare word like `COMMODITISING` restates what shape and color already signal — apply §1's remove test: can I remove this label, does color or shape already carry it? Here it does, so the label is the thing that goes, not its position.
+ An on-arrow label is legitimate only when it qualifies something the arrow *can't* express on its own — a timeframe (`BY Q3`), a driver (`VENDOR LOCK-IN`) — never a restatement of direction. If you add one, mask it Geist Mono 8px, 6–10px clear of the stroke, same masking rule as any arrow label (§6 rule 2), and confirm there's runway for the mask first: the space directly around a component's dot is usually the most congested spot on the map, because that's also where its own dependency links fan out. Worked example — the moving component in `example-wardley.html` sits at `(420,156)` with links fanning to `(620,220)` and `(680,252)`; at the mandatory 6–10px gap band below the arrow (`y=164–176`), those two lines cross at `x=441.7–482.5` and `x=445–482.5` respectively — almost the full width of the arrow's own span (`x=428–504`), leaving no clear pocket wide enough for a label. Above the dot is no better: the component's own name label already occupies that band per the 12px-above-dot convention. Check both bands for interference before adding a movement label; if neither is clear, don't add one — the legend already covers it.
+- **Focal rule:** the 2 accent elements on this type are the moving component's dot (`accent-tint` fill, `accent` stroke) and its movement arrow — or two moving components sharing those 2 accent slots with no other accent anywhere else on the map.
+- **Legend:** horizontal strip at the bottom, hairline separator above it, viewBox extended ~60px — same as every other type.
+
+## Complexity budget
+
+| Limit | Rule |
+|---|---|
+| Max components | 9 |
+| Max dependency links | 12 |
+| Max movement arrows | 2 |
+| Max accent elements | 2 |
+
+## Anti-patterns
+
+- **Treating the x axis as a maturity score.** Evolution is four qualitative bands (genesis / custom-built / product / commodity), not a 0–10 slider. Don't plot a component at "6.5" — place it in a band.
+- **A component with no dependency link.** If nothing in the value chain depends on it and it depends on nothing, it isn't part of the chain — delete it or wire it in.
+- **Arrows drawn right-to-left.** Evolution only moves toward commodity. A left-pointing movement arrow is a contradiction, not a design choice.
+- **Using the map as an architecture diagram.** No request/response direction, no protocols, no runtime topology — that's the architecture type. This type answers "what's worth building vs. buying," not "how does traffic flow."
+- **Numbering the y axis.** Value-chain visibility is ordinal (more visible to the user, less visible), not a quantity. Numeric ticks imply a measurement that doesn't exist.
+- **More than 2 movement arrows.** Beyond that the map stops making a single point and turns into a forecast nobody can act on.
+- **`writing-mode` vertical axis text.** Stack the words as separate horizontal `` lines instead — see Layout conventions above.
+
+## Examples
+
+- `assets/example-wardley.html` — minimal light. AI assistant product, agent orchestration commoditising toward Product.
+- `assets/example-wardley-dark.html` — minimal dark, same map.
+- `assets/example-wardley-full.html` — full editorial: framed container + 3 varied-width cards (the moving component, a genesis-stage build, and the commodity base).