docs(gallery): refresh canonical 38-type visual catalog (#119)

* docs(gallery): refresh canonical visual catalog

* docs: document screenshot renderer setup
This commit is contained in:
Cathryn Lavery
2026-08-19 18:47:20 -05:00
committed by GitHub
parent 4691a2f40c
commit e8b7d7ae62
50 changed files with 646 additions and 38 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "diagram-design", "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, 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.", "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", "version": "2.5.11",
"author": { "author": {
"name": "Cathryn Lavery", "name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery" "url": "https://github.com/cathrynlavery"
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "diagram-design", "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, 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.", "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", "version": "2.5.11",
"author": { "author": {
"name": "Cathryn Lavery", "name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery" "url": "https://github.com/cathrynlavery"
+6
View File
@@ -172,6 +172,11 @@ jobs:
python scripts/verify-docs-sync.py python scripts/verify-docs-sync.py
python scripts/test-verify-docs-sync.py python scripts/test-verify-docs-sync.py
- name: Verify canonical screenshot freshness
if: always()
id: screenshots
run: python scripts/verify-screenshot-freshness.py
- name: Verify packaged self-check - name: Verify packaged self-check
if: always() if: always()
id: self_check id: self_check
@@ -247,6 +252,7 @@ jobs:
echo "| Mermaid Import Extractor | ${{ steps.mermaid.outcome == 'success' && '✅ Passed' || (steps.mermaid.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Mermaid Import Extractor | ${{ steps.mermaid.outcome == 'success' && '✅ Passed' || (steps.mermaid.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Optional Motion Contract | ${{ steps.motion.outcome == 'success' && '✅ Passed' || (steps.motion.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Optional Motion Contract | ${{ steps.motion.outcome == 'success' && '✅ Passed' || (steps.motion.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Docs & Routing Sync | ${{ steps.docs_sync.outcome == 'success' && '✅ Passed' || (steps.docs_sync.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Docs & Routing Sync | ${{ steps.docs_sync.outcome == 'success' && '✅ Passed' || (steps.docs_sync.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Canonical Screenshot Freshness | ${{ steps.screenshots.outcome == 'success' && '✅ Passed' || (steps.screenshots.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Packaged Self-Check | ${{ steps.self_check.outcome == 'success' && '✅ Passed' || (steps.self_check.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Packaged Self-Check | ${{ steps.self_check.outcome == 'success' && '✅ Passed' || (steps.self_check.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Label Geometry | ${{ steps.geometry.outcome == 'success' && '✅ Passed' || (steps.geometry.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Label Geometry | ${{ steps.geometry.outcome == 'success' && '✅ Passed' || (steps.geometry.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
echo "| Label Geometry Checker | ${{ steps.geometry_tests.outcome == 'success' && '✅ Passed' || (steps.geometry_tests.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY echo "| Label Geometry Checker | ${{ steps.geometry_tests.outcome == 'success' && '✅ Passed' || (steps.geometry_tests.outcome == 'skipped' && '⏭️ Skipped' || '❌ Failed') }} |" >> $GITHUB_STEP_SUMMARY
+1
View File
@@ -41,6 +41,7 @@
"python3 scripts/test-verify-motion.py", "python3 scripts/test-verify-motion.py",
"python3 scripts/verify-docs-sync.py", "python3 scripts/verify-docs-sync.py",
"python3 scripts/test-verify-docs-sync.py", "python3 scripts/test-verify-docs-sync.py",
"python3 scripts/verify-screenshot-freshness.py",
"python3 scripts/test-self-check.py", "python3 scripts/test-self-check.py",
"python3 scripts/verify-geometry.py --all", "python3 scripts/verify-geometry.py --all",
"python3 scripts/test-verify-geometry.py", "python3 scripts/test-verify-geometry.py",
+3
View File
@@ -53,6 +53,7 @@ The helper refuses to run if the Claude and Codex versions already differ. If an
| Optional motion contract (fallbacks, controls, budgets, determinism) | `python3 scripts/test-verify-motion.py` | | Optional motion contract (fallbacks, controls, budgets, determinism) | `python3 scripts/test-verify-motion.py` |
| Every shipped motion template/example | `python3 scripts/verify-motion.py --shipped` | | Every shipped motion template/example | `python3 scripts/verify-motion.py --shipped` |
| Docs/routing sync (description hooks, gallery, README tree, reference links, profile surfaces) | `python3 scripts/verify-docs-sync.py && python3 scripts/test-verify-docs-sync.py` | | Docs/routing sync (description hooks, gallery, README tree, reference links, profile surfaces) | `python3 scripts/verify-docs-sync.py && python3 scripts/test-verify-docs-sync.py` |
| Canonical README screenshots match their example HTML sources and recorded PNG digests | `python3 scripts/verify-screenshot-freshness.py` |
| Packaged output self-check behaves (pass + adversarial cases) | `python3 scripts/test-self-check.py` | | Packaged output self-check behaves (pass + adversarial cases) | `python3 scripts/test-self-check.py` |
| Label masks are never clipped by a node painted after them | `python3 scripts/verify-geometry.py --all` | | Label masks are never clipped by a node painted after them | `python3 scripts/verify-geometry.py --all` |
| Label geometry checker behaves (pass + adversarial cases) | `python3 scripts/test-verify-geometry.py` | | Label geometry checker behaves (pass + adversarial cases) | `python3 scripts/test-verify-geometry.py` |
@@ -84,6 +85,7 @@ python3 scripts/test-plugin-package.py \
&& python3 scripts/test-verify-motion.py \ && python3 scripts/test-verify-motion.py \
&& python3 scripts/verify-docs-sync.py \ && python3 scripts/verify-docs-sync.py \
&& python3 scripts/test-verify-docs-sync.py \ && python3 scripts/test-verify-docs-sync.py \
&& python3 scripts/verify-screenshot-freshness.py \
&& python3 scripts/test-self-check.py \ && python3 scripts/test-self-check.py \
&& python3 scripts/verify-geometry.py --all \ && python3 scripts/verify-geometry.py --all \
&& python3 scripts/test-verify-geometry.py \ && python3 scripts/test-verify-geometry.py \
@@ -100,6 +102,7 @@ python3 scripts/test-plugin-package.py \
- **`verify-plugin-package.py`:** run the bump helper if the versions did not increase. If packaging validation fails, keep both marketplaces pointed at the repository root and keep the shared skill at `skills/diagram-design/SKILL.md`. - **`verify-plugin-package.py`:** run the bump helper if the versions did not increase. If packaging validation fails, keep both marketplaces pointed at the repository root and keep the shared skill at `skills/diagram-design/SKILL.md`.
- **`lint-skin.py`:** the failure message names the file, line, and category (`color`, `font-family`, `a11y`, `external-asset`, `pure-black`, `script`). Colors must come from the palette in `skills/diagram-design/references/style-guide.md`; fonts from the allowed list; diagrams must satisfy the accessible SVG contract (see below). The linter also requires the SHA-pinned controller from `template-motion.html` verbatim and rejects remote resources, CSS `@import`, non-fragment CSS `url()`, event handlers, `srcdoc`, executable URLs, and extra scripts. - **`lint-skin.py`:** the failure message names the file, line, and category (`color`, `font-family`, `a11y`, `external-asset`, `pure-black`, `script`). Colors must come from the palette in `skills/diagram-design/references/style-guide.md`; fonts from the allowed list; diagrams must satisfy the accessible SVG contract (see below). The linter also requires the SHA-pinned controller from `template-motion.html` verbatim and rejects remote resources, CSS `@import`, non-fragment CSS `url()`, event handlers, `srcdoc`, executable URLs, and extra scripts.
- **`verify-*.py`:** the extractor's real behavior no longer matches its fixture or the documentation, or the reference/command/prompt wiring drifted. Fix the source of truth — do not widen a test to avoid a failure. - **`verify-*.py`:** the extractor's real behavior no longer matches its fixture or the documentation, or the reference/command/prompt wiring drifted. Fix the source of truth — do not widen a test to avoid a failure.
- **`verify-screenshot-freshness.py`:** a canonical minimal-light example or its committed PNG changed without a synchronized catalog refresh. Before the first regeneration, install the renderer with `python3 -m pip install playwright && python3 -m playwright install chromium`. Then run `python3 scripts/render-canonical-screenshots.py`, inspect all 38 renders, and commit the updated PNGs plus `docs/screenshots/manifest.json`.
- **`verify-slopegraph.py`:** the two axes disagree about scale or origin, or an endpoint is drawn somewhere other than where its own declared value belongs. Fix the coordinate, never the label — and never move a point to stop two endpoint labels colliding, because crowded labels mean the values really are close. - **`verify-slopegraph.py`:** the two axes disagree about scale or origin, or an endpoint is drawn somewhere other than where its own declared value belongs. Fix the coordinate, never the label — and never move a point to stop two endpoint labels colliding, because crowded labels mean the values really are close.
- **`verify-geometry.py`:** a label mask overlaps a node declared later in the document, so the node fill clips the label at render time. Move the label to a free segment of its connector — keep the 6–10px gap from the stroke required by SKILL.md §6, and do not shrink the mask to sneak under the check. - **`verify-geometry.py`:** a label mask overlaps a node declared later in the document, so the node fill clips the label at render time. Move the label to a free segment of its connector — keep the 6–10px gap from the stroke required by SKILL.md §6, and do not shrink the mask to sneak under the check.
- **Icon assets:** you changed `scripts/vendor/icons/` or `scripts/build-icons.py` and the generated files went stale. Rerun `python3 scripts/build-icons.py` and commit the regenerated files. - **Icon assets:** you changed `scripts/vendor/icons/` or `scripts/build-icons.py` and the generated files went stale. Rerun `python3 scripts/build-icons.py` and commit the regenerated files.
+38 -34
View File
@@ -14,7 +14,7 @@
*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.* *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. 38 editorial diagram types for Claude Code, Codex, and Pi. Self-contained HTML + SVG. No shadows. No Mermaid slop. 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. No Figma. No generic rounded boxes. No 30-minute color-picking sessions.
@@ -37,42 +37,42 @@ All 38 visual types ship in three static variants: minimal light, minimal dark,
<table> <table>
<tr> <tr>
<td align="center" width="33%"><img src="docs/screenshots/architecture.png" alt="Architecture"><br><b>Architecture</b><br><sub>Components + connections</sub></td> <td align="center" width="33%"><img src="docs/screenshots/architecture.png" alt="Architecture"><br><b>Architecture</b><br><sub>Components + connections</sub></td>
<td align="center" width="33%"><img src="docs/screenshots/it-state.png" alt="IT current-state"><br><b>IT current-state</b><br><sub>Legacy landscape + modernization</sub></td>
<td align="center" width="33%"><img src="docs/screenshots/flowchart.png" alt="Flowchart"><br><b>Flowchart</b><br><sub>Decision logic</sub></td> <td align="center" width="33%"><img src="docs/screenshots/flowchart.png" alt="Flowchart"><br><b>Flowchart</b><br><sub>Decision logic</sub></td>
<td align="center" width="33%"><img src="docs/screenshots/sequence.png" alt="Sequence"><br><b>Sequence</b><br><sub>Messages over time</sub></td>
</tr> </tr>
<tr> <tr>
<td align="center"><img src="docs/screenshots/sequence.png" alt="Sequence"><br><b>Sequence</b><br><sub>Messages over time</sub></td>
<td align="center"><img src="docs/screenshots/state.png" alt="State machine"><br><b>State machine</b><br><sub>States + transitions</sub></td> <td align="center"><img src="docs/screenshots/state.png" alt="State machine"><br><b>State machine</b><br><sub>States + transitions</sub></td>
<td align="center"><img src="docs/screenshots/er.png" alt="ER"><br><b>ER / data model</b><br><sub>Entities + fields</sub></td> <td align="center"><img src="docs/screenshots/er.png" alt="ER"><br><b>ER / data model</b><br><sub>Entities + fields</sub></td>
<td align="center"><img src="docs/screenshots/timeline.png" alt="Timeline"><br><b>Timeline</b><br><sub>Events on an axis</sub></td>
</tr> </tr>
<tr> <tr>
<td align="center"><img src="docs/screenshots/timeline.png" alt="Timeline"><br><b>Timeline</b><br><sub>Events on an axis</sub></td>
<td align="center"><img src="docs/screenshots/swimlane.png" alt="Swimlane"><br><b>Swimlane</b><br><sub>Cross-functional flow</sub></td> <td align="center"><img src="docs/screenshots/swimlane.png" alt="Swimlane"><br><b>Swimlane</b><br><sub>Cross-functional flow</sub></td>
<td align="center"><img src="docs/screenshots/quadrant.png" alt="Quadrant"><br><b>Quadrant</b><br><sub>Two-axis positioning</sub></td> <td align="center"><img src="docs/screenshots/quadrant.png" alt="Quadrant"><br><b>Quadrant</b><br><sub>Two-axis positioning</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/radar.png" alt="Radar chart"><br><b>Radar / spider</b><br><sub>Multi-axis comparison</sub></td>
<td align="center"><img src="docs/screenshots/loop.png" alt="Loop"><br><b>Loop / flywheel</b><br><sub>Reinforcing cycle + shared hub</sub></td>
<td align="center"><img src="docs/screenshots/nested.png" alt="Nested"><br><b>Nested</b><br><sub>Hierarchy by containment</sub></td> <td align="center"><img src="docs/screenshots/nested.png" alt="Nested"><br><b>Nested</b><br><sub>Hierarchy by containment</sub></td>
</tr> </tr>
<tr> <tr>
<td align="center"><img src="docs/screenshots/tree.png" alt="Tree"><br><b>Tree</b><br><sub>Parent → children</sub></td> <td align="center"><img src="docs/screenshots/tree.png" alt="Tree"><br><b>Tree</b><br><sub>Parent → children</sub></td>
<td align="center"><img src="docs/screenshots/org-chart.png" alt="Org chart"><br><b>Org chart</b><br><sub>Ownership + routing</sub></td> <td align="center"><img src="docs/screenshots/org-chart.png" alt="Org chart"><br><b>Org chart</b><br><sub>Ownership + routing</sub></td>
<td align="center"><img src="docs/screenshots/layers.png" alt="Layer stack"><br><b>Layer stack</b><br><sub>Stacked abstractions</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/venn.png" alt="Venn"><br><b>Venn</b><br><sub>Set overlap</sub></td> <td align="center"><img src="docs/screenshots/venn.png" alt="Venn"><br><b>Venn</b><br><sub>Set overlap</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/layers.png" alt="Layers"><br><b>Layer stack</b><br><sub>Stacked abstractions</sub></td>
<td align="center"><img src="docs/screenshots/pyramid.png" alt="Pyramid"><br><b>Pyramid / funnel</b><br><sub>Ranked hierarchy or drop-off</sub></td> <td align="center"><img src="docs/screenshots/pyramid.png" alt="Pyramid"><br><b>Pyramid / funnel</b><br><sub>Ranked hierarchy or drop-off</sub></td>
<td align="center"><img src="docs/screenshots/quadrant-consultant.png" alt="Consultant 2×2"><br><b>Consultant 2×2</b><br><sub>Scenario matrix · named cells</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/radar.png" alt="Radar"><br><b>Radar / Spider</b><br><sub>Multi-axis comparison</sub></td>
<td align="center"><img src="docs/screenshots/loop.png" alt="Loop"><br><b>Loop</b><br><sub>Flywheel · stations around a hub</sub></td>
<td align="center"><img src="docs/screenshots/it-state.png" alt="IT current-state"><br><b>IT current-state</b><br><sub>Legacy landscape · modernization</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/high-level.png" alt="High-Level"><br><b>High-Level</b><br><sub>End-to-end stack on a cluster</sub></td>
<td align="center"><img src="docs/screenshots/bar.png" alt="Bar chart"><br><b>Bar chart</b><br><sub>Categorical comparison</sub></td> <td align="center"><img src="docs/screenshots/bar.png" alt="Bar chart"><br><b>Bar chart</b><br><sub>Categorical comparison</sub></td>
<td align="center"><img src="docs/screenshots/line.png" alt="Line chart"><br><b>Line chart</b><br><sub>Trends over time</sub></td>
</tr> </tr>
<tr> <tr>
<td align="center"><img src="docs/screenshots/gantt.png" alt="Gantt"><br><b>Gantt</b><br><sub>Tasks and phases on a timeline</sub></td> <td align="center"><img src="docs/screenshots/treemap.png" alt="Treemap"><br><b>Treemap</b><br><sub>Part-of-whole by area</sub></td>
<td align="center"><img src="docs/screenshots/scatter.png" alt="Scatter plot"><br><b>Scatter plot</b><br><sub>Distribution and correlation</sub></td> <td align="center"><img src="docs/screenshots/line.png" alt="Line chart"><br><b>Line chart</b><br><sub>Trends over time</sub></td>
<td align="center"><img src="docs/screenshots/gantt.png" alt="Gantt"><br><b>Gantt</b><br><sub>Tasks + phases on a timeline</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/scatter.png" alt="Scatter plot"><br><b>Scatter plot</b><br><sub>Distribution + correlation</sub></td>
<td align="center"><img src="docs/screenshots/high-level.png" alt="High-Level"><br><b>High-Level</b><br><sub>End-to-end stack on a cluster</sub></td>
<td align="center"><img src="docs/screenshots/process.png" alt="Process"><br><b>Process</b><br><sub>Multi-actor sequential workflow</sub></td> <td align="center"><img src="docs/screenshots/process.png" alt="Process"><br><b>Process</b><br><sub>Multi-actor sequential workflow</sub></td>
</tr> </tr>
<tr> <tr>
@@ -82,25 +82,27 @@ All 38 visual types ship in three static variants: minimal light, minimal dark,
</tr> </tr>
<tr> <tr>
<td align="center"><img src="docs/screenshots/dp-security-matrix.png" alt="DP security matrix"><br><b>DP security matrix</b><br><sub>Per-role access permissions</sub></td> <td align="center"><img src="docs/screenshots/dp-security-matrix.png" alt="DP security matrix"><br><b>DP security matrix</b><br><sub>Per-role access permissions</sub></td>
<td align="center"><img src="docs/screenshots/treemap.png" alt="Treemap"><br><b>Treemap</b><br><sub>Part-of-whole by area</sub></td> <td align="center"><img src="docs/screenshots/sankey.png" alt="Sankey"><br><b>Sankey</b><br><sub>Quantities that split + merge</sub></td>
<td align="center"><img src="docs/screenshots/fishbone.png" alt="Fishbone"><br><b>Fishbone</b><br><sub>Grouped causes → one effect</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/wardley.png" alt="Wardley map"><br><b>Wardley map</b><br><sub>Value chain × evolution</sub></td>
<td align="center"><img src="docs/screenshots/kanban.png" alt="Kanban"><br><b>Kanban</b><br><sub>Work in progress by state</sub></td>
<td align="center"><img src="docs/screenshots/journey.png" alt="User journey"><br><b>User journey</b><br><sub>Stages, actions + sentiment</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/deployment.png" alt="Deployment"><br><b>Deployment</b><br><sub>Zones, hosts + artifacts</sub></td>
<td align="center"><img src="docs/screenshots/dependency.png" alt="Dependency graph"><br><b>Dependency graph</b><br><sub>Fan-in, ranks + cycles</sub></td>
<td align="center"><img src="docs/screenshots/uml-class.png" alt="UML class"><br><b>UML class</b><br><sub>Classes, operations + typed relations</sub></td>
</tr>
<tr>
<td align="center"><img src="docs/screenshots/story-map.png" alt="Story map"><br><b>Story map</b><br><sub>Backbone × release slices</sub></td>
<td align="center"><img src="docs/screenshots/db-schema.png" alt="Database schema"><br><b>Database schema</b><br><sub>Physical tables + column FKs</sub></td>
<td></td> <td></td>
</tr> </tr>
</table> </table>
**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). The v2.5.10 release added the final ten types above. Compare their light, dark, and full-editorial variants 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. **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.
@@ -406,6 +408,8 @@ diagram-design/
│ └── example-sequence-oauth*.html │ └── example-sequence-oauth*.html
├── scripts/ ├── scripts/
│ ├── bump-plugin-version.py — synchronized Claude/Codex version bump │ ├── bump-plugin-version.py — synchronized Claude/Codex version bump
│ ├── render-canonical-screenshots.py — deterministic 38-type PNG catalog renderer
│ ├── verify-screenshot-freshness.py — source + screenshot digest gate
│ ├── verify-plugin-package.py — version + marketplace package gate │ ├── verify-plugin-package.py — version + marketplace package gate
│ ├── test-plugin-package.py — adversarial package-gate tests │ ├── test-plugin-package.py — adversarial package-gate tests
│ ├── test-verify-docs-sync.py — docs/profile-surface gate tests │ ├── test-verify-docs-sync.py — docs/profile-surface gate tests
@@ -414,7 +418,7 @@ diagram-design/
│ ├── sample-readme-with-mermaid.md │ ├── sample-readme-with-mermaid.md
│ └── sample-adversarial.mmd │ └── sample-adversarial.mmd
├── docs/adr/ — short records of settled design decisions ├── docs/adr/ — short records of settled design decisions
└── docs/screenshots/ — images used in this README └── docs/screenshots/ — README images + source-digest manifest.json
``` ```
This keeps the agent's working context tight: routine diagrams load one type reference; behavior-rich diagrams add the routed semantic reference; animation adds its contract only when selected. This keeps the agent's working context tight: routine diagrams load one type reference; behavior-rich diagrams add the routed semantic reference; animation adds its contract only when selected.
+1 -1
View File
@@ -22,7 +22,7 @@ Accepts `.drawio`, `.drawio.xml`, `.xml`, `.drawio.png`, and `.drawio.svg`.
- `--detail=balanced` · `--audience=mixed`. - `--detail=balanced` · `--audience=mixed`.
- `--variant=light` — the minimal light template. - `--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. - 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 37. - Type is chosen from the extracted structure; `--type` forces one of the 38.
## Flags ## Flags
+1 -1
View File
@@ -22,7 +22,7 @@ Accepts `.mmd`, `.mermaid`, and Markdown files containing fenced `mermaid` block
- `--detail=balanced` · `--audience=mixed`. - `--detail=balanced` · `--audience=mixed`.
- `--variant=light` — the minimal light template. - `--variant=light` — the minimal light template.
- A single diagram selects diagram 0; a multi-block Markdown file lists blocks and asks which to use. - 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 37. - Type is chosen from the extracted grammar and structure; `--type` forces one of the 38.
## Flags ## Flags
Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 133 KiB

+357
View File
@@ -0,0 +1,357 @@
{
"schema_version": 1,
"renderer": {
"engine": "playwright-chromium",
"scale": 2.0,
"viewport": [
1440,
1000
],
"capture": "first-svg",
"font_gate": "document.fonts.ready"
},
"entries": [
{
"slug": "architecture",
"source": "skills/diagram-design/assets/example-architecture.html",
"screenshot": "docs/screenshots/architecture.png",
"source_sha256": "03716fdb0a4ad641c30a5267b14a4c573d699f0f31ab3d8a0ba4e2b74ad56177",
"screenshot_sha256": "2258aef552e8e83aa9936ab4ca2b58fbee76fdb742cc4f68ce6499785b80f614",
"width": 2400,
"height": 1154
},
{
"slug": "it-state",
"source": "skills/diagram-design/assets/example-it-state.html",
"screenshot": "docs/screenshots/it-state.png",
"source_sha256": "59103bffa775b744828643e361b71f4b80e5ef8a0042abe9ce65c81e3d5dd21e",
"screenshot_sha256": "e8cd7d4453118bfd10bd3dd875703d673c5f9eaef38d9c9fcdceca38e05ed428",
"width": 2400,
"height": 1252
},
{
"slug": "flowchart",
"source": "skills/diagram-design/assets/example-flowchart.html",
"screenshot": "docs/screenshots/flowchart.png",
"source_sha256": "ba0a39df57d5fd4beccebeb51d62028b420371b30793b2658d308df04d571ff3",
"screenshot_sha256": "47c84d9f89a4e60ad131b05b0619e356894052d0477a8b3b024d56e5bd91b517",
"width": 2400,
"height": 1442
},
{
"slug": "sequence",
"source": "skills/diagram-design/assets/example-sequence.html",
"screenshot": "docs/screenshots/sequence.png",
"source_sha256": "12dcedc98c28d15f7a455f1266c8d8bd93bebe1ed8f352d89bc20703eaa00fad",
"screenshot_sha256": "224bc43edef8c8ebe9260ad38f292bdc6efaf45cb3fe57be64ca2704cc58b2c2",
"width": 2400,
"height": 1402
},
{
"slug": "state",
"source": "skills/diagram-design/assets/example-state.html",
"screenshot": "docs/screenshots/state.png",
"source_sha256": "75521144ce5aaf477096f355e86ae2d3301eb136391a6bd0702a844a8fe7ce30",
"screenshot_sha256": "60cfc8e2e67bbae841dad46280de7fe30425789cbd8ec1d776c0e7ed3bdc0871",
"width": 2400,
"height": 1106
},
{
"slug": "er",
"source": "skills/diagram-design/assets/example-er.html",
"screenshot": "docs/screenshots/er.png",
"source_sha256": "aee470dcf37af317f14d21cd9420f6bcb1b65f0fb0047483a42b8afc0cab2774",
"screenshot_sha256": "8ce5d595238c8adf710a4c36bb2def7f2488dc88a1afb5ed3e73b0f9dc0f565f",
"width": 2400,
"height": 1154
},
{
"slug": "timeline",
"source": "skills/diagram-design/assets/example-timeline.html",
"screenshot": "docs/screenshots/timeline.png",
"source_sha256": "1a58e3824eb2bb89ff6e57439b61c38d6e4c08b187143436f50108d8e60bfc45",
"screenshot_sha256": "c2da6df558afa9e94ad134348729533b9726836398576ad595795d1abf9e767d",
"width": 2400,
"height": 1010
},
{
"slug": "swimlane",
"source": "skills/diagram-design/assets/example-swimlane.html",
"screenshot": "docs/screenshots/swimlane.png",
"source_sha256": "75fc463ad3282dd0faaa4328c6b07f7e853184eeb1edcff2add8f7ed1876ab3b",
"screenshot_sha256": "562c47b77f177732aa0e5fffe2ce32426c121b4e98fa28f9f482aba1d73dba38",
"width": 2400,
"height": 1154
},
{
"slug": "quadrant",
"source": "skills/diagram-design/assets/example-quadrant.html",
"screenshot": "docs/screenshots/quadrant.png",
"source_sha256": "a147cc85f78958da824d53d226067bff687f3e35a64601394c3075f55c675648",
"screenshot_sha256": "c8235b122853a2ab32c981c849c2df3e813435fd34cefc776f5e4cca55b2c8b4",
"width": 2400,
"height": 1202
},
{
"slug": "radar",
"source": "skills/diagram-design/assets/example-radar.html",
"screenshot": "docs/screenshots/radar.png",
"source_sha256": "767b6a52116665a75b5895c1bde6d96a6a3277449229ff7e21b33afff9b9fcdf",
"screenshot_sha256": "4bd26ecc002557e9063a65e1f374bcb8cc5fd05d59078788c2edb07582271326",
"width": 2400,
"height": 1202
},
{
"slug": "loop",
"source": "skills/diagram-design/assets/example-loop.html",
"screenshot": "docs/screenshots/loop.png",
"source_sha256": "b5d0e37b14614ba95d95cdbc5ecdfb84c6c03d7cf664124e029cecb97af340bc",
"screenshot_sha256": "83461f3b0fc9c42319cac54a09ee0b3745987327f72095c1aba1209a4a8d269f",
"width": 2400,
"height": 1570
},
{
"slug": "nested",
"source": "skills/diagram-design/assets/example-nested.html",
"screenshot": "docs/screenshots/nested.png",
"source_sha256": "17648e5a26604bf678d7cd256ec0d84a54f7f2c6920fb56c030226e6ffc6557a",
"screenshot_sha256": "7199d6871a0aab4377af0002a42c3dc9daee9e869f1131493ecf6e17a5a1cac0",
"width": 2400,
"height": 1202
},
{
"slug": "tree",
"source": "skills/diagram-design/assets/example-tree.html",
"screenshot": "docs/screenshots/tree.png",
"source_sha256": "5de9151661ad9e1b21809d58494390472cdd82ca1ef1ddcde88b6f14e667afcd",
"screenshot_sha256": "7703d9c26e64350d79dda9c82dc1c5bdf4257251e89091697154193cc2634818",
"width": 2400,
"height": 1154
},
{
"slug": "org-chart",
"source": "skills/diagram-design/assets/example-org-chart.html",
"screenshot": "docs/screenshots/org-chart.png",
"source_sha256": "8c4e95ee52d597f28743673ea11f01ecfcf1a230d6f3dfb6d5ad641b770af46c",
"screenshot_sha256": "3e53f9f739b2bde2ed5c5715fc677f8c363e888bd2041bcba40b0f4361bcfd19",
"width": 2360,
"height": 1408
},
{
"slug": "layers",
"source": "skills/diagram-design/assets/example-layers.html",
"screenshot": "docs/screenshots/layers.png",
"source_sha256": "196f3cd9866d64da9e04323f258534b1a51d1116140c0db2c8e330adb516a809",
"screenshot_sha256": "74f5708645ba4a30cb65f8d6f2ae997ab6229140f3db7384aaf8ade9ada46cfe",
"width": 2400,
"height": 1202
},
{
"slug": "venn",
"source": "skills/diagram-design/assets/example-venn.html",
"screenshot": "docs/screenshots/venn.png",
"source_sha256": "86d763a94bc20fb3038cb00b9ef0fedd1e00cd8009df50852eac77d92e3965da",
"screenshot_sha256": "36c6bd3ada49450efae5199f677ab7c3a28c09c829d4b7faac1fcdedb5ef5a5d",
"width": 2400,
"height": 1154
},
{
"slug": "pyramid",
"source": "skills/diagram-design/assets/example-pyramid.html",
"screenshot": "docs/screenshots/pyramid.png",
"source_sha256": "d12cf7c4c921f3bbd66026af9ed947ff23acdcf414a4309b59c173377d9bdd80",
"screenshot_sha256": "69cc3ab86ff9feb43fb0ef57f1a2063ad76723966555e2309766c8aee11e4834",
"width": 2400,
"height": 1202
},
{
"slug": "bar",
"source": "skills/diagram-design/assets/example-bar.html",
"screenshot": "docs/screenshots/bar.png",
"source_sha256": "1bbd708cdca419c137160056ed9862532a3402ba65d9335bae1be0aef90c7abb",
"screenshot_sha256": "80b5373404a6fc2d8163edee06a6b37a5737364968be0d3b010c0e7103355173",
"width": 2400,
"height": 1202
},
{
"slug": "treemap",
"source": "skills/diagram-design/assets/example-treemap.html",
"screenshot": "docs/screenshots/treemap.png",
"source_sha256": "41e11b175c5c2e77716b1193c28ae9e02bde755283d8624628d1f1c9e9a78a4e",
"screenshot_sha256": "b9e2b356e444bd75284130e31e71a7c6c5c1bd880fca066083bd9de87cca9372",
"width": 2400,
"height": 1202
},
{
"slug": "line",
"source": "skills/diagram-design/assets/example-line.html",
"screenshot": "docs/screenshots/line.png",
"source_sha256": "83f5e305d6ce509b25371db6f6e73fa6f3982b7a8dbe09451091c0a15f3b1d90",
"screenshot_sha256": "411caacff9cd215ec7a9e9ca03d1808467ba1b95288d9cfbd64aeba83ca57f28",
"width": 2400,
"height": 1202
},
{
"slug": "gantt",
"source": "skills/diagram-design/assets/example-gantt.html",
"screenshot": "docs/screenshots/gantt.png",
"source_sha256": "607745921006b312ab710c3166036aebeb31a2b7cd40df36713a850a28cb73f3",
"screenshot_sha256": "d4dbac5e12e4e93a203908085e3aba0581ba7a895e222480b22570dca1ef0ffd",
"width": 2400,
"height": 1202
},
{
"slug": "scatter",
"source": "skills/diagram-design/assets/example-scatter.html",
"screenshot": "docs/screenshots/scatter.png",
"source_sha256": "576e0061f65b1885cf5fccb794c2827b19fbea66cc14e8284f3fa075ef755d06",
"screenshot_sha256": "a1524da60146ac78039b45aca7d39bef42b49e34d295858729d6fa45c636f177",
"width": 2400,
"height": 1202
},
{
"slug": "high-level",
"source": "skills/diagram-design/assets/example-high-level.html",
"screenshot": "docs/screenshots/high-level.png",
"source_sha256": "33789942cb06be5228ffa6e450602d1f7c9344b7d263fa2674b7ba5e6dd7e788",
"screenshot_sha256": "afe822249fbbb601657edc468d5572d2c4a6acc8cbef4ea41771d42d13e3b75e",
"width": 2400,
"height": 1298
},
{
"slug": "process",
"source": "skills/diagram-design/assets/example-process.html",
"screenshot": "docs/screenshots/process.png",
"source_sha256": "50ca0b9e6a3e9f5ba8102ff3c6fb87b6a66b1d59f272777b72a97639d4fe2375",
"screenshot_sha256": "70b6756e5d692c273d2e394f212a2e117148cb899cf7d5ae2f6db4355d6cf022",
"width": 2240,
"height": 920
},
{
"slug": "medallion",
"source": "skills/diagram-design/assets/example-medallion.html",
"screenshot": "docs/screenshots/medallion.png",
"source_sha256": "e88a5b1f1f67a7bf6ad83c5144a7f79973a732f68972ba648ec81968579032eb",
"screenshot_sha256": "811dbce44a7bf9b7bbcdd0d3ea36389c83e23b49f81516e939f13661ac3e5ef4",
"width": 2400,
"height": 1266
},
{
"slug": "data-flow",
"source": "skills/diagram-design/assets/example-data-flow.html",
"screenshot": "docs/screenshots/data-flow.png",
"source_sha256": "511788f809b9d674e2f92568955e5fc0c5f5f7a3960eaa0049e136ec93957add",
"screenshot_sha256": "25d71f2662e4383f8b2167ed807a4232fcfc24b8188168152a3ea879c2751954",
"width": 2400,
"height": 1176
},
{
"slug": "dp-integration",
"source": "skills/diagram-design/assets/example-dp-integration.html",
"screenshot": "docs/screenshots/dp-integration.png",
"source_sha256": "929b6aaefa9a362d4cd18fb1801a57f28d32aa8dd78ba577375a11926ee2cc94",
"screenshot_sha256": "abb41e56d502d7d77cb1dbe46bfb5b612696bdb26c38ff347c81f581c2f0ed2a",
"width": 2400,
"height": 1330
},
{
"slug": "dp-security-matrix",
"source": "skills/diagram-design/assets/example-dp-security-matrix.html",
"screenshot": "docs/screenshots/dp-security-matrix.png",
"source_sha256": "88d7a3fb9788300082274924f1f95dfd0a5a8b3bfca3fcd91b424cc8caa50044",
"screenshot_sha256": "a8f054d9562eab854fcc1ea554605f80d56a8a3334d491108834b1a82d03a6f7",
"width": 2400,
"height": 888
},
{
"slug": "sankey",
"source": "skills/diagram-design/assets/example-sankey.html",
"screenshot": "docs/screenshots/sankey.png",
"source_sha256": "f9196488b04763405fe56a56ed201630ce63aa86c96dcf8ba652d3927093707c",
"screenshot_sha256": "3acec7a81cbdc7d8bb5eb49caf4bb30ec594dbdd165b02c825293fe8edf6b52c",
"width": 2400,
"height": 1346
},
{
"slug": "fishbone",
"source": "skills/diagram-design/assets/example-fishbone.html",
"screenshot": "docs/screenshots/fishbone.png",
"source_sha256": "cd7079857240a9f6228804d3492af0add2eb36343798c9e0ef90657f2a246d04",
"screenshot_sha256": "c634bb13367a2299d862dc84f0046017d5067ab64498784024a220576b473f33",
"width": 2640,
"height": 1072
},
{
"slug": "wardley",
"source": "skills/diagram-design/assets/example-wardley.html",
"screenshot": "docs/screenshots/wardley.png",
"source_sha256": "b0ffc8f5bde65a8d77d863f22cd6c0d0211490c059dbcb503798851d1413860a",
"screenshot_sha256": "22466ff1159465a9e127b09932ef304b88a6d6c1f10b05554592e307abaa9a75",
"width": 2400,
"height": 1106
},
{
"slug": "kanban",
"source": "skills/diagram-design/assets/example-kanban.html",
"screenshot": "docs/screenshots/kanban.png",
"source_sha256": "3b19fb185019e0e341496de095bb1d92bd1fe4705c1502562ef47cb88329b2bb",
"screenshot_sha256": "509af93dd2441e1e359c6755cf9b79cba9ec31c9b4b13f06979acf1b0b24ae95",
"width": 2400,
"height": 946
},
{
"slug": "journey",
"source": "skills/diagram-design/assets/example-journey.html",
"screenshot": "docs/screenshots/journey.png",
"source_sha256": "b01e32ff87d63fddf6d1db47155906dd624acc13327856269114f760afc754f0",
"screenshot_sha256": "26cc8bb0d2aec927046dc128c06b7a93b51ab131e815dda60ba684d6c177de81",
"width": 2560,
"height": 1110
},
{
"slug": "deployment",
"source": "skills/diagram-design/assets/example-deployment.html",
"screenshot": "docs/screenshots/deployment.png",
"source_sha256": "6e28f0eee98dd728bfa6b5210b1885caf2b39992fdd06a680e37bbc8863e89b2",
"screenshot_sha256": "cb216a1a8dd18ee31493b4d19ec29051022075ae227a4c64e5de7b5ef86a4e25",
"width": 2400,
"height": 962
},
{
"slug": "dependency",
"source": "skills/diagram-design/assets/example-dependency.html",
"screenshot": "docs/screenshots/dependency.png",
"source_sha256": "973f7b5f5ac1746bb018e9ea8de9f6853b5f14ff41173e64abcf9855ea5f353b",
"screenshot_sha256": "817d52acd84d5dbfce6f8b3806ee151afbe12379f681ab3a87f203c85546420d",
"width": 2400,
"height": 1442
},
{
"slug": "uml-class",
"source": "skills/diagram-design/assets/example-uml-class.html",
"screenshot": "docs/screenshots/uml-class.png",
"source_sha256": "c6c353f4d53c476fc3530f20d09cdb9d4b47a2bd22d0f3c56c807732534a685d",
"screenshot_sha256": "27990fb2b79df122bfff3c6f06e9a4898d59b2d285f65f37145949835149037c",
"width": 2480,
"height": 1682
},
{
"slug": "story-map",
"source": "skills/diagram-design/assets/example-story-map.html",
"screenshot": "docs/screenshots/story-map.png",
"source_sha256": "40f737ca1c2a9f46cd8a3ad1a377faabc1adc546a410ff8395e6622b4e773da1",
"screenshot_sha256": "2adaaf914b772a81743fd2600d0c44b96224d06dfeeac1da83f282227d6e541a",
"width": 2400,
"height": 1258
},
{
"slug": "db-schema",
"source": "skills/diagram-design/assets/example-db-schema.html",
"screenshot": "docs/screenshots/db-schema.png",
"source_sha256": "58d473906c57670fecee29bc55377df5b433549445962204412ebd2c081b76db",
"screenshot_sha256": "939061c701f7bb70aa1b5f7ee1fe2da3a68b3b8edc4822cd9dcb7586acd7a2d6",
"width": 2480,
"height": 1288
}
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Render the 38 canonical minimal-light examples and record their digests."""
from __future__ import annotations
import json
from playwright.sync_api import sync_playwright
from screenshot_catalog import (
MANIFEST,
ROOT,
SCREENSHOT_DIR,
canonical_slugs,
png_dimensions,
screenshot_path,
sha256,
source_path,
)
def main() -> int:
slugs = canonical_slugs()
if len(slugs) != 38 or len(slugs) != len(set(slugs)):
raise SystemExit(f"expected 38 unique canonical types; found {len(slugs)}")
SCREENSHOT_DIR.mkdir(parents=True, exist_ok=True)
entries: list[dict[str, object]] = []
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
page = browser.new_page(
viewport={"width": 1440, "height": 1000},
device_scale_factor=2,
)
for index, slug in enumerate(slugs, 1):
source = source_path(slug)
output = screenshot_path(slug)
if not source.is_file():
raise SystemExit(f"missing canonical example: {source.relative_to(ROOT)}")
page.goto(source.resolve().as_uri(), wait_until="networkidle")
page.evaluate("() => document.fonts.ready")
svg = page.locator("svg").first
if svg.count() != 1:
raise SystemExit(f"no first SVG found in {source.relative_to(ROOT)}")
svg.screenshot(path=str(output), omit_background=True)
width, height = png_dimensions(output)
entries.append(
{
"slug": slug,
"source": source.relative_to(ROOT).as_posix(),
"screenshot": output.relative_to(ROOT).as_posix(),
"source_sha256": sha256(source),
"screenshot_sha256": sha256(output),
"width": width,
"height": height,
}
)
print(f"[{index:02d}/38] {slug}: {width}x{height}")
browser.close()
payload = {
"schema_version": 1,
"renderer": {
"engine": "playwright-chromium",
"scale": 2.0,
"viewport": [1440, 1000],
"capture": "first-svg",
"font_gate": "document.fonts.ready",
},
"entries": entries,
}
MANIFEST.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
print(f"Wrote {MANIFEST.relative_to(ROOT)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+54
View File
@@ -0,0 +1,54 @@
"""Shared helpers for the canonical README screenshot catalog."""
from __future__ import annotations
import hashlib
import re
import struct
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SKILL = ROOT / "skills/diagram-design/SKILL.md"
ASSET_DIR = ROOT / "skills/diagram-design/assets"
SCREENSHOT_DIR = ROOT / "docs/screenshots"
MANIFEST = SCREENSHOT_DIR / "manifest.json"
def canonical_slugs() -> list[str]:
"""Return the visual-type order declared by SKILL.md's selection table."""
markdown = SKILL.read_text(encoding="utf-8")
start = markdown.find("### Visual-type guide")
end = markdown.find("Rules of thumb", start)
if start < 0 or end < 0:
raise ValueError("SKILL.md visual-type guide is missing")
return re.findall(
r"^\|[^\n]*\]\(references/type-([a-z0-9-]+)\.md\)\s*\|$",
markdown[start:end],
re.MULTILINE,
)
def source_path(slug: str) -> Path:
return ASSET_DIR / f"example-{slug}.html"
def screenshot_path(slug: str) -> Path:
return SCREENSHOT_DIR / f"{slug}.png"
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def png_dimensions(path: Path) -> tuple[int, int]:
with path.open("rb") as handle:
header = handle.read(24)
if len(header) != 24 or header[:8] != b"\x89PNG\r\n\x1a\n":
raise ValueError(f"not a PNG: {path}")
return struct.unpack(">II", header[16:24])
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Fail when a canonical example or committed screenshot drifts from its manifest."""
from __future__ import annotations
import json
import sys
from screenshot_catalog import (
MANIFEST,
ROOT,
canonical_slugs,
png_dimensions,
screenshot_path,
sha256,
source_path,
)
def main() -> int:
errors: list[str] = []
slugs = canonical_slugs()
if len(slugs) != 38 or len(slugs) != len(set(slugs)):
errors.append(f"expected 38 unique canonical types; found {len(slugs)}")
if not MANIFEST.is_file():
errors.append("docs/screenshots/manifest.json is missing")
payload: dict[str, object] = {}
else:
try:
payload = json.loads(MANIFEST.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError) as exc:
errors.append(f"cannot read screenshot manifest: {exc}")
payload = {}
if payload.get("schema_version") != 1:
errors.append("screenshot manifest schema_version must be 1")
renderer = payload.get("renderer")
expected_renderer = {
"engine": "playwright-chromium",
"scale": 2.0,
"viewport": [1440, 1000],
"capture": "first-svg",
"font_gate": "document.fonts.ready",
}
if renderer != expected_renderer:
errors.append("screenshot manifest must use the canonical 1440x1000, 2x SVG renderer")
entries = payload.get("entries", [])
if not isinstance(entries, list):
errors.append("screenshot manifest entries must be a list")
entries = []
manifest_slugs = [entry.get("slug") for entry in entries if isinstance(entry, dict)]
if manifest_slugs != slugs:
errors.append("screenshot manifest order does not match SKILL.md's canonical type order")
by_slug = {
entry.get("slug"): entry
for entry in entries
if isinstance(entry, dict) and isinstance(entry.get("slug"), str)
}
for slug in slugs:
source = source_path(slug)
screenshot = screenshot_path(slug)
entry = by_slug.get(slug)
if not source.is_file():
errors.append(f"missing canonical example: {source.relative_to(ROOT)}")
continue
if not screenshot.is_file():
errors.append(f"missing canonical screenshot: {screenshot.relative_to(ROOT)}")
continue
if not entry:
errors.append(f"manifest has no entry for {slug}")
continue
expected_source = source.relative_to(ROOT).as_posix()
expected_screenshot = screenshot.relative_to(ROOT).as_posix()
if entry.get("source") != expected_source:
errors.append(f"{slug}: manifest source must be {expected_source}")
if entry.get("screenshot") != expected_screenshot:
errors.append(f"{slug}: manifest screenshot must be {expected_screenshot}")
if entry.get("source_sha256") != sha256(source):
errors.append(f"{slug}: source changed; rerun scripts/render-canonical-screenshots.py")
if entry.get("screenshot_sha256") != sha256(screenshot):
errors.append(f"{slug}: screenshot changed without a matching manifest refresh")
try:
width, height = png_dimensions(screenshot)
except ValueError as exc:
errors.append(str(exc))
else:
if [entry.get("width"), entry.get("height")] != [width, height]:
errors.append(f"{slug}: manifest dimensions do not match the PNG")
if errors:
print("FAIL screenshot freshness")
for error in errors:
print(f" - {error}")
return 1
print("OK screenshot freshness: 38 canonical sources and PNG digests match")
return 0
if __name__ == "__main__":
sys.exit(main())