scrum-skills 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/diagram-design/LICENSE +4 -0
- package/.agents/skills/diagram-design/SKILL.md +413 -0
- package/.agents/skills/diagram-design/UPSTREAM.json +76 -0
- package/.agents/skills/diagram-design/UPSTREAM.md +23 -0
- package/.agents/skills/diagram-design/assets/example-architecture-containment.html +205 -0
- package/.agents/skills/diagram-design/assets/example-architecture-delta.html +193 -0
- package/.agents/skills/diagram-design/assets/example-architecture.html +183 -0
- package/.agents/skills/diagram-design/assets/example-axonometric-plan-campus.html +108 -0
- package/.agents/skills/diagram-design/assets/example-axonometric-plan-coffee-shop.html +121 -0
- package/.agents/skills/diagram-design/assets/example-axonometric-plan-warehouse.html +127 -0
- package/.agents/skills/diagram-design/assets/example-axonometric-plan.html +114 -0
- package/.agents/skills/diagram-design/assets/example-bar.html +129 -0
- package/.agents/skills/diagram-design/assets/example-beeswarm.html +384 -0
- package/.agents/skills/diagram-design/assets/example-box-plot.html +127 -0
- package/.agents/skills/diagram-design/assets/example-bubble.html +147 -0
- package/.agents/skills/diagram-design/assets/example-bump.html +142 -0
- package/.agents/skills/diagram-design/assets/example-data-flow.html +143 -0
- package/.agents/skills/diagram-design/assets/example-datalake.html +269 -0
- package/.agents/skills/diagram-design/assets/example-db-schema.html +302 -0
- package/.agents/skills/diagram-design/assets/example-dependency.html +224 -0
- package/.agents/skills/diagram-design/assets/example-deployment.html +190 -0
- package/.agents/skills/diagram-design/assets/example-dp-integration.html +81 -0
- package/.agents/skills/diagram-design/assets/example-dp-security-matrix.html +88 -0
- package/.agents/skills/diagram-design/assets/example-er.html +202 -0
- package/.agents/skills/diagram-design/assets/example-exploded-ai-stack.html +85 -0
- package/.agents/skills/diagram-design/assets/example-exploded-keyboard.html +84 -0
- package/.agents/skills/diagram-design/assets/example-exploded-phone.html +83 -0
- package/.agents/skills/diagram-design/assets/example-exploded-unboxing.html +84 -0
- package/.agents/skills/diagram-design/assets/example-exploded.html +83 -0
- package/.agents/skills/diagram-design/assets/example-fishbone.html +152 -0
- package/.agents/skills/diagram-design/assets/example-flowchart.html +163 -0
- package/.agents/skills/diagram-design/assets/example-gantt.html +137 -0
- package/.agents/skills/diagram-design/assets/example-heatmap.html +224 -0
- package/.agents/skills/diagram-design/assets/example-high-level-vertical.html +325 -0
- package/.agents/skills/diagram-design/assets/example-high-level.html +301 -0
- package/.agents/skills/diagram-design/assets/example-import-drawio.html +185 -0
- package/.agents/skills/diagram-design/assets/example-import-excalidraw.html +70 -0
- package/.agents/skills/diagram-design/assets/example-import-mermaid.html +70 -0
- package/.agents/skills/diagram-design/assets/example-it-state.html +128 -0
- package/.agents/skills/diagram-design/assets/example-journey.html +148 -0
- package/.agents/skills/diagram-design/assets/example-kanban.html +174 -0
- package/.agents/skills/diagram-design/assets/example-layers.html +123 -0
- package/.agents/skills/diagram-design/assets/example-line.html +111 -0
- package/.agents/skills/diagram-design/assets/example-loop.html +100 -0
- package/.agents/skills/diagram-design/assets/example-marimekko.html +148 -0
- package/.agents/skills/diagram-design/assets/example-medallion.html +159 -0
- package/.agents/skills/diagram-design/assets/example-nested.html +136 -0
- package/.agents/skills/diagram-design/assets/example-org-chart.html +45 -0
- package/.agents/skills/diagram-design/assets/example-polar.html +116 -0
- package/.agents/skills/diagram-design/assets/example-process.html +64 -0
- package/.agents/skills/diagram-design/assets/example-pyramid.html +119 -0
- package/.agents/skills/diagram-design/assets/example-quadrant-consultant.html +166 -0
- package/.agents/skills/diagram-design/assets/example-quadrant.html +135 -0
- package/.agents/skills/diagram-design/assets/example-radar.html +139 -0
- package/.agents/skills/diagram-design/assets/example-ridgeline.html +104 -0
- package/.agents/skills/diagram-design/assets/example-sankey.html +150 -0
- package/.agents/skills/diagram-design/assets/example-scatter.html +141 -0
- package/.agents/skills/diagram-design/assets/example-sequence-oauth.html +227 -0
- package/.agents/skills/diagram-design/assets/example-sequence.html +222 -0
- package/.agents/skills/diagram-design/assets/example-service-blueprint.html +185 -0
- package/.agents/skills/diagram-design/assets/example-slopegraph.html +119 -0
- package/.agents/skills/diagram-design/assets/example-state-lifecycle.html +92 -0
- package/.agents/skills/diagram-design/assets/example-state.html +147 -0
- package/.agents/skills/diagram-design/assets/example-story-map.html +184 -0
- package/.agents/skills/diagram-design/assets/example-streamgraph.html +99 -0
- package/.agents/skills/diagram-design/assets/example-swimlane.html +172 -0
- package/.agents/skills/diagram-design/assets/example-timeline.html +135 -0
- package/.agents/skills/diagram-design/assets/example-tree-block-decomposition.html +151 -0
- package/.agents/skills/diagram-design/assets/example-tree.html +173 -0
- package/.agents/skills/diagram-design/assets/example-treemap.html +107 -0
- package/.agents/skills/diagram-design/assets/example-uml-class.html +188 -0
- package/.agents/skills/diagram-design/assets/example-venn.html +110 -0
- package/.agents/skills/diagram-design/assets/example-wardley.html +153 -0
- package/.agents/skills/diagram-design/assets/example-waterfall.html +129 -0
- package/.agents/skills/diagram-design/assets/template-dark.html +99 -0
- package/.agents/skills/diagram-design/assets/template-full.html +421 -0
- package/.agents/skills/diagram-design/assets/template-motion.html +448 -0
- package/.agents/skills/diagram-design/assets/template-terminal.html +188 -0
- package/.agents/skills/diagram-design/assets/template.html +100 -0
- package/.agents/skills/diagram-design/references/animation.md +143 -0
- package/.agents/skills/diagram-design/references/export-registry.md +78 -0
- package/.agents/skills/diagram-design/references/export.md +376 -0
- package/.agents/skills/diagram-design/references/import-drawio.md +181 -0
- package/.agents/skills/diagram-design/references/import-excalidraw.md +130 -0
- package/.agents/skills/diagram-design/references/import-mermaid.md +137 -0
- package/.agents/skills/diagram-design/references/layout-budget.md +97 -0
- package/.agents/skills/diagram-design/references/onboarding.md +368 -0
- package/.agents/skills/diagram-design/references/output-spec.md +277 -0
- package/.agents/skills/diagram-design/references/primitive-annotation.md +36 -0
- package/.agents/skills/diagram-design/references/primitive-icons.md +827 -0
- package/.agents/skills/diagram-design/references/primitive-sketchy.md +43 -0
- package/.agents/skills/diagram-design/references/primitive-terminal.md +76 -0
- package/.agents/skills/diagram-design/references/primitives-core.md +146 -0
- package/.agents/skills/diagram-design/references/profiles.md +183 -0
- package/.agents/skills/diagram-design/references/semantic-patterns.md +154 -0
- package/.agents/skills/diagram-design/references/style-guide.md +236 -0
- package/.agents/skills/diagram-design/references/style-vivid.md +148 -0
- package/.agents/skills/diagram-design/references/type-architecture-delta.md +143 -0
- package/.agents/skills/diagram-design/references/type-architecture.md +117 -0
- package/.agents/skills/diagram-design/references/type-axonometric-plan.md +83 -0
- package/.agents/skills/diagram-design/references/type-bar.md +108 -0
- package/.agents/skills/diagram-design/references/type-data-flow.md +371 -0
- package/.agents/skills/diagram-design/references/type-db-schema.md +48 -0
- package/.agents/skills/diagram-design/references/type-dependency.md +44 -0
- package/.agents/skills/diagram-design/references/type-deployment.md +45 -0
- package/.agents/skills/diagram-design/references/type-dp-integration.md +407 -0
- package/.agents/skills/diagram-design/references/type-dp-security-matrix.md +379 -0
- package/.agents/skills/diagram-design/references/type-er.md +25 -0
- package/.agents/skills/diagram-design/references/type-exploded.md +115 -0
- package/.agents/skills/diagram-design/references/type-fishbone.md +75 -0
- package/.agents/skills/diagram-design/references/type-flowchart.md +23 -0
- package/.agents/skills/diagram-design/references/type-gantt.md +45 -0
- package/.agents/skills/diagram-design/references/type-heatmap.md +80 -0
- package/.agents/skills/diagram-design/references/type-high-level.md +470 -0
- package/.agents/skills/diagram-design/references/type-it-state.md +468 -0
- package/.agents/skills/diagram-design/references/type-journey.md +55 -0
- package/.agents/skills/diagram-design/references/type-kanban.md +49 -0
- package/.agents/skills/diagram-design/references/type-layers.md +26 -0
- package/.agents/skills/diagram-design/references/type-line.md +337 -0
- package/.agents/skills/diagram-design/references/type-loop.md +223 -0
- package/.agents/skills/diagram-design/references/type-medallion.md +356 -0
- package/.agents/skills/diagram-design/references/type-nested.md +22 -0
- package/.agents/skills/diagram-design/references/type-org-chart.md +44 -0
- package/.agents/skills/diagram-design/references/type-polar.md +136 -0
- package/.agents/skills/diagram-design/references/type-process.md +490 -0
- package/.agents/skills/diagram-design/references/type-pyramid.md +33 -0
- package/.agents/skills/diagram-design/references/type-quadrant.md +81 -0
- package/.agents/skills/diagram-design/references/type-radar.md +82 -0
- package/.agents/skills/diagram-design/references/type-sankey.md +75 -0
- package/.agents/skills/diagram-design/references/type-scatter.md +276 -0
- package/.agents/skills/diagram-design/references/type-sequence.md +130 -0
- package/.agents/skills/diagram-design/references/type-service-blueprint.md +103 -0
- package/.agents/skills/diagram-design/references/type-state.md +30 -0
- package/.agents/skills/diagram-design/references/type-story-map.md +46 -0
- package/.agents/skills/diagram-design/references/type-swimlane.md +22 -0
- package/.agents/skills/diagram-design/references/type-timeline.md +20 -0
- package/.agents/skills/diagram-design/references/type-tree.md +24 -0
- package/.agents/skills/diagram-design/references/type-treemap.md +137 -0
- package/.agents/skills/diagram-design/references/type-uml-class.md +65 -0
- package/.agents/skills/diagram-design/references/type-venn.md +26 -0
- package/.agents/skills/diagram-design/references/type-wardley.md +39 -0
- package/.agents/skills/diagram-design/references/type-waterfall.md +75 -0
- package/.agents/skills/scrum-meta/SKILL.md +36 -36
- package/.agents/skills/scrum-planning/SKILL.md +61 -61
- package/.agents/skills/scrum-planning/references/schema.md +384 -336
- package/.agents/skills/scrum-report/SKILL.md +42 -42
- package/.agents/skills/scrum-sprint/SKILL.md +49 -49
- package/.agents/skills/scrum-tdd/SKILL.md +140 -127
- package/README.md +224 -201
- package/assets/board/200.html +1 -1
- package/assets/board/404.html +1 -1
- package/assets/board/_nuxt/1XlYaCp9.js +1 -0
- package/assets/board/_nuxt/4gQF_HS3.js +1 -0
- package/assets/board/_nuxt/5okfNy5D.js +1 -0
- package/assets/board/_nuxt/{Bb3Limos.js → B0C2jsdk.js} +1 -1
- package/assets/board/_nuxt/B1j6UC4U.js +1 -0
- package/assets/board/_nuxt/B3LKy6o2.js +1 -0
- package/assets/board/_nuxt/BAQQngAq.js +13 -0
- package/assets/board/_nuxt/BE6t7Q2m.js +1 -0
- package/assets/board/_nuxt/BLvbupFS.js +1 -0
- package/assets/board/_nuxt/BQgzP7ur.js +1 -0
- package/assets/board/_nuxt/BRZIF_wo.js +1 -0
- package/assets/board/_nuxt/BW3xJdEx.js +1 -0
- package/assets/board/_nuxt/{Cm9lkUvP.js → BY36DFyj.js} +1 -1
- package/assets/board/_nuxt/BZlZD94i.js +1 -0
- package/assets/board/_nuxt/BZvXNwev.js +3 -0
- package/assets/board/_nuxt/BbxmvdIF.js +1 -0
- package/assets/board/_nuxt/BiWrMOsL.js +1 -0
- package/assets/board/_nuxt/BizDeOK5.js +1 -0
- package/assets/board/_nuxt/BkcaOYQ_.js +95 -0
- package/assets/board/_nuxt/BkoKCNUY.js +1 -0
- package/assets/board/_nuxt/BlKmZhhF.js +1 -0
- package/assets/board/_nuxt/BmBpmU73.js +1 -0
- package/assets/board/_nuxt/BrWE0up6.js +1 -0
- package/assets/board/_nuxt/Bs52qkgk.js +1 -0
- package/assets/board/_nuxt/BtzUbHO_.js +1 -0
- package/assets/board/_nuxt/BuBzMkFZ.js +1 -0
- package/assets/board/_nuxt/Bubk0xn-.js +1 -0
- package/assets/board/_nuxt/BxuBMtk_.js +3 -0
- package/assets/board/_nuxt/By1KXXLR.js +1 -0
- package/assets/board/_nuxt/BygIGL69.js +2 -0
- package/assets/board/_nuxt/C1iO5KH3.js +1 -0
- package/assets/board/_nuxt/C2YPmTzt.js +1 -0
- package/assets/board/_nuxt/C3SpAhCW.js +1 -0
- package/assets/board/_nuxt/C3ZRWz5L.js +1 -0
- package/assets/board/_nuxt/C4WdPP6K.js +1 -0
- package/assets/board/_nuxt/C6o03JHe.js +1 -0
- package/assets/board/_nuxt/C8qB5llI.js +1 -0
- package/assets/board/_nuxt/C9MgRdhu.js +1 -0
- package/assets/board/_nuxt/CCA81-4P.js +1 -0
- package/assets/board/_nuxt/{D2O8Q8x9.js → CFCM18fF.js} +1 -1
- package/assets/board/_nuxt/CGXljzd_.js +1 -0
- package/assets/board/_nuxt/CI0scS-N.js +1 -0
- package/assets/board/_nuxt/CJs9B42o.js +1 -0
- package/assets/board/_nuxt/COecDWbb.js +1 -0
- package/assets/board/_nuxt/COmtTtfB.js +1 -0
- package/assets/board/_nuxt/CPYm4J_K.js +1 -0
- package/assets/board/_nuxt/CReA4TEB.js +3 -0
- package/assets/board/_nuxt/CXG7GZes.js +1 -0
- package/assets/board/_nuxt/CYGiZn-X.js +1 -0
- package/assets/board/_nuxt/CaE8VlUp.js +1 -0
- package/assets/board/_nuxt/CcGiNUgA.js +1 -0
- package/assets/board/_nuxt/Ccgv3lDj.js +1 -0
- package/assets/board/_nuxt/CdPGFZyy.js +1 -0
- package/assets/board/_nuxt/{DfR3IZN_.js → Cdf_T8Xa.js} +1 -1
- package/assets/board/_nuxt/CgQ30j_6.js +1 -0
- package/assets/board/_nuxt/ChUHb39z.js +1 -0
- package/assets/board/_nuxt/Ck0-FqVI.js +1 -0
- package/assets/board/_nuxt/CkWKLtjO.js +1 -0
- package/assets/board/_nuxt/Cq7hsCKB.js +1 -0
- package/assets/board/_nuxt/CtFknnHZ.js +1 -0
- package/assets/board/_nuxt/D166WVUG.js +1 -0
- package/assets/board/_nuxt/D4Dpzo9e.js +1 -0
- package/assets/board/_nuxt/D5i92OZO.js +1 -0
- package/assets/board/_nuxt/D6dUp4Nm.js +9 -0
- package/assets/board/_nuxt/DFQDFspC.js +1 -0
- package/assets/board/_nuxt/DHX2tw9J.js +1 -0
- package/assets/board/_nuxt/DJM7u8P3.js +1 -0
- package/assets/board/_nuxt/{BPTrRhcw.js → DLr85ebo.js} +1 -1
- package/assets/board/_nuxt/DOMM1wfl.js +1 -0
- package/assets/board/_nuxt/DU6ArlUN.js +1 -0
- package/assets/board/_nuxt/{B_SlFcWp.js → DUgGsde6.js} +1 -1
- package/assets/board/_nuxt/DV4ti-Pq.js +1 -0
- package/assets/board/_nuxt/DZ--fXuU.js +1 -0
- package/assets/board/_nuxt/D_ct-Stz.js +2 -0
- package/assets/board/_nuxt/DbWAComO.js +1 -0
- package/assets/board/_nuxt/DbwlcHAt.js +1 -0
- package/assets/board/_nuxt/DjzLR9Bl.js +1 -0
- package/assets/board/_nuxt/Dki9VkAL.js +3 -0
- package/assets/board/_nuxt/DlNJhOoc.js +1 -0
- package/assets/board/_nuxt/DqG7CtD4.js +1 -0
- package/assets/board/_nuxt/DqUSsCJ2.js +1 -0
- package/assets/board/_nuxt/Du2F4WXh.js +1 -0
- package/assets/board/_nuxt/DuRiEXn4.js +1 -0
- package/assets/board/_nuxt/DxBwVNyP.js +2 -0
- package/assets/board/_nuxt/DzmVW5-D.js +1 -0
- package/assets/board/_nuxt/I-sGtDIB.js +6 -0
- package/assets/board/_nuxt/JU9-x68N.js +1 -0
- package/assets/board/_nuxt/Lozm7hhE.js +1 -0
- package/assets/board/_nuxt/MMsTMkcB.js +1 -0
- package/assets/board/_nuxt/MS7CGmCB.js +1 -0
- package/assets/board/_nuxt/OKKaKILz.js +1 -0
- package/assets/board/_nuxt/{Csqgy925.js → P6qlvBHA.js} +1 -1
- package/assets/board/_nuxt/SrNUvNwO.js +1 -0
- package/assets/board/_nuxt/{DSaWoFHS.js → SywdkA98.js} +1 -1
- package/assets/board/_nuxt/TBIRpVLG.js +1 -0
- package/assets/board/_nuxt/TlTrMIMm.js +1 -0
- package/assets/board/_nuxt/Zv9-SOQF.js +1 -0
- package/assets/board/_nuxt/_id_.ItzoSaBL.css +1 -0
- package/assets/board/_nuxt/builds/latest.json +1 -1
- package/assets/board/_nuxt/builds/meta/2218461a-f45b-41d6-ae44-b0d2332a9511.json +1 -0
- package/assets/board/_nuxt/burndown.CT8fx1Ge.css +1 -0
- package/assets/board/_nuxt/diagrams.D1ybqBem.css +1 -0
- package/assets/board/_nuxt/{entry.CKHePurH.css → entry.BCuHiFgF.css} +1 -1
- package/assets/board/_nuxt/epics.CUeDIEa0.css +1 -0
- package/assets/board/_nuxt/error-404.Y9imKiDC.css +1 -0
- package/assets/board/_nuxt/error-500.DufSBGVC.css +1 -0
- package/assets/board/_nuxt/gantt.CiC2Ts1t.css +1 -0
- package/assets/board/_nuxt/jbri6q1p.js +1 -0
- package/assets/board/_nuxt/last-change.C05Vc3BF.css +1 -0
- package/assets/board/_nuxt/milestones.Civ3sMiQ.css +1 -0
- package/assets/board/_nuxt/oSJF4yHw.js +1 -0
- package/assets/board/_nuxt/pages.BshWbOyo.css +1 -0
- package/assets/board/_nuxt/q_8bxRMt.js +1 -0
- package/assets/board/_nuxt/tests.Ci9fBCka.css +1 -0
- package/assets/board/burndown/index.html +1 -1
- package/assets/board/diagrams/index.html +1 -0
- package/assets/board/epics/index.html +1 -1
- package/assets/board/favicon.svg +16 -16
- package/assets/board/gantt/index.html +1 -1
- package/assets/board/index.html +1 -1
- package/assets/board/last-change/index.html +1 -1
- package/assets/board/milestones/index.html +1 -1
- package/assets/board/tests/index.html +1 -1
- package/bin/scrum-skills.mjs +204 -191
- package/docs/ai-assistant-guide.md +1008 -1008
- package/package.json +42 -41
- package/templates/AGENTS.md +84 -74
- package/tools/agile-tools.mjs +510 -510
- package/tools/ai.mjs +464 -464
- package/tools/diagram-import.mjs +238 -0
- package/tools/diagram-lint.mjs +518 -0
- package/tools/diagram.mjs +299 -0
- package/tools/git-commit.mjs +216 -216
- package/tools/last-change.mjs +326 -326
- package/tools/projects.mjs +240 -215
- package/tools/serve.mjs +180 -154
- package/tools/validate.mjs +781 -664
- package/assets/board/_nuxt/1eqboJxR.js +0 -1
- package/assets/board/_nuxt/2K7ag6ES.js +0 -1
- package/assets/board/_nuxt/51OWHj8c.js +0 -2
- package/assets/board/_nuxt/6gFtTBwm.js +0 -1
- package/assets/board/_nuxt/B3jkABw9.js +0 -1
- package/assets/board/_nuxt/B5n2_jZN.js +0 -1
- package/assets/board/_nuxt/BDK2Hj7B.js +0 -1
- package/assets/board/_nuxt/BDcnzXHq.js +0 -1
- package/assets/board/_nuxt/BaG8y0Wt.js +0 -1
- package/assets/board/_nuxt/BbwJq5pb.js +0 -1
- package/assets/board/_nuxt/BgLeKwx0.js +0 -1
- package/assets/board/_nuxt/Bi9Axj3V.js +0 -1
- package/assets/board/_nuxt/BmxvtaMq.js +0 -1
- package/assets/board/_nuxt/BodFvto3.js +0 -1
- package/assets/board/_nuxt/BpWeHLuN.js +0 -1
- package/assets/board/_nuxt/BuOKDFiJ.js +0 -1
- package/assets/board/_nuxt/C40iTe-x.js +0 -1
- package/assets/board/_nuxt/C7K0R7F-.js +0 -2
- package/assets/board/_nuxt/C8vL692X.js +0 -1
- package/assets/board/_nuxt/C9StZL3D.js +0 -3
- package/assets/board/_nuxt/CGI_ZV79.js +0 -1
- package/assets/board/_nuxt/CJ2mz0WY.js +0 -1
- package/assets/board/_nuxt/CJMBJQuf.js +0 -1
- package/assets/board/_nuxt/CK-lOYG9.js +0 -1
- package/assets/board/_nuxt/CK9_veoz.js +0 -1
- package/assets/board/_nuxt/CLBcBrYf.js +0 -1
- package/assets/board/_nuxt/CMUi2-Lj.js +0 -1
- package/assets/board/_nuxt/COf6E6h4.js +0 -1
- package/assets/board/_nuxt/CPCUMJnF.js +0 -1
- package/assets/board/_nuxt/CPcKlmSm.js +0 -1
- package/assets/board/_nuxt/CQTvWh4i.js +0 -1
- package/assets/board/_nuxt/CSEEUF8S.js +0 -1
- package/assets/board/_nuxt/CSSb154I.js +0 -13
- package/assets/board/_nuxt/CgDTd7jS.js +0 -1
- package/assets/board/_nuxt/ChG76uh9.js +0 -1
- package/assets/board/_nuxt/Ci0qbkgh.js +0 -1
- package/assets/board/_nuxt/CqoQ__I_.js +0 -1
- package/assets/board/_nuxt/CuJUHLl8.js +0 -1
- package/assets/board/_nuxt/CvLiA4_O.js +0 -1
- package/assets/board/_nuxt/Cvs12oA0.js +0 -3
- package/assets/board/_nuxt/CyEXFe3V.js +0 -1
- package/assets/board/_nuxt/Cz6rZcLK.js +0 -1
- package/assets/board/_nuxt/D2FhHl1o.js +0 -1
- package/assets/board/_nuxt/D3YCAmfu.js +0 -1
- package/assets/board/_nuxt/D5CE81jK.js +0 -1
- package/assets/board/_nuxt/D75vbfSb.js +0 -1
- package/assets/board/_nuxt/D99LbGfb.js +0 -9
- package/assets/board/_nuxt/DEfLc7p3.js +0 -6
- package/assets/board/_nuxt/DF-nsa1Z.js +0 -1
- package/assets/board/_nuxt/DIc8yx98.js +0 -1
- package/assets/board/_nuxt/DLkAKotw.js +0 -1
- package/assets/board/_nuxt/DRPlYvb3.js +0 -1
- package/assets/board/_nuxt/DRlQgul3.js +0 -1
- package/assets/board/_nuxt/DSLbmoWa.js +0 -1
- package/assets/board/_nuxt/DWO9c9yp.js +0 -1
- package/assets/board/_nuxt/DZo3dYLJ.js +0 -3
- package/assets/board/_nuxt/D_S6N7_b.js +0 -1
- package/assets/board/_nuxt/DajA-Tkt.js +0 -1
- package/assets/board/_nuxt/DbHiyab-.js +0 -1
- package/assets/board/_nuxt/Dc7Ql6eE.js +0 -1
- package/assets/board/_nuxt/Dd9ZukPU.js +0 -1
- package/assets/board/_nuxt/Dg2LiqmN.js +0 -1
- package/assets/board/_nuxt/DhuleNnm.js +0 -1
- package/assets/board/_nuxt/DkI1Qxpp.js +0 -95
- package/assets/board/_nuxt/DnDHGSYI.js +0 -1
- package/assets/board/_nuxt/DpXJ_tCU.js +0 -1
- package/assets/board/_nuxt/DqZgF3hU.js +0 -1
- package/assets/board/_nuxt/DqcxvfbD.js +0 -1
- package/assets/board/_nuxt/DsA2lVci.js +0 -1
- package/assets/board/_nuxt/Dtsa-1NS.js +0 -1
- package/assets/board/_nuxt/Du91iq0p.js +0 -1
- package/assets/board/_nuxt/Dx1wcYFo.js +0 -1
- package/assets/board/_nuxt/EYTShbt4.js +0 -1
- package/assets/board/_nuxt/MaXJprwN.js +0 -1
- package/assets/board/_nuxt/P9x67aq2.js +0 -1
- package/assets/board/_nuxt/S08nFESZ.js +0 -3
- package/assets/board/_nuxt/V0uynWE2.js +0 -1
- package/assets/board/_nuxt/Vo4wMbnS.js +0 -1
- package/assets/board/_nuxt/ZVTqot-_.js +0 -1
- package/assets/board/_nuxt/ZngEd3HB.js +0 -1
- package/assets/board/_nuxt/_id_.B2NDKSlX.css +0 -1
- package/assets/board/_nuxt/assMu_Wn.js +0 -1
- package/assets/board/_nuxt/builds/meta/8e23aec9-5b67-4569-b8bf-d4f07e50ffdf.json +0 -1
- package/assets/board/_nuxt/burndown.Do6IbM6o.css +0 -1
- package/assets/board/_nuxt/epics.Dmessplu.css +0 -1
- package/assets/board/_nuxt/error-404.BFmXOnCT.css +0 -1
- package/assets/board/_nuxt/error-500.BZ-DdjQ6.css +0 -1
- package/assets/board/_nuxt/gantt.Dmp00GUo.css +0 -1
- package/assets/board/_nuxt/last-change.1Su4GrCN.css +0 -1
- package/assets/board/_nuxt/milestones.U0xKCsEo.css +0 -1
- package/assets/board/_nuxt/pages.Dbj2IVk8.css +0 -1
- package/assets/board/_nuxt/rlePnzpc.js +0 -1
- package/assets/board/_nuxt/tests.dXlUX16A.css +0 -1
- package/assets/board/_nuxt/uKzCKCTq.js +0 -1
- package/assets/board/_nuxt/vwxaNGfc.js +0 -1
- package/assets/board/_nuxt/yh6sf_D5.js +0 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Gantt Chart
|
|
2
|
+
|
|
3
|
+
**Best for:** project plans and roadmaps — tasks with explicit start and end dates, grouped into phases. Use when the reader needs to see temporal overlap, parallel tracks, and milestone sequencing at a glance.
|
|
4
|
+
|
|
5
|
+
## Layout conventions
|
|
6
|
+
|
|
7
|
+
- **Left label column:** x=20–200 (180px). Task names in the `node-name` role at 11px 600. Phase labels as `eyebrow` 7px above each group.
|
|
8
|
+
- **Timeline area:** x=200–960 (760px). Time axis runs left→right.
|
|
9
|
+
- **Row height:** 40px per task. Each bar occupies h=24px centered in the row (8px top padding).
|
|
10
|
+
- **Time axis:** `arrow-label` role 8px week/month labels at x=200+i×pitch, y=56 (just above first task row). A hairline separator at y=64.
|
|
11
|
+
- **Phase grouping:** a subtle zone rect (same pattern as architecture zone) behind each phase's rows, with an eyebrow label in the top-left margin. Use `ink @ 0.02` fill, `ink @ 0.10` stroke.
|
|
12
|
+
- **Focal task bar:** 1 bar in accent fill/stroke (the key deliverable or critical path task). All others: muted fill @ 0.15, muted stroke.
|
|
13
|
+
- **Today / milestone marker:** optional vertical dashed line in `muted` at the current week x-position.
|
|
14
|
+
|
|
15
|
+
### Task bar pattern
|
|
16
|
+
|
|
17
|
+
```svg
|
|
18
|
+
<!-- Non-focal task -->
|
|
19
|
+
<rect x="X_start" y="ROW_Y+8" width="DURATION_PX" height="24" rx="4"
|
|
20
|
+
fill="{muted @ 0.15}" stroke="{muted}" stroke-width="1"/>
|
|
21
|
+
<text x="X_start+8" y="ROW_Y+25" fill="{ink}" font-size="10" font-weight="600"
|
|
22
|
+
font-family="{node-name}">Task name</text>
|
|
23
|
+
|
|
24
|
+
<!-- Focal task -->
|
|
25
|
+
<rect x="X_start" y="ROW_Y+8" width="DURATION_PX" height="24" rx="4"
|
|
26
|
+
fill="{accent @ 0.12}" stroke="{accent}" stroke-width="1"/>
|
|
27
|
+
<text x="X_start+8" y="ROW_Y+25" fill="{accent}" font-size="10" font-weight="600"
|
|
28
|
+
font-family="{node-name}">Key task</text>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Duration in pixels: `(end_week - start_week) × pitch`. Pitch = timeline_width / total_weeks.
|
|
32
|
+
|
|
33
|
+
## Anti-patterns
|
|
34
|
+
|
|
35
|
+
- More than 12 tasks (splits into sub-plans or collapses into phase-level view).
|
|
36
|
+
- More than 5 parallel tracks per phase (illegible overlap).
|
|
37
|
+
- Dependency arrows between tasks in v1 (add only when essential; use the annotation primitive for labels).
|
|
38
|
+
- Start/end dates in the bar label (put them in the x-axis or tooltip comment instead).
|
|
39
|
+
- Equal visual weight for all bars (the focal task must stand out).
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
- `assets/example-gantt.html` — minimal light
|
|
44
|
+
- `assets/example-gantt-dark.html` — minimal dark
|
|
45
|
+
- `assets/example-gantt-full.html` — full editorial
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Heatmap
|
|
2
|
+
|
|
3
|
+
**Best for:** cross-tabulated data where *which row × column combination stands out* is the story. Use when the reader needs to scan a full matrix at once — not compare individual bars or trace a trend line — and one cell (or a cluster of cells) is editorially distinct from the field. Common uses: CI failure rate by service and sprint, support ticket volume by team and week, confusion matrix for a classifier, correlation coefficients across many variables.
|
|
4
|
+
|
|
5
|
+
The CSS geometry guard ignores comments; active transform declarations still fail.
|
|
6
|
+
|
|
7
|
+
## Layout conventions
|
|
8
|
+
|
|
9
|
+
- **Plot area:** left 160px (row labels), top 64px (column labels), right 40px, bottom 120px (legend area); inside `0 0 1000 500` viewBox.
|
|
10
|
+
- **Cell size:** 116px wide × 56px tall, gap 4px. Maximum grid: 6 columns × 5 rows within the viewBox; smaller grids scale the cells up to fill the space.
|
|
11
|
+
- **Row count:** 3–7. Fewer → a table says it with less ink; more → the cells shrink below readability at the minimum viewBox width.
|
|
12
|
+
- **Column count:** 3–8. Same constraint: 8 × 116 = 928px exceeds the available 800px at this viewBox, so either reduce columns or reduce cell width proportionally (minimum cell width 80px).
|
|
13
|
+
- **Axes:** row labels right-aligned in the left gutter (`sublabel` role 9px, `text-anchor="end"`, x=148); column labels centered above each column (`sublabel` role 9px, `text-anchor="middle"`); axis titles in the `eyebrow` role 7px small-caps rotated/positioned in the margins.
|
|
14
|
+
- **Value text (optional):** `arrow-label` role 8px centered inside each cell. Flip text color to paper when fill opacity ≥ 0.40 (the ink ramp becomes dark enough to carry white); keep ink text below that threshold.
|
|
15
|
+
|
|
16
|
+
### Cell pattern
|
|
17
|
+
|
|
18
|
+
Every cell is two overlapping `<rect>` elements: a paper-fill underlay (no data attributes, paints the background), then the data rect with all three data bindings.
|
|
19
|
+
|
|
20
|
+
```svg
|
|
21
|
+
<!-- Paper underlay — no data attributes, scenery only -->
|
|
22
|
+
<rect x="160" y="64" width="116" height="56" fill="{paper}"/>
|
|
23
|
+
|
|
24
|
+
<!-- Data cell — all three bindings required -->
|
|
25
|
+
<rect data-row="auth" data-col="S1" data-value="4"
|
|
26
|
+
x="160" y="64" width="116" height="56"
|
|
27
|
+
fill="{ink @ 0.29}"/>
|
|
28
|
+
|
|
29
|
+
<!-- Focal cell — data-focal="true" required, uses accent fill -->
|
|
30
|
+
<rect x="520" y="124" width="116" height="56" fill="{paper}"/>
|
|
31
|
+
<rect data-row="payments" data-col="S4" data-value="47" data-focal="true"
|
|
32
|
+
x="520" y="124" width="116" height="56"
|
|
33
|
+
fill="{accent @ 0.85}" stroke="{accent}" stroke-width="1.2"/>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## The fill ramp
|
|
37
|
+
|
|
38
|
+
**One ink ramp, one accent.** Non-focal cells use a single tonal ramp: `rgba(INK, opacity)` where opacity is a non-decreasing function of the data value. The shipped example uses `opacity = max(0.07, value / max_non_focal × 0.65)`. Any monotone formula (linear, sqrt, log) passes the verifier as long as opacity never decreases with value.
|
|
39
|
+
|
|
40
|
+
**One focal cell only.** The accent marks the editorially focal cell — the one whose combination of row and column is the figure's argument. It is not the automatically highest value; choose the cell whose story the title is about. `data-focal="true"` is required; `scripts/verify-heatmap.py` counts all accent-fill and `data-focal` cells and fails if more than one is found.
|
|
41
|
+
|
|
42
|
+
**Ramp bounds:** the lowest-value non-focal cell should land at ≥ 0.05 opacity (the cell must be visually distinct from the paper background) and the highest-value non-focal cell at ≤ 0.70 (the ramp must not bleed into the focal accent's territory).
|
|
43
|
+
|
|
44
|
+
## Anti-patterns
|
|
45
|
+
|
|
46
|
+
- A hue per row or per column — hue is not a continuous variable; it maps "which series" (slopegraph contract), not "how much". The ramp carries quantity; the label carries category identity.
|
|
47
|
+
- A multi-hue diverging ramp (e.g. blue–white–red) — these read as two variables (negative and positive deviation from center) and are only honest when the data is signed and the center is meaningful. For unsigned rates or counts, the single ink ramp is the honest encoding.
|
|
48
|
+
- Focal accent on more than one cell — if two cells are both focal the figure needs a different title; hue-coding two things is a palette decision masquerading as an editorial one.
|
|
49
|
+
- A value axis (color bar with a continuous legend) instead of a discrete ramp strip — the ink ramp is not a gradient legend; it encodes comparative reading ("S4 is much darker than S3"), not precise magnitude retrieval. If readers need the exact value, the number printed inside the cell carries it.
|
|
50
|
+
- Rows or columns dropped because they made the pattern less clean — omitted rows and columns are invisible to the reader and look like "the services that didn't have this problem". Name everything included and say in the footnote if anything is excluded.
|
|
51
|
+
- A transform on a cell, its underlay, or an ancestor `<g>`. The verifier reads raw `x`/`y`/`width`/`height` attributes; a transform silently moves the rendered mark off the verified position.
|
|
52
|
+
|
|
53
|
+
## Honest-data rule
|
|
54
|
+
|
|
55
|
+
**Row × column labels are complete and stated.** A heatmap that quietly drops a service with a high rate is a filtered view the reader cannot see. State every included row and column; note any exclusions in the footnote or source line.
|
|
56
|
+
|
|
57
|
+
**The ramp scale is declared.** The legend strip shows the range the ramp covers for non-focal cells, stated as "LOW" to "HIGH" rather than a continuous scale — because the ramp's job is comparative, not absolute. If the footnote states bounds, those bounds must match the actual minimum and maximum non-focal values in the figure.
|
|
58
|
+
|
|
59
|
+
**The focal cell is excluded from the ramp's scale.** Its value (often an outlier) would collapse every other cell into near-identical opacity if included. The footnote must state the focal cell's value explicitly. `scripts/verify-heatmap.py` checks that the focal cell carries `data-focal="true"` and that no non-focal cell uses accent fill.
|
|
60
|
+
|
|
61
|
+
## Declaring the values
|
|
62
|
+
|
|
63
|
+
The verifier accepts either matching quote delimiter for SVG attributes.
|
|
64
|
+
|
|
65
|
+
**Every drawn cell is bound to its row, column, and value.** Declared data values are finite and nonnegative; unsigned counts may exceed one billion. NaN, infinity, and negative values are rejected rather than weakening grid completeness. The paper underlay carries nothing. The data rect carries all three.
|
|
66
|
+
|
|
67
|
+
| Binding | Without it |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `data-row` on the data rect | A row cannot be identified during verification; a swapped row passes silently. |
|
|
70
|
+
| `data-col` on the data rect | A column cannot be identified; a shuffled column is invisible to the verifier. |
|
|
71
|
+
| `data-value` on the data rect | The fill cannot be verified as monotone; any opacity passes. |
|
|
72
|
+
| `data-focal="true"` on the focal rect | The focal cell is counted as a non-focal cell with an unexplained accent fill. |
|
|
73
|
+
|
|
74
|
+
`scripts/verify-heatmap.py` enforces the complete `rows × cols` grid, the monotone fill ramp on non-focal cells, and at most one focal cell. It does **not** verify cell geometry (position, width, height) because both axes are categorical — position encodes "which row/column", and that is carried by the label, not by a scale the checker can measure against.
|
|
75
|
+
|
|
76
|
+
Focal-text contrast measurement accepts finite unitless and explicit `px` coordinates. Unsupported relative units or malformed lengths produce a named measurement finding, never a traceback; this does not add a quantitative cell-geometry check.
|
|
77
|
+
|
|
78
|
+
Focal-text contrast composites translucent foreground text against the resolved focal-cell fill before measuring WCAG AA. The 4.5:1 minimum applies to that foreground/background pair in both themes.
|
|
79
|
+
|
|
80
|
+
**No `transform` on any verified element.** Bake any coordinate offsets directly into `x`/`y` attributes.
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# High-Level
|
|
2
|
+
|
|
3
|
+
**Best for:** end-to-end data stack overviews — ingestion → storage → query → analytics → visualization — deployed on a container orchestrator (Kubernetes, ECS, Nomad). Combines a phase chevron banner, deployment boundary, orchestration bar, identity footer, and (optionally) a right-side vertical chevron strip for cross-cutting concerns (Orchestration, Security, Observability).
|
|
4
|
+
|
|
5
|
+
This type is **parametric**. The diagram is fully determined by a small list of inputs (chevrons, sources, components, connections). The formulas below tell you exactly where every shape lands given those inputs — two generations from the same inputs must produce visually identical SVG.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Inputs — the parameter contract
|
|
10
|
+
|
|
11
|
+
Before drawing, collect these from the user (or accept them as a YAML/JSON block). Everything in this reference is derived from these inputs. Don't invent geometry on the fly.
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
chevrons: # ordered left → right; reserved names auto-promote to vertical
|
|
15
|
+
- { name: "Data sources", columns: 1 }
|
|
16
|
+
- { name: "Ingestion", columns: 1 }
|
|
17
|
+
- { name: "Storage", columns: 1 }
|
|
18
|
+
- { name: "Transformation", columns: 1 }
|
|
19
|
+
- { name: "Visualization", columns: 1 }
|
|
20
|
+
- { name: "Orchestration", vertical: true } # reserved → pairs with the bar
|
|
21
|
+
- { name: "Security", vertical: true, color: "#b85450" } # tinted to match the Identity bar below
|
|
22
|
+
- { name: "Observability", vertical: true } # reserved → pairs with crosscut #2
|
|
23
|
+
|
|
24
|
+
sources: # external; rendered in the dashed zone on the left
|
|
25
|
+
- { name: "PostgreSQL", type: "db", connects_to: ["NiFi"] }
|
|
26
|
+
- { name: "SFTP drop", type: "ftp", connects_to: ["NiFi"] }
|
|
27
|
+
- { name: "Web forms", type: "web", connects_to: ["NiFi"] }
|
|
28
|
+
- { name: "Legacy", type: "legacy", connects_to: ["NiFi"] }
|
|
29
|
+
|
|
30
|
+
components: # inside the cluster, plus bars and cross-cutting rows
|
|
31
|
+
- { name: "NiFi", chevron: "Ingestion", kind: node, icon: nifi, role: "COLL" }
|
|
32
|
+
- { name: "MinIO", chevron: "Storage", kind: node, icon: minio, role: "STORE", focal: true }
|
|
33
|
+
- { name: "Trino", chevron: "Storage", kind: node, icon: trino, role: "VIRT" }
|
|
34
|
+
- { name: "Notebooks", chevron: "Transformation", kind: node, icon: jupyter, role: "ANLZ" }
|
|
35
|
+
- { name: "Superset", chevron: "Visualization", kind: node, icon: superset, role: "DASH" }
|
|
36
|
+
- { name: "Airflow", chevron: "Orchestration", kind: bar, icon: airflow, subtitle: "Apache Airflow" }
|
|
37
|
+
- { name: "Identity", chevron: "Security", kind: cross-cutting, icon: keycloak, subtitle: "Keycloak · LDAP · OIDC", color: "#b85450" }
|
|
38
|
+
- { name: "Monitoring", chevron: "Observability", kind: cross-cutting, icon: prometheus, subtitle: "Prometheus · Grafana · Loki" }
|
|
39
|
+
|
|
40
|
+
connections: # explicit edges; focal-touching ones become accent automatically
|
|
41
|
+
- { from: "NiFi", to: "MinIO", style: "primary" }
|
|
42
|
+
- { from: "NiFi", to: "Trino", style: "secondary" }
|
|
43
|
+
- { from: "MinIO", to: "Notebooks", style: "primary" }
|
|
44
|
+
- { from: "Trino", to: "MinIO", style: "query" } # read-back (dashed)
|
|
45
|
+
- { from: "Notebooks", to: "Superset", style: "secondary" }
|
|
46
|
+
- { from: "Airflow", to: ["NiFi", "Trino", "Notebooks"], style: "trigger" }
|
|
47
|
+
|
|
48
|
+
focal: "MinIO" # exactly one; defaults to first kind=node under "Storage"
|
|
49
|
+
dark: false
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Reserved chevron names** (always vertical, even if `vertical: true` is omitted): `Orchestration`, `Security`, `Observability`, `Governance`, `Backup`.
|
|
53
|
+
|
|
54
|
+
**Reserved `kind` values:**
|
|
55
|
+
- `node` — a standard box inside the cluster (default).
|
|
56
|
+
- `bar` — a horizontal strip spanning the cluster top. Typically one (Orchestration); see §5 for the pairing rule.
|
|
57
|
+
- `cross-cutting` — a horizontal strip spanning the body width (stops at the strip margin), stacked below the cluster. **Zero or more allowed**; each stacks 44 px below the previous (§2.5) and pairs 1:1 with a vertical chevron (§5).
|
|
58
|
+
|
|
59
|
+
**Optional `color`** (per component, hex string): tints the component's container and content while leaving connectors untouched. See §3.4. Use sparingly — a custom color is a semantic flag (e.g., red = security concern), not decoration.
|
|
60
|
+
|
|
61
|
+
**Source `type` values** → icon mapping (use `references/primitive-icons.md`):
|
|
62
|
+
- `db` → `database`
|
|
63
|
+
- `ftp` → `bucket` or upload arrow
|
|
64
|
+
- `web` → `internet`
|
|
65
|
+
- `legacy` → `server`
|
|
66
|
+
- `api` → `api`
|
|
67
|
+
- Any explicit icon name in `primitive-icons.md` is also accepted.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2. Layout formulas — deterministic geometry
|
|
72
|
+
|
|
73
|
+
Every coordinate below is derived from the inputs. **No hardcoded numbers in examples that aren't justified here.**
|
|
74
|
+
|
|
75
|
+
### 2.1 Canvas
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
has_vertical = any(c.vertical or c.name in reserved_names for c in chevrons)
|
|
79
|
+
right_strip_w = 28 if has_vertical else 0
|
|
80
|
+
strip_margin = 8 if has_vertical else 0 # gap between body and right strip
|
|
81
|
+
effective_w = 1000 - right_strip_w - strip_margin # 1000 or 964
|
|
82
|
+
|
|
83
|
+
n_cross = count of components with kind == "cross-cutting"
|
|
84
|
+
strip_y_bot = max(428, 388 + n_cross * 44 - 4) # extends to last crosscut row
|
|
85
|
+
viewBox_h = max(540, strip_y_bot + 112) # 112 reserved for legend
|
|
86
|
+
viewBox = f"0 0 1000 {viewBox_h}"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Every horizontal element (chevron banner, cluster, orchestration bar, identity / cross-cutting bars) ends at `effective_w`. The right strip sits at `x = 1000 - right_strip_w` (= 972). The 8-px band between them is visual breathing room — never put content there.
|
|
90
|
+
|
|
91
|
+
`viewBox_h` grows when more than one cross-cutting bar is declared: 1 crosscut → 540, 2 → 600 (or 584 if you want it tight; the rule rounds to the next multiple of 20 for clean grids).
|
|
92
|
+
|
|
93
|
+
### 2.2 Horizontal chevron banner
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
y_banner = 4
|
|
97
|
+
h_banner = 28
|
|
98
|
+
horizontals = [c for c in chevrons if not c.vertical and c.name not in reserved_names]
|
|
99
|
+
sum_columns = sum(c.columns for c in horizontals)
|
|
100
|
+
base_unit = floor_to_4(effective_w / sum_columns) # multiple of 4
|
|
101
|
+
widths = [max(120, base_unit * c.columns) for c in horizontals]
|
|
102
|
+
widths[-1] += effective_w - sum(widths) # trailing absorbs remainder
|
|
103
|
+
x_boundaries = cumulative_sum([0] + widths) # length sum_columns+1
|
|
104
|
+
chevron_cx(C) = (x_boundaries[index(C)] + x_boundaries[index(C)+1]) / 2
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Polygon shapes:**
|
|
108
|
+
- First (leftmost): `(x0,4) (x1-12,4) (x1,18) (x1-12,32) (x0,32)`
|
|
109
|
+
- Middle: `(x0,4) (x1-12,4) (x1,18) (x1-12,32) (x0,32) (x0+12,18)`
|
|
110
|
+
- Last (rightmost): `(x0,4) (effective_w,4) (effective_w,32) (x0,32) (x0+12,18)`
|
|
111
|
+
|
|
112
|
+
Fills alternate between two steps of the **phase-band palette** (§6.1): `band-1` / `band-2` in light mode, `band-2` / `band-3` in dark. Labels: `band-label` fill, `eyebrow` role (mono), `font-size=7`, `letter-spacing=0.14em`, `text-anchor=middle`, centered at `chevron_cx, 21`.
|
|
113
|
+
|
|
114
|
+
**Color override** (per chevron, both horizontal and vertical): a chevron may declare an optional `color: "#hex"` that replaces the alternation fill for that one chevron. Use it to flag a phase that pairs with a custom-colored component (e.g., `Security` chevron in red when the Identity bar uses `color: "#b85450"`). Rules:
|
|
115
|
+
|
|
116
|
+
- Override applies to the polygon fill only. The label stays `band-label`; it never takes the active skin's `paper`.
|
|
117
|
+
- The alternation index doesn't shift; neighboring chevrons keep their natural fill, even if it produces two adjacent same-fill chevrons. Don't try to "fix" this — overrides should be rare (≤ 2 per diagram).
|
|
118
|
+
- In dark mode, use the same hex unless contrast against `band-label` falls below 4.5:1; if it does, pick a darker shade for dark mode and document it as a `color_dark` field on that chevron.
|
|
119
|
+
- A chevron color override is independent of any paired component's color, but pairing them (same hex on chevron + bar) is the conventional way to make the column "read" as one concern.
|
|
120
|
+
|
|
121
|
+
### 2.3 Source zone (dashed, external)
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
sources_x = 4
|
|
125
|
+
sources_y = 40
|
|
126
|
+
sources_w = x_boundaries[1] - 8 # width of the first chevron, minus 4px gutter each side
|
|
127
|
+
sources_h = 336
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Stroke: `ink @ 0.20`, `stroke-width=0.8`, `stroke-dasharray=6,3`, `rx=6`. Zone fill: `ink @ 0.02`.
|
|
131
|
+
|
|
132
|
+
### 2.4 Cluster boundary (solid)
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
cluster_x = x_boundaries[1] + 4 # starts at end of source zone + 4px gutter
|
|
136
|
+
cluster_y = 40
|
|
137
|
+
cluster_w = effective_w - cluster_x # extends to right strip / canvas edge
|
|
138
|
+
cluster_h = 336
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Stroke: `ink @ 0.18`, `stroke-width=1.2`, `rx=8`. Fill: `ink @ 0.02`. K8s icon + label at `(cluster_x + 16, 352)` (icon) and `(cluster_x + 40, 362)` (text).
|
|
142
|
+
|
|
143
|
+
### 2.5 Cross-cutting bars (identity, observability, …)
|
|
144
|
+
|
|
145
|
+
Zero or more `kind: cross-cutting` components stack below the cluster. Each gets its own 40-px row with a 4-px gap.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
crosscuts = [c for c in components if c.kind == "cross-cutting"] # ordered as declared
|
|
149
|
+
cross_x = 4
|
|
150
|
+
cross_y(k) = 388 + k * 44 # 388, 432, 476, …
|
|
151
|
+
cross_w = effective_w - 4 # spans body width, stops at the strip margin
|
|
152
|
+
cross_h = 40
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Stroke: `ink @ 0.20`, `stroke-width=0.8`, `rx=6`. Fill: `ink @ 0.05`. Icon at `(16, cross_y(k) + 10)`, name centered at `(effective_w / 2, cross_y(k) + 22)`, subtitle at `(effective_w / 2, cross_y(k) + 34)`.
|
|
156
|
+
|
|
157
|
+
Reserved cross-cutting *concerns* (informational; user can name the actual bar whatever they want):
|
|
158
|
+
- **Identity / Security** — Keycloak, LDAP/AD, Okta, Auth0, OIDC providers
|
|
159
|
+
- **Observability** — Prometheus + Grafana, Datadog, OpenTelemetry, Loki
|
|
160
|
+
- **Backup / DR** — Velero, Restic, snapshot orchestrators
|
|
161
|
+
- **Governance / Lineage** — OpenMetadata, DataHub, Apache Atlas
|
|
162
|
+
- **Secrets / config** — Vault, Sealed Secrets, External Secrets
|
|
163
|
+
|
|
164
|
+
Each cross-cutting bar pairs 1:1 with a vertical chevron in the right strip (§5).
|
|
165
|
+
|
|
166
|
+
### 2.6 Orchestration bar component (inside cluster)
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
bar_x = cluster_x + 12
|
|
170
|
+
bar_y = 52
|
|
171
|
+
bar_w = cluster_w - 24
|
|
172
|
+
bar_h = 44
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Stroke: `ink @ 0.18`, `stroke-width=0.8`, `rx=4`. Fill: `ink @ 0.05`. Tool icon at the far right (`bar_x + bar_w - 50, 58`); name centered at `(bar_x + bar_w/2, 71)`; subtitle at `(bar_x + bar_w/2, 84)`.
|
|
176
|
+
|
|
177
|
+
### 2.7 Component nodes (inside cluster)
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
node_w = 152
|
|
181
|
+
node_h = 80 # focal same height, accent border
|
|
182
|
+
node_cx(N) = chevron_cx(N.chevron) # ← non-negotiable
|
|
183
|
+
node_x(N) = node_cx(N) - node_w/2
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
If a chevron has K nodes assigned, stack them vertically:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
first_top_y = 120 if any bar in this column else 64
|
|
190
|
+
gap = 16
|
|
191
|
+
row_top(k) = first_top_y + k * (node_h + gap) # k = 0..K-1
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Focal node:** `fill="{accent @ 0.08}"`, `stroke="{accent}"`, `stroke-width=1.2`. Title text in `accent`. All other nodes: white fill, `stroke={ink @ 0.25}`, `stroke-width=1`.
|
|
195
|
+
|
|
196
|
+
Role badge top-left at `(node_x+8, node_y+6)`, size 12 high. Icon top-right at `(node_x+node_w-32, node_y+6)`, 24×24, monochrome via `currentColor`. Name centered at `(node_cx, node_y+44)` size 11 sans semibold. Subtitle at `(node_cx, node_y+56)` size 8 mono muted.
|
|
197
|
+
|
|
198
|
+
### 2.8 Source nodes (inside dashed zone)
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
src_node_w = sources_w - 8
|
|
202
|
+
src_node_h = 64 # uniform; chosen to fit ≤ 4 sources
|
|
203
|
+
src_node_x = sources_x + 4
|
|
204
|
+
src_first_top_y = 60
|
|
205
|
+
src_gap = 16
|
|
206
|
+
src_row_top(k) = src_first_top_y + k * (src_node_h + src_gap)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Same role-badge / icon / name / subtitle pattern as cluster nodes (icon at `src_node_x+54, row_top(k)+6`; name centered at `src_node_x+src_node_w/2, row_top(k)+42`; subtitle one line below). Role badge text: `EXT`. Caps at 4 sources; for more, split into a separate diagram.
|
|
210
|
+
|
|
211
|
+
### 2.9 Right strip — vertical chevrons
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
strip_x = 1000 - right_strip_w # 972 when present
|
|
215
|
+
strip_w = 28
|
|
216
|
+
verticals = [c for c in chevrons if c.vertical or c.name in reserved_names]
|
|
217
|
+
strip_y_top = 40
|
|
218
|
+
strip_y_bot = max(428, 388 + n_cross * 44 - 4) # extends to last crosscut row (see §2.1)
|
|
219
|
+
strip_h_total = strip_y_bot - strip_y_top
|
|
220
|
+
heights = [floor_to_4(strip_h_total / len(verticals))] * len(verticals)
|
|
221
|
+
heights[-1] += strip_h_total - sum(heights) # last absorbs remainder
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Examples:
|
|
225
|
+
- 2 verticals (Orchestration + Security), 1 crosscut → `heights = [192, 196]`, layout `[40..232, 232..428]`.
|
|
226
|
+
- 3 verticals (Orchestration + Security + Observability), 2 crosscuts → `strip_y_bot = 472`, `strip_h_total = 432`, `heights = [144, 144, 144]`, layout `[40..184, 184..328, 328..472]`.
|
|
227
|
+
|
|
228
|
+
Adjacent edges share the same y (no gap), like horizontal chevrons share x at their boundary.
|
|
229
|
+
|
|
230
|
+
**Polygon shapes** (top-to-bottom flow, mirrors horizontal §2.2):
|
|
231
|
+
- First (topmost): flat top, point at bottom — `(strip_x, y0) (strip_x+strip_w, y0) (strip_x+strip_w, y1-12) (strip_x+strip_w/2, y1) (strip_x, y1-12)`
|
|
232
|
+
- Middle: notch on top, point on bottom — `(strip_x, y0) (strip_x+strip_w/2, y0+12) (strip_x+strip_w, y0) (strip_x+strip_w, y1-12) (strip_x+strip_w/2, y1) (strip_x, y1-12)`
|
|
233
|
+
- Last (bottommost): notch on top, flat bottom — `(strip_x, y0) (strip_x+strip_w/2, y0+12) (strip_x+strip_w, y0) (strip_x+strip_w, y1) (strip_x, y1)`
|
|
234
|
+
|
|
235
|
+
Fills alternate `band-1` / `band-2` (same phase-band palette as the horizontals, §6.1). Labels: `band-label` fill, `eyebrow` role (mono), `font-size=7`, `letter-spacing=0.14em`, **rotated −90°**, anchored at `(strip_x + strip_w/2, (y0+y1)/2)`.
|
|
236
|
+
|
|
237
|
+
Vertical chevrons honor the per-chevron `color` override documented in §2.2 — apply the hex to the polygon fill, leave the rotated label `band-label`. Pair the override with the same hex on the chevron's paired bar/crosscut to bind them visually as one concern.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 3. Connector rules (mandatory)
|
|
242
|
+
|
|
243
|
+
These are non-negotiable. Pick the style **automatically** from the topology — do not let the user override style on focal-touching or bar-originating edges.
|
|
244
|
+
|
|
245
|
+
| `style` | Stroke | Width | Dash | Marker | When required |
|
|
246
|
+
|---|---|---|---|---|---|
|
|
247
|
+
| `primary` | `accent` | 1.2 | — | `arrow-accent` | Every edge whose endpoint is the `focal` node. |
|
|
248
|
+
| `secondary` | `muted` | 1.0 | — | `arrow` | Default for source→component and component→component when neither endpoint is focal. |
|
|
249
|
+
| `trigger` | `muted` | 1.0 | `4,3` | `arrow-sm` | Every edge originating from a `kind: bar` component. |
|
|
250
|
+
| `query` | `ink @ 0.30` | 1.0 | `4,3` | `arrow` | Read-back edges (e.g., focal ↔ Trino). |
|
|
251
|
+
|
|
252
|
+
**Defs block** (required, exactly these four markers):
|
|
253
|
+
|
|
254
|
+
```svg
|
|
255
|
+
<defs>
|
|
256
|
+
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="{muted}"/></marker>
|
|
257
|
+
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="{accent}"/></marker>
|
|
258
|
+
<marker id="arrow-sm" markerWidth="6" markerHeight="5" refX="5" refY="2.5" orient="auto"><polygon points="0 0, 6 2.5, 0 5" fill="{muted}"/></marker>
|
|
259
|
+
<marker id="arrow-dim" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="{ink @ 0.45}"/></marker>
|
|
260
|
+
</defs>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 3.1 Exit / entry sides (non-negotiable)
|
|
264
|
+
|
|
265
|
+
| Edge kind | Exit side of source | Entry side of target |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| Source → cluster node | **right** of source node | **left** of target |
|
|
268
|
+
| Component → component (within cluster) | **right** | **left** |
|
|
269
|
+
| Bar component → node | **bottom** of bar | **top** of node |
|
|
270
|
+
| Cross-cutting bar | — (emits no edges) | — |
|
|
271
|
+
| Vertical chevron | — (labels only; emits no edges) | — |
|
|
272
|
+
|
|
273
|
+
### 3.2 Routing
|
|
274
|
+
|
|
275
|
+
- Orthogonal elbows, **at most two bends** per path.
|
|
276
|
+
- Use a Q-bezier 8-px corner radius at every bend.
|
|
277
|
+
- Z-order: draw **all connectors before any node rectangle** (so node fills mask the line ends).
|
|
278
|
+
- Exactly one `marker-end` per `<path>` / `<line>`. Never both `marker-start` and `marker-end`.
|
|
279
|
+
- Labels: every `primary` and `secondary` connector gets a label (small mono, opaque paper-filled rect mask behind). `trigger` and `query` connectors are unlabelled.
|
|
280
|
+
|
|
281
|
+
### 3.3 Crossings
|
|
282
|
+
|
|
283
|
+
- Avoid. Re-route via the chevron divider trunk (§4) before accepting a crossing.
|
|
284
|
+
- If unavoidable, the path drawn second carries a 6-px arc hop over the first.
|
|
285
|
+
|
|
286
|
+
### 3.4 Component color override
|
|
287
|
+
|
|
288
|
+
A component may declare an optional `color: "#hex"` (CSS color string). The override **only** retints the component's container and content — connectors are never recolored. Edges keep their topology-driven style from §3.
|
|
289
|
+
|
|
290
|
+
**Where the color is applied** (given `C = color`):
|
|
291
|
+
|
|
292
|
+
| Element | Light mode | Dark mode |
|
|
293
|
+
|---|---|---|
|
|
294
|
+
| Container fill (`rect` body) | `rgba(C, 0.06)` | `rgba(C, 0.10)` |
|
|
295
|
+
| Container stroke | `rgba(C, 0.35)` (`stroke-width=1` for nodes, `0.8` for bars) | `rgba(C, 0.45)` |
|
|
296
|
+
| Role badge stroke (nodes) | `rgba(C, 0.40)` | `rgba(C, 0.55)` |
|
|
297
|
+
| Role badge text (nodes) | `rgba(C, 0.85)` | `rgba(C, 1.0)` |
|
|
298
|
+
| Icon fill / stroke | `C` | lighten `C` by ~15% (or use `C` if already light) |
|
|
299
|
+
| Name text | `C` | lighten `C` |
|
|
300
|
+
| Subtitle text | **unchanged** (`muted`) | **unchanged** (`muted`) |
|
|
301
|
+
| Connectors touching this component | **unchanged** (still topology-driven) | **unchanged** |
|
|
302
|
+
|
|
303
|
+
The subtitle stays muted because it's parenthetical metadata — only the primary identity (name + icon + border) carries the color signal.
|
|
304
|
+
|
|
305
|
+
**Rules**:
|
|
306
|
+
|
|
307
|
+
- **Never on the focal node.** The focal node is already colored with the accent (§2.7). A `color` on the focal node is ignored — accent wins.
|
|
308
|
+
- **Never on source nodes.** Sources live outside the cluster and stay neutral.
|
|
309
|
+
- **Cap at 2 custom-colored components** per diagram (in addition to the focal). Three or more colored things erases the signal — the same reason §1 limits accent to 1–2 elements.
|
|
310
|
+
- **No color on connectors.** If you find yourself wanting a colored edge, the right move is to pick a different `style` from §3, not to override.
|
|
311
|
+
|
|
312
|
+
**Semantic uses** (recommended):
|
|
313
|
+
- `#b85450` (rust-red) — Security / Identity (Keycloak, Vault)
|
|
314
|
+
- `#5a7d9a` (slate-blue) — Observability (Prometheus, Datadog)
|
|
315
|
+
- `#7a8c47` (olive-green) — Governance / Lineage (OpenMetadata)
|
|
316
|
+
- `#8c6d3f` (warm-brown) — Backup / DR
|
|
317
|
+
|
|
318
|
+
Stick to these unless the user's brand demands otherwise. Random hex per component is exactly the failure mode this skill avoids.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 4. Block branching rules (fan-out)
|
|
323
|
+
|
|
324
|
+
The single biggest reproducibility hazard. Fix these rules and the diagram becomes predictable.
|
|
325
|
+
|
|
326
|
+
### 4.1 Source fan-out (one source → N components)
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
exit_x = source.right
|
|
330
|
+
trunk_x = cluster_x - 8 # 4-px gutter before cluster border
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Path per target: `M exit_x,source_cy → H trunk_x → V target_cy → H target.left`. Use Q-bezier corners.
|
|
334
|
+
|
|
335
|
+
### 4.2 Component fan-out (one component → N components)
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
exit_x = node.right
|
|
339
|
+
trunk_x = x_boundaries[index(source.chevron) + 1] + 4 # 4 px past the chevron divider
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Path per target: `M exit_x,source_cy → H trunk_x → V target_cy → H target.left`.
|
|
343
|
+
|
|
344
|
+
### 4.3 Fan-out cap
|
|
345
|
+
|
|
346
|
+
**Max 3 outgoing edges per node.** Above 3, introduce a hub (usually the `focal` node). The chevron banner is the legend; if a node is fanning out to four downstream targets, it's secretly the hub — make it explicit.
|
|
347
|
+
|
|
348
|
+
### 4.4 Bar drops (Airflow → N nodes)
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
drop_x(target) = target.cx
|
|
352
|
+
drop_y_start = bar.bottom
|
|
353
|
+
drop_y_end = target.top
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Straight vertical line, `style: trigger`. One per target. No bends — bar drops never elbow.
|
|
357
|
+
|
|
358
|
+
### 4.5 Source vertical staggering
|
|
359
|
+
|
|
360
|
+
When multiple sources connect to the same single target (e.g. four sources → NiFi), stagger their entry y on the target:
|
|
361
|
+
|
|
362
|
+
```
|
|
363
|
+
entry_y(k) = target.top + 8 + k * (target_h - 16) / (N - 1) # k = 0..N-1, evenly spaced
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
This avoids overlapping arrowheads at the target's left edge.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 5. Vertical chevrons — semantics
|
|
371
|
+
|
|
372
|
+
Reserved names `Orchestration`, `Security`, `Observability`, `Governance`, `Backup` always render in the right strip (§2.9). Any chevron with `vertical: true` is treated as a reserved-style vertical regardless of name. The rules:
|
|
373
|
+
|
|
374
|
+
- **Pairing rule (mandatory, 1:1):** every vertical chevron pairs with exactly one cross-spanning component, and every cross-spanning component pairs with exactly one vertical chevron. The two component kinds that pair:
|
|
375
|
+
- `kind: bar` — lives inside the cluster (top row). Conventionally paired with `Orchestration`.
|
|
376
|
+
- `kind: cross-cutting` — lives below the cluster, one row per component. Paired with `Security`, `Observability`, `Governance`, etc.
|
|
377
|
+
|
|
378
|
+
If the inputs declare a vertical chevron without a paired component (or vice versa), halt and ask the user — the diagram is incomplete.
|
|
379
|
+
|
|
380
|
+
- **Count constraint:** `len(verticals) == len(bars) + len(crosscuts)`. The right strip is split evenly among all verticals (§2.9), so visual alignment between a chevron and its bar/row is approximate — the *label* is what matters, not the y-pixel match.
|
|
381
|
+
|
|
382
|
+
- **Ordering convention:** declare verticals top-down in the order: bar-paired first (Orchestration), then crosscut-paired in the same order the crosscuts appear below the cluster. This keeps the visual reading order consistent.
|
|
383
|
+
|
|
384
|
+
- **No edges:** vertical chevrons emit no connectors themselves. They are *labels for a column of cross-cutting concern*.
|
|
385
|
+
|
|
386
|
+
- **No node placement:** no `kind: node` may be assigned to a vertical chevron. Nodes always belong to a horizontal phase.
|
|
387
|
+
|
|
388
|
+
- **Right strip presence:** if any vertical chevron exists, the right strip is reserved (`effective_w = 964`) and **all** horizontal chevron widths and cluster geometry shrink accordingly. Do not draw a vertical chevron on top of the cluster.
|
|
389
|
+
|
|
390
|
+
The visual contract: the vertical chevron's column visually "owns" the bar/cross-cutting row at its approximate y-band. Orchestration (top of strip) ↔ Airflow bar (top of cluster). Security ↔ Identity bar. Observability ↔ monitoring bar (below identity). And so on.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## 6. Dark mode
|
|
395
|
+
|
|
396
|
+
`paper`, `ink`, `muted`, and `accent` invert with the skin: take their values from the dark column in [`style-guide.md`](style-guide.md). Every derived value in this reference is a **role at an opacity**, so `ink @ 0.18` resolves to dark ink on light paper and light ink on dark paper with no extra handling.
|
|
397
|
+
|
|
398
|
+
Only these differ between modes:
|
|
399
|
+
|
|
400
|
+
| Element | Light | Dark | Why it differs |
|
|
401
|
+
|---|---|---|---|
|
|
402
|
+
| Muted text | `muted` | `ink @ 0.65` | Dark mode softens secondary text by opacity rather than by hue |
|
|
403
|
+
| Dashed border | `ink @ 0.20` | `ink @ 0.22` | A hairline needs marginally more presence on dark paper |
|
|
404
|
+
| Node fill | `#ffffff` (white) | `ink @ 0.06` | White is opaque; on dark paper the node lifts off the ground instead |
|
|
405
|
+
| Node stroke | `ink @ 0.25` | `ink @ 0.20` | Light ink on dark paper reads stronger at equal opacity |
|
|
406
|
+
| Focal fill | `accent @ 0.08` | `accent @ 0.12` | ditto |
|
|
407
|
+
| Phase bands | `band-1` / `band-2` | `band-2` / `band-3` | The alternation shifts one step lighter (§6.1) |
|
|
408
|
+
|
|
409
|
+
Unchanged across modes: cluster border `ink @ 0.18`, dot pattern `ink @ 0.10`, focal stroke `accent`, accent connector `accent`, and the chevron label, which is always `band-label`.
|
|
410
|
+
|
|
411
|
+
### 6.1 Phase-band palette
|
|
412
|
+
|
|
413
|
+
The chevron banner needs a **dark band with a light label in both modes**. `ink` and `paper` swap places between modes, so the banner can't be built from them. It uses four fixed tokens that ignore the light/dark flip:
|
|
414
|
+
|
|
415
|
+
| Token | Value | Use |
|
|
416
|
+
|---|---|---|
|
|
417
|
+
| `band-1` | `#2d3142` | Darkest step: odd chevrons, light mode |
|
|
418
|
+
| `band-2` | `#3d4460` | Middle step: even chevrons light, odd chevrons dark |
|
|
419
|
+
| `band-3` | `#4a5270` | Lightest step: even chevrons, dark mode |
|
|
420
|
+
| `band-label` | `#f5f5f5` | Fixed label color: 11.82:1, 8.78:1, and 7.05:1 against the three bands |
|
|
421
|
+
|
|
422
|
+
**These are type-scoped tokens, not skin roles, and they do not invert.** They are the one deliberate exception to the rule that hex values live only in [`style-guide.md`](style-guide.md). `scripts/lint-skin.py` rejects `band-2` and `band-3` as off-palette, which is why the shipped high-level examples are listed in `scripts/lint-skin-baseline.txt`. Phase labels always use `band-label`, and `band-label` has to hold at least 4.5:1 against every band, because these are 7px labels in either mode. When you re-skin, derive three analogous steps from the new brand's darkest neutral and pick a fixed label color that holds 4.5:1 against all three.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 7. Reproducibility checklist (the taste gate)
|
|
427
|
+
|
|
428
|
+
Before emitting SVG, verify **every** item. If any fails, fix it — don't ship.
|
|
429
|
+
|
|
430
|
+
1. Every cluster `node.cx` equals its chevron's `cx` (§2.2 + §2.7). This is what makes the chevron banner a real legend.
|
|
431
|
+
2. Every chevron `width` is a multiple of 4 and ≥ 120.
|
|
432
|
+
3. The reserved right strip (28 px) exists **iff** any vertical chevron is declared. If yes, `effective_w = 964`; if no, `effective_w = 1000`.
|
|
433
|
+
4. Exactly **one** `focal` node. If `focal` is unset in inputs, default to the first `kind: node` under chevron "Storage".
|
|
434
|
+
5. Every edge whose endpoint is the focal node uses `style: primary` (accent stroke + `arrow-accent` marker).
|
|
435
|
+
6. Every edge originating from a `kind: bar` component uses `style: trigger` (dashed + `arrow-sm`).
|
|
436
|
+
7. The cross-cutting bar (if any) emits **no** edges.
|
|
437
|
+
8. No node has > 3 outgoing edges, or if it does, it is the declared `focal` / hub.
|
|
438
|
+
9. All `<path>` and `<line>` connectors are emitted **before** any node `<rect>` (z-order).
|
|
439
|
+
10. Each vertical chevron pairs **1:1** with exactly one `bar` or `cross-cutting` component (§5 pairing rule). `len(verticals) == len(bars) + len(crosscuts)`.
|
|
440
|
+
11. `viewBox_h = max(540, strip_y_bot + 112)` — grow the canvas when multiple crosscuts are declared so the legend still fits.
|
|
441
|
+
12. Custom component colors (§3.4) apply only to container + icon + name; connectors stay topology-driven. Cap at 2 custom-colored components in addition to the focal.
|
|
442
|
+
13. The diagram passes SKILL.md §9 (4-px grid; ≤ 2 accent elements; mono only for technical content; hairlines; no shadows; no `rounded-2xl`).
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## 8. Anti-patterns
|
|
447
|
+
|
|
448
|
+
- Chevron banner omitted — it's the key that maps visual columns to functional phases.
|
|
449
|
+
- Node x-center off-chevron (§7 #1) — breaks the "banner-as-legend" contract.
|
|
450
|
+
- Vertical chevron drawn on the cluster (overlay) instead of in a reserved right strip.
|
|
451
|
+
- More than one focal node — MinIO/S3 (or whichever storage hub) is *the* focal point.
|
|
452
|
+
- External zone with solid border — dashed border is the signal that these components are outside the cluster.
|
|
453
|
+
- Identity bar inside the cluster boundary — it applies to all components and must span the full canvas width.
|
|
454
|
+
- Vertical chevron without a paired bar/cross-cutting component — see §5 pairing rule.
|
|
455
|
+
- Bar-component edges drawn solid — orchestration triggers must be dashed.
|
|
456
|
+
- Source fanning out to >3 components without a hub.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 9. Examples
|
|
461
|
+
|
|
462
|
+
- `assets/example-high-level.html` — horizontal-only, 5 phases, light skin.
|
|
463
|
+
- `assets/example-high-level-dark.html` — same, dark skin.
|
|
464
|
+
- `assets/example-high-level-full.html` — same, editorial-card frame.
|
|
465
|
+
- `assets/example-high-level-vertical.html` — adds vertical Orchestration + Security chevrons, Airflow bar, Keycloak cross-cutting. **Reference render of the full parametric pattern.**
|
|
466
|
+
- `assets/example-high-level-vertical-dark.html` — vertical pattern, dark skin.
|
|
467
|
+
- `assets/example-high-level-vertical-full.html` — vertical pattern, editorial-card frame.
|
|
468
|
+
- `assets/example-datalake.html` — unclustered five-phase data stack (Sources → Ingest → Data Lake → Query → Consume), zone-based flow without a container-orchestrator boundary. The MinIO lake is the focal node; vertical concerns are flattened into the horizontal chevron banner. Light skin.
|
|
469
|
+
- `assets/example-datalake-dark.html` — same, dark skin.
|
|
470
|
+
- `assets/example-datalake-full.html` — same, editorial-card frame.
|