schematex 0.6.10 → 0.8.0
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/dist/ai/ai-sdk.cjs +19 -19
- package/dist/ai/ai-sdk.d.cts +4 -4
- package/dist/ai/ai-sdk.d.ts +4 -4
- package/dist/ai/ai-sdk.js +14 -14
- package/dist/ai/index.cjs +25 -25
- package/dist/ai/index.d.cts +3 -3
- package/dist/ai/index.d.ts +3 -3
- package/dist/ai/index.js +14 -14
- package/dist/{api-JaBtsUT8.d.cts → api-BnJAPCwC.d.cts} +1 -1
- package/dist/{api-DIJM_mqp.d.ts → api-DAZJGq9r.d.ts} +1 -1
- package/dist/browser.cjs +20 -20
- package/dist/browser.d.cts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +14 -14
- package/dist/{chunk-34O3C6OC.cjs → chunk-2YBBDPOW.cjs} +4 -4
- package/dist/chunk-2YBBDPOW.cjs.map +1 -0
- package/dist/{chunk-3YRYBTLG.cjs → chunk-3CSST5GZ.cjs} +9082 -591
- package/dist/chunk-3CSST5GZ.cjs.map +1 -0
- package/dist/{chunk-JTGTWBAD.js → chunk-6DVK5M2J.js} +3 -3
- package/dist/chunk-6DVK5M2J.js.map +1 -0
- package/dist/{chunk-SHMG7BVF.cjs → chunk-6L46VIXI.cjs} +4 -4
- package/dist/{chunk-SHMG7BVF.cjs.map → chunk-6L46VIXI.cjs.map} +1 -1
- package/dist/{chunk-OFKRELZK.js → chunk-ABCMTAOZ.js} +3 -3
- package/dist/{chunk-OFKRELZK.js.map → chunk-ABCMTAOZ.js.map} +1 -1
- package/dist/{chunk-5FYPSIGD.cjs → chunk-B5AQ3CG3.cjs} +4 -4
- package/dist/{chunk-5FYPSIGD.cjs.map → chunk-B5AQ3CG3.cjs.map} +1 -1
- package/dist/{chunk-3GAPHXCE.js → chunk-CDK7KDIW.js} +3 -3
- package/dist/{chunk-3GAPHXCE.js.map → chunk-CDK7KDIW.js.map} +1 -1
- package/dist/{chunk-Z3A2UNK2.cjs → chunk-D34VGLSE.cjs} +4 -4
- package/dist/{chunk-Z3A2UNK2.cjs.map → chunk-D34VGLSE.cjs.map} +1 -1
- package/dist/{chunk-BL57NQKN.cjs → chunk-DHI7YAQJ.cjs} +326 -29
- package/dist/chunk-DHI7YAQJ.cjs.map +1 -0
- package/dist/{chunk-C7V57V6O.js → chunk-DX44TBFZ.js} +3 -3
- package/dist/{chunk-C7V57V6O.js.map → chunk-DX44TBFZ.js.map} +1 -1
- package/dist/{chunk-MPCSWRZC.js → chunk-E3CAJGJM.js} +3 -3
- package/dist/{chunk-MPCSWRZC.js.map → chunk-E3CAJGJM.js.map} +1 -1
- package/dist/{chunk-HL5PS6MG.js → chunk-E7LXMEKX.js} +325 -28
- package/dist/chunk-E7LXMEKX.js.map +1 -0
- package/dist/{chunk-P26FCZP3.js → chunk-IXRPRMHI.js} +3 -3
- package/dist/{chunk-P26FCZP3.js.map → chunk-IXRPRMHI.js.map} +1 -1
- package/dist/{chunk-WU2N6ZVM.js → chunk-JGCKW5RS.js} +3 -3
- package/dist/{chunk-WU2N6ZVM.js.map → chunk-JGCKW5RS.js.map} +1 -1
- package/dist/{chunk-J3EPFZPX.cjs → chunk-JIJWGHRN.cjs} +5 -5
- package/dist/{chunk-J3EPFZPX.cjs.map → chunk-JIJWGHRN.cjs.map} +1 -1
- package/dist/{chunk-TACTEF2N.cjs → chunk-JIUC4DRS.cjs} +4 -4
- package/dist/{chunk-TACTEF2N.cjs.map → chunk-JIUC4DRS.cjs.map} +1 -1
- package/dist/{chunk-77GPD4YQ.cjs → chunk-KUITLG4N.cjs} +4 -4
- package/dist/{chunk-77GPD4YQ.cjs.map → chunk-KUITLG4N.cjs.map} +1 -1
- package/dist/{chunk-2F45Y2ON.cjs → chunk-NXU4XKLY.cjs} +4 -4
- package/dist/{chunk-2F45Y2ON.cjs.map → chunk-NXU4XKLY.cjs.map} +1 -1
- package/dist/{chunk-UHPGWO77.cjs → chunk-Q2YRJHFB.cjs} +4 -4
- package/dist/{chunk-UHPGWO77.cjs.map → chunk-Q2YRJHFB.cjs.map} +1 -1
- package/dist/{chunk-DZGA25O5.cjs → chunk-RKN6QJ7K.cjs} +733 -10
- package/dist/chunk-RKN6QJ7K.cjs.map +1 -0
- package/dist/{chunk-2TUZ3QJA.js → chunk-T3GV7OVF.js} +3 -3
- package/dist/{chunk-2TUZ3QJA.js.map → chunk-T3GV7OVF.js.map} +1 -1
- package/dist/{chunk-5IKOLUWK.js → chunk-TO6PNBT3.js} +3 -3
- package/dist/chunk-TO6PNBT3.js.map +1 -0
- package/dist/{chunk-X4P4HKHP.js → chunk-TXMT4XLE.js} +731 -8
- package/dist/chunk-TXMT4XLE.js.map +1 -0
- package/dist/{chunk-T3FV73LM.js → chunk-UOM3EDE6.js} +3 -3
- package/dist/{chunk-T3FV73LM.js.map → chunk-UOM3EDE6.js.map} +1 -1
- package/dist/{chunk-NAGUZFXX.cjs → chunk-VHDSPI6A.cjs} +3 -2
- package/dist/chunk-VHDSPI6A.cjs.map +1 -0
- package/dist/{chunk-YMZTXOUG.js → chunk-WNGOG4CI.js} +3 -3
- package/dist/{chunk-YMZTXOUG.js.map → chunk-WNGOG4CI.js.map} +1 -1
- package/dist/{chunk-6AWASOFO.js → chunk-XI5QP7LM.js} +9054 -571
- package/dist/chunk-XI5QP7LM.js.map +1 -0
- package/dist/{chunk-LPAWZYDU.cjs → chunk-YMFYPB5Y.cjs} +14 -14
- package/dist/{chunk-LPAWZYDU.cjs.map → chunk-YMFYPB5Y.cjs.map} +1 -1
- package/dist/{diagnostics-BKRow1ur.d.cts → diagnostics-B-jOt6Ua.d.cts} +1 -1
- package/dist/{diagnostics-BKRow1ur.d.ts → diagnostics-B-jOt6Ua.d.ts} +1 -1
- package/dist/diagrams/blockdiagram/index.cjs +6 -6
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/blockdiagram/index.js +2 -2
- package/dist/diagrams/circuit/index.cjs +9 -9
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.js +2 -2
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/entity/index.cjs +6 -6
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/entity/index.js +2 -2
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.cjs +6 -6
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.js +2 -2
- package/dist/diagrams/logic/index.cjs +8 -8
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/logic/index.js +2 -2
- package/dist/diagrams/orgchart/index.cjs +8 -8
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.js +2 -2
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.cjs +7 -7
- package/dist/diagrams/phylo/index.d.cts +22 -1
- package/dist/diagrams/phylo/index.d.ts +22 -1
- package/dist/diagrams/phylo/index.js +2 -2
- package/dist/diagrams/sld/index.cjs +8 -8
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sld/index.js +2 -2
- package/dist/diagrams/sociogram/index.cjs +6 -6
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/sociogram/index.js +2 -2
- package/dist/diagrams/timing/index.cjs +5 -5
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/timing/index.js +2 -2
- package/dist/diagrams/venn/index.cjs +9 -9
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/diagrams/venn/index.js +2 -2
- package/dist/{index-Dq3Mfxay.d.ts → index-8MaUFTMN.d.ts} +1 -1
- package/dist/{index-DU2h1Y-a.d.cts → index-D-MAB6CH.d.cts} +1 -1
- package/dist/index.cjs +83 -51
- package/dist/index.d.cts +33 -5
- package/dist/index.d.ts +33 -5
- package/dist/index.js +17 -17
- package/dist/react.cjs +14 -14
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +13 -13
- package/dist/{tools-OzOQnlnV.d.cts → tools-CV1JZ75-.d.cts} +2 -2
- package/dist/{tools-A0HRZ8jj.d.ts → tools-CcPysgAD.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-34O3C6OC.cjs.map +0 -1
- package/dist/chunk-3YRYBTLG.cjs.map +0 -1
- package/dist/chunk-5IKOLUWK.js.map +0 -1
- package/dist/chunk-6AWASOFO.js.map +0 -1
- package/dist/chunk-BL57NQKN.cjs.map +0 -1
- package/dist/chunk-DZGA25O5.cjs.map +0 -1
- package/dist/chunk-HL5PS6MG.js.map +0 -1
- package/dist/chunk-JTGTWBAD.js.map +0 -1
- package/dist/chunk-NAGUZFXX.cjs.map +0 -1
- package/dist/chunk-X4P4HKHP.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai/registry.ts","../src/ai/_generated.ts","../src/ai/examples.ts","../src/ai/profiles.ts","../src/ai/syntax.ts","../src/ai/tools.ts"],"names":["parseResult","renderResult"],"mappings":"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","file":"chunk-RKN6QJ7K.cjs","sourcesContent":["/**\n * Diagram registry — metadata for every diagram type Schematex supports.\n *\n * This is the index an LLM sees when calling `listDiagrams()`. Descriptions\n * are tuned to help the model pick the right type for a user request.\n */\n\nimport type { DiagramType } from \"../core/types\";\n\nexport type DiagramCluster =\n | \"relationships\"\n | \"electrical-industrial\"\n | \"corporate-legal\"\n | \"causality-analysis\"\n | \"generic\"\n | \"strategy\"\n | \"knowledge\"\n | \"behavior-modeling\"\n | \"concurrency\"\n | \"research\"\n | \"project-management\"\n | \"network-infrastructure\"\n | \"software-uml\"\n | \"risk-reliability\";\n\nexport interface DiagramMeta {\n /** Canonical type id — matches `DiagramType` and plugin keys. */\n type: DiagramType;\n /** Human-readable name. */\n name: string;\n /** One-sentence tagline. */\n tagline: string;\n /** When should an LLM pick this diagram? Written in \"use X when …\" form. */\n useWhen: string;\n /** Domain cluster for grouping. */\n cluster: DiagramCluster;\n /** Published standard the parser and layout follow. */\n standard: string;\n /** Path to the syntax doc key in the generated content bundle. */\n syntaxKey: string;\n}\n\nexport const DIAGRAM_REGISTRY: readonly DiagramMeta[] = [\n // ── Relationships ────────────────────────────────────────────\n {\n type: \"genogram\",\n name: \"Genogram\",\n tagline: \"Family diagram with emotional, medical, and generational notation.\",\n useWhen:\n \"Use for family therapy, social-work case notes, or medical family history. Handles 3+ generations with deaths, cutoffs, hostility, closeness, and the proband marker.\",\n cluster: \"relationships\",\n standard: \"McGoldrick, Gerson & Petry (2020) + GenoPro emotional taxonomy\",\n syntaxKey: \"genogram\",\n },\n {\n type: \"ecomap\",\n name: \"Ecomap\",\n tagline: \"Radial diagram of a client's connections to external systems.\",\n useWhen:\n \"Use for social work intake to visualise a client's support network — school, work, healthcare, faith, extended family — with strong/weak/stressful tie variants.\",\n cluster: \"relationships\",\n standard: \"Hartman (1978) + NSGC\",\n syntaxKey: \"ecomap\",\n },\n {\n type: \"pedigree\",\n name: \"Pedigree chart\",\n tagline: \"Clinical genetic-counselling pedigree with affected/carrier states.\",\n useWhen:\n \"Use for genetic counselling or medical genetics education — mendelian inheritance, carrier status, consanguinity, deceased generations. Follows NSGC conventions.\",\n cluster: \"relationships\",\n standard: \"NSGC Pedigree Standardization (Bennett 2008)\",\n syntaxKey: \"pedigree\",\n },\n {\n type: \"phylo\",\n name: \"Phylogenetic tree\",\n tagline: \"Rectangular cladogram from a Newick/NHX tree string.\",\n useWhen:\n \"Use for evolutionary biology, taxonomy, or species relationships. Accepts standard Newick input with optional branch lengths and clade highlighting.\",\n cluster: \"relationships\",\n standard: \"Newick + NHX extensions\",\n syntaxKey: \"phylo\",\n },\n {\n type: \"sociogram\",\n name: \"Sociogram\",\n tagline: \"Force-directed social network graph with edge types and weights.\",\n useWhen:\n \"Use for classroom sociometry, team influence mapping, or organisational network analysis. Edges can be directed, weighted, positive, negative, or reciprocal.\",\n cluster: \"relationships\",\n standard: \"Moreno (1934) sociometry\",\n syntaxKey: \"sociogram\",\n },\n // ── Electrical & Industrial ──────────────────────────────────\n {\n type: \"timing\",\n name: \"Timing / waveform diagram\",\n tagline: \"Digital signal timing diagram with clocks, buses, and annotations.\",\n useWhen:\n \"Use for digital-logic or bus-protocol documentation (SPI/I²C/AXI). Supports clock, data, bus, and gap signals with transition annotations.\",\n cluster: \"electrical-industrial\",\n standard: \"WaveDrom-compatible signal description\",\n syntaxKey: \"timing\",\n },\n {\n type: \"logic\",\n name: \"Logic gate netlist\",\n tagline: \"IEEE 91 logic-gate diagram from a gate-list DSL.\",\n useWhen:\n \"Use for combinational / sequential logic design — AND/OR/XOR/NAND/NOR/NOT/MUX/latches. Auto-routes via DAG topological sort.\",\n cluster: \"electrical-industrial\",\n standard: \"IEEE Std 91/91a-1991\",\n syntaxKey: \"logic\",\n },\n {\n type: \"circuit\",\n name: \"Circuit schematic\",\n tagline: \"Positional circuit schematic with resistors, sources, transistors.\",\n useWhen:\n \"Use for analogue/mixed-signal schematics — voltage/current sources, passives, diodes, BJT/MOSFET, op-amps. Uses an explicit positional DSL, not auto-layout.\",\n cluster: \"electrical-industrial\",\n standard: \"IEEE Std 315 / ANSI Y32.2\",\n syntaxKey: \"circuit\",\n },\n {\n type: \"blockdiagram\",\n name: \"Control-systems block diagram\",\n tagline: \"Transfer-function block diagram with summing junctions and feedback.\",\n useWhen:\n \"Use for classical control theory — plants, controllers, sensors, summing junctions, feedback loops. Nested feedback supported.\",\n cluster: \"electrical-industrial\",\n standard: \"Ogata / standard controls textbook convention\",\n syntaxKey: \"block\",\n },\n {\n type: \"ladder\",\n name: \"Ladder logic\",\n tagline: \"IEC 61131-3 ladder-logic program with rungs, contacts, coils.\",\n useWhen:\n \"Use for PLC / industrial-automation programs — normally-open/closed contacts, output coils, timers, counters. Renders with fixed power-rail layout.\",\n cluster: \"electrical-industrial\",\n standard: \"IEC 61131-3 Ladder Diagram\",\n syntaxKey: \"ladder\",\n },\n {\n type: \"fbd\",\n name: \"Function Block Diagram (FBD)\",\n tagline: \"IEC 61131-3 §6.4 function blocks wired through named ports.\",\n useWhen:\n \"Use for PLC programs that are easier to read as data-flow than as ladder rungs — boolean logic (AND/OR/NOT/NAND/NOR/XOR), timers (TON/TOF/TP), counters (CTU/CTD), edge detectors (R_TRIG/F_TRIG), comparison (EQ/NE/GT/GE/LT/LE), math (ADD/SUB/MUL/DIV/MOVE), selection (SEL/MUX/MAX/MIN/LIMIT). Inline expression notation `Out = OR(A, AND(B, C))`. Sister language to `ladder` (§10) and `sfc` (§24); together they form the visual half of IEC 61131-3.\",\n cluster: \"electrical-industrial\",\n standard: \"IEC 61131-3:2013 §6.4 + §2.5 standard FB library; see 23-FBD-STANDARD.md\",\n syntaxKey: \"fbd\",\n },\n {\n type: \"sfc\",\n name: \"Sequential Function Chart (SFC)\",\n tagline: \"IEC 61131-3 §6.5 step + transition state machine for cyclic PLC sequences.\",\n useWhen:\n \"Use for PLC sequential control — batch reactors, robotic cells, packaging lines, assembly stations — where the program has explicit phases that hand off to each other on boolean conditions. Steps with action qualifiers (N/S/R/L/D/P), transitions with conditions, alternative branches (single bar, OR semantics) and simultaneous branches (double bar, AND semantics), jumps for loops. Distinct from `state` (UML — Schematex `state` covers reactive UI/lifecycle FSMs, not cyclic PLC scans) and from `flowchart` (no bars, no qualifiers).\",\n cluster: \"electrical-industrial\",\n standard: \"IEC 61131-3:2013 §6.5 + IEC 60848 GRAFCET visual subset; see 24-SFC-STANDARD.md\",\n syntaxKey: \"sfc\",\n },\n {\n type: \"sld\",\n name: \"Single-line diagram\",\n tagline: \"Electrical power distribution single-line (one-line) diagram.\",\n useWhen:\n \"Use for facility / industrial / utility power systems — utility, generator, transformer, ATS, bus, breaker, load. Top-to-bottom power flow.\",\n cluster: \"electrical-industrial\",\n standard: \"IEEE Std 315 + ANSI device numbering\",\n syntaxKey: \"sld\",\n },\n {\n type: \"pid\",\n name: \"P&ID (Piping & Instrumentation)\",\n tagline: \"ISA-5.1 process equipment, valves, and instrument bubbles.\",\n useWhen:\n \"Use for chemical / petrochemical / pharmaceutical / water-treatment process diagrams — vessels, columns, heat exchangers, pumps, valves, and instrument loops with ISA tag codes (FT/FIC/PT/etc.). Equipment + piping + instrumentation in one diagram.\",\n cluster: \"electrical-industrial\",\n standard: \"ANSI/ISA-5.1-2009 + ISO 10628-1:2014\",\n syntaxKey: \"pid\",\n },\n {\n type: \"breadboard\",\n name: \"Breadboard / Physical wiring\",\n tagline: \"Fritzing-style breadboard view — physical wiring of Arduino / ESP32 / Pi prototypes.\",\n useWhen:\n \"Use for maker / Arduino / ESP32 / Raspberry Pi tutorials and lab handouts where the user wants to see *how to physically wire components on a breadboard* — not the abstract circuit schematic. Address tie-points by `@col-row` (e.g. `@5e`, `@+t8`). Smooth Bézier jumper-wires with conventional colors. Distinct from `circuit` (IEEE 315 schematic — same prototype, different view).\",\n cluster: \"electrical-industrial\",\n standard: \"Fritzing visual conventions + Wokwi DSL precedent (no ISO standard exists for this view; see 26-BREADBOARD-STANDARD.md)\",\n syntaxKey: \"breadboard\",\n },\n // ── Corporate / Legal ────────────────────────────────────────\n {\n type: \"entity\",\n name: \"Entity structure\",\n tagline: \"Corporate ownership hierarchy with percentage rollup.\",\n useWhen:\n \"Use for legal entity structures, holdco/opco charts, international tax charts, Series-A cap-table snapshots. Tiered layout with ownership percentages. NOT for database schema diagrams — use `erd` for those.\",\n cluster: \"corporate-legal\",\n standard: \"Tier-based ownership hierarchy\",\n syntaxKey: \"entity\",\n },\n // ── Data modeling ────────────────────────────────────────────\n {\n type: \"erd\",\n name: \"Entity-Relationship Diagram (ERD)\",\n tagline: \"Database schema diagram (crow's-foot tabular entities + cardinality glyphs).\",\n useWhen:\n \"Use for relational database schema diagrams — tables, columns, primary/foreign keys, and cardinality (1..1 / 0..N / 1..N) between tables. DBML-like text DSL plus Mermaid `}o--||` glyph aliases. Distinct from `entity` (which is for corporate/legal ownership). v0.1 supports crow's-foot only; Chen and Barker notations are deferred.\",\n cluster: \"corporate-legal\",\n standard: \"Chen 1976 / Everest 1976 (crow's foot) — implements the crow's-foot subset; see 27-ERD-STANDARD.md\",\n syntaxKey: \"erd\",\n },\n // ── Causality / Analysis ─────────────────────────────────────\n {\n type: \"fishbone\",\n name: \"Fishbone (Ishikawa)\",\n tagline: \"Ishikawa cause-and-effect diagram with categorised root causes.\",\n useWhen:\n \"Use for root-cause analysis, post-mortems, quality investigations. Categories branch off the spine; each cause is a bone.\",\n cluster: \"causality-analysis\",\n standard: \"Ishikawa (1968) cause-and-effect\",\n syntaxKey: \"fishbone\",\n },\n {\n type: \"venn\",\n name: \"Venn / Euler\",\n tagline: \"Set-theoretic Venn / Euler diagram with 2, 3, or 4 sets.\",\n useWhen:\n \"Use to visualise set overlaps, commonalities, or category intersections. Supports 2/3-set Venn and Euler (non-overlapping) arrangements.\",\n cluster: \"causality-analysis\",\n standard: \"Venn (1880) / Euler diagrams\",\n syntaxKey: \"venn\",\n },\n {\n type: \"decisiontree\",\n name: \"Decision tree\",\n tagline: \"Decision/classification tree with splits, probabilities, leaves.\",\n useWhen:\n \"Use for decision analysis (Howard-Raiffa EV rollback), ML decision trees, or taxonomy classification. Binary or multi-way splits.\",\n cluster: \"causality-analysis\",\n standard: \"Howard-Raiffa / CART-sklearn / taxonomy\",\n syntaxKey: \"decisiontree\",\n },\n // ── Behavior modeling ────────────────────────────────────────\n {\n type: \"state\",\n name: \"State diagram\",\n tagline: \"UML 2.5 / Harel statechart with composite states and pseudo-states.\",\n useWhen:\n \"Use for modeling reactive system behavior — finite state machines, lifecycle states, controller modes, UI workflows. Supports simple states, composite (nested) states, fork/join, choice, history, and full Mermaid `stateDiagram-v2` syntax.\",\n cluster: \"behavior-modeling\",\n standard: \"OMG UML 2.5.1 §14 + Harel (1987) statechart\",\n syntaxKey: \"state\",\n },\n {\n type: \"bpmn\",\n name: \"BPMN business process\",\n tagline: \"OMG BPMN 2.0 — pools and lanes, events, gateways, tasks for organizational processes.\",\n useWhen:\n \"Use for business processes that span multiple roles, departments, or systems — claims handling, hiring, order-to-cash, incident response, ISO-9001 / SOX audits. Pools = participants, lanes = roles, events = start/intermediate/end, gateways = XOR/AND/OR/event-based branches, message flows cross pool boundaries (`~~>`). Distinct from `flowchart` (no pools/lanes/event taxonomy), `state` (mode-centric, not activity-centric), and `pid` (physical equipment, not organisational work).\",\n cluster: \"behavior-modeling\",\n standard: \"OMG BPMN 2.0.2 / ISO/IEC 19510:2013 visual subset; see 25-BPMN-STANDARD.md\",\n syntaxKey: \"bpmn\",\n },\n {\n type: \"usecase\",\n name: \"UML use case diagram\",\n tagline: \"UML 2.5.1 use case diagram — captures what a system does and for whom: actors, use cases, a subject boundary, and include/extend/generalization.\",\n useWhen:\n \"Use for software-engineering requirements and scope diagrams — 'what does this system do, and for whom'. Actors (stick figures, or `(external)` rectangles for other systems) sit outside a subject boundary; use cases are ellipses inside it. `--` association, `..>` «include» (source includes target), `<..` «extend» (left extends right, with optional `[condition]` and extension points), `--|>` generalization (hollow triangle to parent, between actors or between use cases). Accepts a PlantUML-style inline form (`:Actor:`, `(Use case)`, `as ID`). Distinct from `state` (intra-object behavior, not system scope), `flowchart` (no actor/subject/include-extend semantics), and `bpmn` (how a process executes, not what a system offers).\",\n cluster: \"behavior-modeling\",\n standard: \"OMG UML 2.5.1 §18 visual subset; see 29-USECASE-STANDARD.md\",\n syntaxKey: \"usecase\",\n },\n {\n type: \"sequence\",\n name: \"UML sequence diagram\",\n tagline: \"UML 2.5.1 §17 interaction diagram — shows how participants exchange messages over time (who calls whom, in what order): lifelines, activations, and all twelve combined fragments.\",\n useWhen:\n \"Use for time-ordered interactions between participants — API call flows, auth handshakes, distributed protocols, object collaborations, 'who calls whom in what order'. Lifelines run top→bottom; messages run left→right: `->` synchronous (filled head), `->>` asynchronous (open head), `-->` reply (dashed), `-x` lost, `o->` found. `+`/`-` suffixes open/close activation bars; `*Target` creates a participant and `destroy` ends one. All twelve UML combined fragments — `alt`/`opt`/`loop`/`par`/`break`/`critical`/`seq`/`strict`/`neg`/`ignore`/`consider`/`assert` — plus `ref` interaction-use frames. Participant kinds `actor`/`boundary`/`control`/`entity`/`database` render their UML/Jacobson symbols; `«stereotype»` overrides the label. Distinct from `usecase` (system scope, not message order), `state` (one object's modes, not inter-object messages), `bpmn` (organisational process), and `flowchart` (no lifelines/time axis).\",\n cluster: \"behavior-modeling\",\n standard: \"OMG UML 2.5.1 §17 (Interactions); see 33-SEQUENCE-STANDARD.md\",\n syntaxKey: \"sequence\",\n },\n {\n type: \"petri\",\n name: \"Petri net\",\n tagline:\n \"Place/transition net that computes the dynamics — enabled transitions and token firing, not just shapes.\",\n useWhen:\n \"Use whenever the user mentions 'Petri net', 'place/transition net', 'token', 'marking', 'concurrency model', 'mutual exclusion', 'producer/consumer', or wants to model concurrent resource flow / synchronisation. Declare `place <id> *<tokens>` (circles holding tokens), `transition <id>` (bars — add `timed rate: <λ>` for a GSPN timed transition), and bipartite arcs: `->` standard, `-o` inhibitor (enabled only while the place is empty), `--` read/test, `=>` reset. Arc weight via `weight: n` or `*n`; place limit via `capacity: n`. The engine validates the bipartite structure, applies a `fire: T1, T2` sequence to the initial marking, and highlights which transitions are *enabled* in the result. `layout: lr|tb`. Distinct from `state` (one active state, not a token distribution), `sfc` (a restricted PLC Petri net), `bpmn` (organisational process), and `flowchart` (single thread, no concurrency or marking).\",\n cluster: \"concurrency\",\n standard: \"Murata 1989 + ISO/IEC 15909-1 (place/transition net); see 34-PETRINET-STANDARD.md\",\n syntaxKey: \"petri\",\n },\n // ── Network / infrastructure ─────────────────────────────────\n {\n type: \"network\",\n name: \"Network topology\",\n tagline:\n \"IT / CCTV network topology with Cisco-convention device icons, typed links, subnets/VLANs, and topology-correct layout.\",\n useWhen:\n \"Use whenever the user mentions 'network diagram', 'network topology', 'infrastructure diagram', a 'cámaras / CCTV / camera network', a LAN/WAN/data-center diagram, or wants to lay out routers, switches, firewalls, access points, servers, IP cameras, NVRs, etc. Declare typed devices `<kind> <id> \\\"label\\\"` (router, switch, l3switch, firewall, loadbalancer, ap, wlc, gateway, modem, ids, proxy, vpngw, server, serverfarm, pc, laptop, mobile, ipphone, printer, storage, camera (with `type: fixed|bullet|dome|ptz|turret`), nvr, dvr, poeswitch, encoder, monitor, internet, wan, pstn, cloud, lan) and connect with `a -- b` (undirected), `a -> b` (directed), or `a == b` (LAG). After `:` add a link spec: a link type (fiber/wireless/serial/poe/vpn/lag), `trunk`/`access` mode, `vlan: 10,20`, a speed like `1G`/`10G`, and `port: Gi0/1>eth0`. Group devices in nested boundaries: `site`/`rack` (physical) and `subnet`/`vlan`/`zone`/`dmz` (logical) blocks `{ … }`. Choose `layout: tiered` (default; band by `tier: edge|core|distribution|access`), `tree`, `star`, `ring`, `bus`, `mesh`, `spine-leaf` (declare `spines:`/`leaves:` and the mesh is auto-generated), or `manual`. The engine never drops a device/port/link, and validates VLAN range 1–4094 plus device IP-in-subnet-CIDR. Distinct from `flowchart` (no device icons/topology), `c4` (software containers, not physical devices), and `sld` (electrical single-line, not data network).\",\n cluster: \"network-infrastructure\",\n standard: \"Cisco-convention topology icons + hierarchical/spine-leaf models + ANSI/TIA-606 + ONVIF; see 35-NETWORK-STANDARD.md\",\n syntaxKey: \"network\",\n },\n // ── Research / evidence synthesis ────────────────────────────\n {\n type: \"prisma\",\n name: \"PRISMA 2020 flow diagram\",\n tagline: \"PRISMA 2020 — the mandatory four-row flow diagram for systematic reviews and meta-analyses.\",\n useWhen:\n \"Use whenever the user mentions 'PRISMA', 'systematic review', 'meta-analysis flow', 'scoping review', 'evidence screening', or 'Cochrane review' — this is the dedicated, standards-correct engine (prefer it over a generic flowchart). The author writes record counts and exclusion reasons; the rigid four-row layout (Identification → Screening → Eligibility → Included) is correct by construction, with mandatory `n = …` counts, parallel exclusion side-boxes, and an optional second 'other methods' column (`mode: 2020-dual`). Vocabulary swaps for scoping reviews (`kind: scoping-review`) and IPD (`kind: ipd`). Count arithmetic is validated (`validate-counts: warn|strict|off`). Distinct from `flowchart` (no mandatory stages/counts/exclusion-box convention).\",\n cluster: \"research\",\n standard: \"PRISMA 2020 (Page MJ et al., BMJ 2021;372:n71); see 28-PRISMA-STANDARD.md\",\n syntaxKey: \"prisma\",\n },\n // ── Project management / scheduling ──────────────────────────\n {\n type: \"pert\",\n name: \"PERT / CPM network\",\n tagline:\n \"Activity-on-node project schedule that computes ES/EF/LS/LF, slack, and the critical path.\",\n useWhen:\n \"Use whenever the user mentions 'PERT', 'CPM', 'critical path', 'project network', 'precedence diagram', or wants a project schedule from tasks + durations + dependencies. Unlike a flowchart, this engine *computes* the schedule: write `task <id> \\\"label\\\" duration: <n> after: <preds>` and it runs the forward/backward pass and returns Early/Late Start & Finish, total slack, project duration, and highlights the critical path in red. Supports PDM dependency types (FS/SS/FF/SF) with lag/lead (`after: A SS+2d`), three-point estimation (`duration: 4/6/10` → te + variance), milestones (`milestone`), swimlanes (`lane: \\\"Team\\\"`), a `layout: timescaled` mode (x ∝ ES, width ∝ duration) for a network-Gantt hybrid, and a legacy `layout: aoa` mode (activity-on-arrow: numbered event circles + arrow activities + dummy activities, FS-only). Distinct from `flowchart` (no scheduling), `timeline`/Gantt (no critical-path computation), and `bpmn` (organisational process, not a one-off schedule).\",\n cluster: \"project-management\",\n standard: \"PMI PMBOK 7 + Moder 1983 (AON/PDM); see 32-PERT-STANDARD.md\",\n syntaxKey: \"pert\",\n },\n // ── Structural UML ───────────────────────────────────────────\n {\n type: \"umlclass\",\n name: \"UML Class Diagram\",\n tagline:\n \"OMG UML 2.5.1 class diagram — classifiers (class / abstract / interface / enum / datatype / primitive) joined by the six relationship kinds, with visibility, multiplicity, and stereotypes.\",\n useWhen:\n \"Use for OO design — the static type structure of a software system. Declare `class X { + name: T }` / `«interface» Y { + op(): R }` / `«enumeration» Z { A B C }`, then connect with PlantUML-flavoured glyphs: `<|--` generalization (hollow triangle to parent), `<|..` realization (dashed + hollow triangle to interface), `*--` composition (filled diamond at the whole), `o--` aggregation (hollow diamond at the whole), `-->` directed association (open arrow to target), `..>` dependency (dashed + open arrow), `--` plain association. Adornment placement is normalised regardless of which id is typed first (reversed forms accepted). Mermaid `classDiagram` glyphs work as aliases. Layout is generalization-driven (parents on top by default). Distinct from `erd` (data tables + crow's-foot — no visibility/methods/inheritance) and from `entity` (legal/corporate ownership). This is the C4 (§30) Code-level engine.\",\n cluster: \"software-uml\",\n standard:\n \"OMG UML 2.5.1 §9–§11 (Classification / Classifiers / Associations) + ISO/IEC 19505-2:2012; see 36-UMLCLASS-STANDARD.md\",\n syntaxKey: \"umlclass\",\n },\n {\n type: \"faulttree\",\n name: \"Fault Tree Analysis\",\n tagline:\n \"Deductive top-down reliability analysis — decompose one undesired top event through Boolean AND/OR/voting gates to basic component failures; the engine computes the minimal cut sets and the top-event probability.\",\n useWhen:\n \"Use for safety / reliability analysis: start from one top event and decompose its causes through gates down to basic events with known failure probabilities. Flat declaration wired by id: `top T \\\"…\\\" = OR(G1, G2)`, `gate G1 = AND(A, B)`, `basic A \\\"…\\\" p: 0.01`. Gates: AND/OR/XOR(a,b,…), VOTING(k/n; …), INHIBIT(x) if cond, PAND(a,b). `house H state: 0|1` switches branches; `undeveloped` for unanalysed causes. The engine *computes* the minimal cut sets (MOCUS) and P(top) (`prob: rare|mcub|exact`) and highlights single points of failure — the differentiator over a shape stencil. Keyword `faulttree` (alias `fta`). Distinct from `logic` (left-right signal netlist), `decisiontree` (expected-value rollback), and `fishbone` (qualitative, unquantified).\",\n cluster: \"risk-reliability\",\n standard:\n \"NUREG-0492 Fault Tree Handbook + IEC 61025:2006 + NASA FT Handbook 2002; MOCUS cut sets (Fussell-Vesely 1972); see 37-FAULT-TREE-STANDARD.md\",\n syntaxKey: \"faulttree\",\n },\n {\n type: \"bowtie\",\n name: \"Bowtie risk diagram\",\n tagline:\n \"Barrier-based risk management — one hazard's top event (the knot) with threats fanning in through preventative barriers on the left and consequences fanning out through mitigative barriers on the right, the whole shaped like a bow tie.\",\n useWhen:\n \"Use for process-safety / barrier risk analysis (oil & gas, aviation SMS, chemical, rail): one hazard, one top event, the threats that could cause it and the consequences if it happens, with the controls (barriers) in between. Indentation-structured DSL mirrors the CCPS 7-step build: `hazard \\\"…\\\"`, `topevent \\\"…\\\"`, then each `threat \\\"…\\\"` with indented `prevent \\\"…\\\"` barrier chain, each `consequence \\\"…\\\"` with indented `mitigate \\\"…\\\"` chain; `escalation \\\"…\\\"` nests under a barrier it degrades, `barrier \\\"…\\\"` nests under an escalation. Correct-by-construction: the engine *rejects* a threat/consequence with no barrier and an escalation not attached to a barrier (CCPS/EI barrier rule set). Qualitative — no probability rollup (that is `faulttree`'s job; a bowtie's left wing read backwards IS a fault tree). Distinct from `fishbone` (one-sided causes, no barriers) and `faulttree` (Boolean gates + cut sets, left wing only).\",\n cluster: \"risk-reliability\",\n standard:\n \"CCPS / Energy Institute 2018 (Bow Ties in Risk Management) + IEC 31010:2019 §B.4.6 + ICAO Doc 9859; Swiss-cheese lineage (Reason 1990); see 38-BOWTIE-STANDARD.md\",\n syntaxKey: \"bowtie\",\n },\n // ── Generic process / flow ───────────────────────────────────\n {\n type: \"flowchart\",\n name: \"Flowchart\",\n tagline: \"Generic flowchart with start/end/decision/process nodes.\",\n useWhen:\n \"Use for process flows, decision flows, or algorithms when no more specific diagram fits. Sugiyama layered layout with orthogonal routing.\",\n cluster: \"generic\",\n standard: \"Sugiyama layered DAG + orthogonal routing\",\n syntaxKey: \"flowchart\",\n },\n // ── Strategy / analysis ──────────────────────────────────────\n {\n type: \"matrix\",\n name: \"Matrix / quadrant\",\n tagline: \"2×2 / 3×3 / N×M matrix diagrams (Eisenhower, BCG, heatmap).\",\n useWhen:\n \"Use for prioritisation (Eisenhower urgent/important), portfolio (BCG growth/share), or any 2-axis categorisation.\",\n cluster: \"strategy\",\n standard: \"2×2 / N×M quadrant convention\",\n syntaxKey: \"matrix\",\n },\n {\n type: \"orgchart\",\n name: \"Organisation chart\",\n tagline: \"Corporate or team reporting-line hierarchy.\",\n useWhen:\n \"Use for reporting lines, team structure, or organisational design. Tidy-tree layout (not to be confused with legal `entity` ownership).\",\n cluster: \"corporate-legal\",\n standard: \"Reingold-Tilford tidy tree\",\n syntaxKey: \"orgchart\",\n },\n // ── Knowledge / brainstorming ────────────────────────────────\n {\n type: \"mindmap\",\n name: \"Mindmap\",\n tagline: \"Radial or markmap-style mindmap from markdown headings.\",\n useWhen:\n \"Use for brainstorming, note structures, concept maps, or outline visualisation. Accepts markdown-headings input.\",\n cluster: \"knowledge\",\n standard: \"Buzan radial + markmap-compat tree\",\n syntaxKey: \"mindmap\",\n },\n {\n type: \"timeline\",\n name: \"Timeline\",\n tagline: \"Horizontal or vertical timeline with events, eras, milestones.\",\n useWhen:\n \"Use for historical sequences, project milestones, product roadmaps. Horizontal or vertical orientation.\",\n cluster: \"generic\",\n standard: \"Timeline convention with era bands\",\n syntaxKey: \"timeline\",\n },\n // ── Risk & reliability (Bucket B) ────────────────────────────\n {\n type: \"eventtree\",\n name: \"Event Tree Analysis\",\n tagline:\n \"Forward-looking risk: one initiating event branches through each safety function into outcome sequences, with computed path frequencies.\",\n useWhen:\n \"Use to propagate the consequences of an initiating event through a chain of barriers/safety functions and quantify each outcome's frequency — the inductive complement to a fault tree and the right wing of a bowtie. Header `eventtree`/`eta`; declare the initiating event with a frequency, the ordered functions with success/failure branch probabilities, and outcome rows with `s`/`f`/`*` patterns. The engine computes path frequency = f_initiating × Π branch-probabilities and flags the dominant sequence.\",\n cluster: \"risk-reliability\",\n standard: \"IEC 62502:2010 · NUREG/CR-2300 (PRA) · ISO 31010 Annex B; see 39-EVENT-TREE-STANDARD.md\",\n syntaxKey: \"eventtree\",\n },\n {\n type: \"fmea\",\n name: \"FMEA (Failure Mode and Effects Analysis)\",\n tagline:\n \"The reliability worksheet that computes its own risk — RPN = S×O×D plus AIAG-VDA Action Priority, ranked and colour-coded.\",\n useWhen:\n \"Use to score and prioritise how each component/process step can fail — severity, occurrence, detection — and decide what to fix first. Header `fmea`; declare item/function → failure mode → effect (with `sev`) → cause (with `occ`) → controls (with `det`). The engine computes RPN = S×O×D and the AIAG-VDA Action Priority (High/Medium/Low), sorts the sheet, and colour-fills the RPN/AP cells by risk. Schematex's first table-shaped diagram.\",\n cluster: \"risk-reliability\",\n standard: \"AIAG-VDA FMEA Handbook (2019) · IEC 60812:2018 · SAE J1739 · MIL-STD-1629A; see 40-FMEA-STANDARD.md\",\n syntaxKey: \"fmea\",\n },\n // ── Systems thinking / stochastic ────────────────────────────\n {\n type: \"causalloop\",\n name: \"Causal Loop Diagram\",\n tagline:\n \"System-dynamics feedback map — signed causal links the engine reads to classify each loop as reinforcing (R) or balancing (B).\",\n useWhen:\n \"Use for systems thinking / system dynamics: variables connected by `+`/`−` causal links, where the engine detects feedback loops and labels each R (even number of negative links) or B (odd). Header `causalloop`/`cld`; write `A -> B : +` links and optional `loop R1 \\\"name\\\"` annotations and `delay` marks. Distinct from `sociogram` (social ties, no polarity) and `flowchart` (process steps).\",\n cluster: \"causality-analysis\",\n standard: \"Sterman, Business Dynamics (2000) · Meadows, Thinking in Systems; see 41-CAUSAL-LOOP-STANDARD.md\",\n syntaxKey: \"causalloop\",\n },\n {\n type: \"markov\",\n name: \"Markov chain\",\n tagline:\n \"Discrete-time Markov chain — circles + probability arcs, with the stationary distribution and recurrent/transient/absorbing classification computed for you.\",\n useWhen:\n \"Use to model a probabilistic state process (reliability/availability, queueing, regime models) where you want the long-run distribution or absorption answer, not just the picture. Header `markov`/`markovchain`; write `S1 -> S2 : 0.3` transitions (each state's out-edges sum to 1). The engine computes the stationary distribution, classifies states, and for absorbing chains the fundamental matrix. Sibling of `state` and `petri`.\",\n cluster: \"behavior-modeling\",\n standard: \"Norris, Markov Chains (1997) · Kemeny & Snell, Finite Markov Chains; see 42-MARKOV-CHAIN-STANDARD.md\",\n syntaxKey: \"markov\",\n },\n // ── Software / process engineering ───────────────────────────\n {\n type: \"gitgraph\",\n name: \"Git commit graph\",\n tagline:\n \"Branch-and-merge commit history on per-branch swimlanes — Mermaid gitGraph compatible.\",\n useWhen:\n \"Use to visualise a git branching/merging history. Header `gitGraph`; ordered `commit`, `branch <name>`, `checkout <name>`, `merge <name>`, `cherry-pick id: \\\"…\\\"`, with `commit id:/tag:/type: HIGHLIGHT|REVERSE`. Mermaid `gitGraph` syntax parity so LLM output is drop-in compatible. Commits sit on per-branch lanes ordered chronologically; merges join lanes.\",\n cluster: \"software-uml\",\n standard: \"Mermaid gitGraph syntax · git DAG model; see 43-GIT-GRAPH-STANDARD.md\",\n syntaxKey: \"gitgraph\",\n },\n {\n type: \"epc\",\n name: \"Event-driven Process Chain (EPC)\",\n tagline:\n \"ARIS business-process notation — alternating events (red hexagons) and functions (green rounded rects) joined by AND/OR/XOR connectors, with the alternation rule validated.\",\n useWhen:\n \"Use for ARIS-style business process modelling (SAP / enterprise BPM). Header `epc`; declare `event`, `function`, connectors `and`/`or`/`xor`, and the control flow between them. The engine validates strict event↔function alternation and connector legality (an event cannot be the source of an OR/XOR split). Distinct from `bpmn` and `flowchart` — a separate published standard with stricter rules.\",\n cluster: \"corporate-legal\",\n standard: \"ARIS / Keller, Nüttgens & Scheer (1992); see 44-EPC-STANDARD.md\",\n syntaxKey: \"epc\",\n },\n {\n type: \"idef0\",\n name: \"IDEF0 function model\",\n tagline:\n \"Federal function-modelling standard — boxes are activities, arrows are positional (the ICOM rule: Input-left, Control-top, Output-right, Mechanism-bottom).\",\n useWhen:\n \"Use to model what a system/process does and its inputs/controls/outputs/mechanisms — systems engineering, defence/government process docs, enterprise architecture. Header `idef0`; declare `function` boxes and ICOM arrows (`input`/`control`/`output`/`mechanism`) plus box→box flows that name the target ICOM side. The engine enforces ICOM placement and assigns node numbers, in a diagonal box staircase.\",\n cluster: \"project-management\",\n standard: \"FIPS PUB 183 (1993) · SADT (Ross); see 45-IDEF0-STANDARD.md\",\n syntaxKey: \"idef0\",\n },\n {\n type: \"threatmodel\",\n name: \"Threat model (DFD + STRIDE)\",\n tagline:\n \"Security data-flow diagram where the engine annotates each element with its applicable STRIDE threats and flags every flow that crosses a trust boundary.\",\n useWhen:\n \"Use for security threat modelling (Microsoft SDL / OWASP Threat Dragon workflow): DFD shapes (external entity, process, data store), labelled data flows, and `boundary` trust zones. Header `threatmodel`/`stride`. The engine maps each element type to its STRIDE categories (external = S,R; process = all six; store = T,I,D + conditional R for logs; flow = T,I,D) and accents flows crossing a trust boundary. Includes the DFD base notation (no separate `dfd` engine).\",\n cluster: \"network-infrastructure\",\n standard: \"Shostack, Threat Modeling (2014) STRIDE-per-element · Microsoft SDL · base DFD DeMarco/Yourdon; see 46-THREAT-MODEL-STRIDE-STANDARD.md + 31-DFD-STANDARD.md\",\n syntaxKey: \"threatmodel\",\n },\n] as const;\n\n/**\n * The library version that first shipped each diagram type, sourced from\n * CHANGELOG.md \"Added\" entries. Kept as a companion map (rather than a field on\n * the big registry literal) so the literal stays stable. `since` powers the\n * version badge on /diagrams and the cross-link to /changelog.\n */\nexport const DIAGRAM_SINCE: Readonly<Record<DiagramType, string>> = {\n // 0.1.0 — initial release (2026-03-15)\n genogram: \"0.1.0\",\n ecomap: \"0.1.0\",\n pedigree: \"0.1.0\",\n phylo: \"0.1.0\",\n sociogram: \"0.1.0\",\n logic: \"0.1.0\",\n circuit: \"0.1.0\",\n timing: \"0.1.0\",\n blockdiagram: \"0.1.0\",\n ladder: \"0.1.0\",\n sld: \"0.1.0\",\n entity: \"0.1.0\",\n fishbone: \"0.1.0\",\n // 0.1.1 (2026-04-18)\n flowchart: \"0.1.1\",\n venn: \"0.1.1\",\n matrix: \"0.1.1\",\n mindmap: \"0.1.1\",\n orgchart: \"0.1.1\",\n // 0.2.0 (2026-04-20)\n timeline: \"0.2.0\",\n decisiontree: \"0.2.0\",\n // 0.3.0 (2026-04-29)\n state: \"0.3.0\",\n pid: \"0.3.0\",\n // 0.4.0 (2026-05-05)\n erd: \"0.4.0\",\n breadboard: \"0.4.0\",\n bpmn: \"0.4.0\",\n fbd: \"0.4.0\",\n sfc: \"0.4.0\",\n // 0.4.3 (2026-05-16) — usecase\n usecase: \"0.4.3\",\n // 0.5.0 (2026-05-19)\n prisma: \"0.5.0\",\n // 0.5.1\n sequence: \"0.5.1\",\n // 0.6.0 — upcoming (committed post-0.5.2, not yet released)\n pert: \"0.6.0\",\n petri: \"0.6.0\",\n network: \"0.6.0\",\n // 0.6.4\n umlclass: \"0.6.4\",\n // 0.6.5\n faulttree: \"0.6.5\",\n // 0.6.6\n bowtie: \"0.6.6\",\n // 0.8.0 — Bucket B (event tree, FMEA, causal loop, Markov, git graph, EPC, IDEF0, threat model)\n eventtree: \"0.8.0\",\n fmea: \"0.8.0\",\n causalloop: \"0.8.0\",\n markov: \"0.8.0\",\n gitgraph: \"0.8.0\",\n epc: \"0.8.0\",\n idef0: \"0.8.0\",\n threatmodel: \"0.8.0\",\n};\n\nexport function getDiagramSince(type: string): string | undefined {\n const resolved = resolveDiagramType(type);\n return resolved ? DIAGRAM_SINCE[resolved] : undefined;\n}\n\nconst TYPE_ALIASES: Readonly<Record<string, DiagramType>> = {\n block: \"blockdiagram\",\n \"entity-structure\": \"entity\",\n graph: \"flowchart\",\n statediagram: \"state\",\n \"statediagram-v2\": \"state\",\n sequencediagram: \"sequence\",\n};\n\nexport function resolveDiagramType(type: string): DiagramType | undefined {\n const normalized = type.trim().toLowerCase();\n return (\n DIAGRAM_REGISTRY.find((d) => d.type === normalized)?.type ??\n TYPE_ALIASES[normalized]\n );\n}\n\nexport function getDiagramMeta(type: string): DiagramMeta | undefined {\n const resolved = resolveDiagramType(type);\n return DIAGRAM_REGISTRY.find((d) => d.type === resolved);\n}\n\nexport function getAllDiagramTypes(): DiagramType[] {\n return DIAGRAM_REGISTRY.map((d) => d.type);\n}\n","/**\n * AUTO-GENERATED by scripts/build-ai-content.mjs — do not edit by hand.\n * Regenerate with: npm run build:ai\n *\n * Compiled content bundle for the AI tool layer. Keeps MDX content\n * available to the published npm package without runtime fs access.\n */\n\nexport interface GeneratedExample {\n slug: string;\n diagram: string;\n title: string;\n description: string;\n standard: string;\n tags: readonly string[];\n complexity: number;\n featured: boolean;\n dsl: string;\n notes: string;\n}\n\nexport interface GeneratedSyntax {\n title: string;\n content: string;\n}\n\nexport const EXAMPLES: readonly GeneratedExample[] = [\n {\n \"slug\": \"block-nested-feedback\",\n \"diagram\": \"block\",\n \"title\": \"Nested feedback loops\",\n \"description\": \"A multi-loop control block diagram — an inner loop closes G2·G3 around sensor H1, an outer loop closes the whole forward path around sensor H2 routed over the top, and two summing junctions combine the reference with each feedback signal. The kind of cascaded architecture a generic flowchart can't lay out.\",\n \"standard\": \"Ogata control systems\",\n \"tags\": [\n \"nested-loops\",\n \"cascade\",\n \"feedback\",\n \"summing-junction\",\n \"sensor\",\n \"signal-flow\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"Nested Feedback Loops\\\"\\nG1 = block(\\\"G1(s)\\\") [role: plant]\\nG2 = block(\\\"G2(s)\\\") [role: plant]\\nG3 = block(\\\"G3(s)\\\") [role: plant]\\nH1 = block(\\\"H1(s)\\\") [role: sensor]\\nH2 = block(\\\"H2(s)\\\") [role: sensor, route: above]\\ns1 = sum(+R, -h2)\\ns2 = sum(+a, -h1)\\nin -> s1 [\\\"R(s)\\\"]\\ns1 -> G1 -> s2\\ns2 -> G2 -> G3\\nG3 -> out [\\\"Y(s)\\\"]\\nG2 -> H1\\nH1 -> s2\\nG3 -> H2\\nH2 -> s1\",\n \"notes\": \"## Scenario\\n\\nCascaded and nested control loops are everywhere in real plants — an inner velocity loop inside an outer position loop, an inner current loop inside a speed loop. Textbooks (Ogata, Franklin) draw them as block diagrams with multiple summing junctions and feedback paths that cross over the forward chain. Schematex routes those crossings automatically from a signal-flow description.\\n\\n## Annotation key\\n\\n- `block(\\\"label\\\") [role: plant|sensor]` — transfer-function block; `role` drives the visual styling so plants and sensors read differently\\n- `sum(+R, -h2)` — a summing junction with explicit signs: adds reference `R`, subtracts the outer feedback `h2`\\n- `route: above` on `H2` — forces the outer feedback sensor to route over the top of the diagram, keeping the long return path clear of the forward chain\\n- `s1 -> G1 -> s2` — chained connections; signal flows left to right through the forward path\\n\\n## How to read\\n\\nThe inner loop is `G2 → G3 → H1 → s2`: sensor H1 feeds the plant output back to the second summing junction, closing a loop around `G2·G3`. The outer loop is wider — `G3 → H2 → s1` — where H2 (routed above) returns the final output to the first summing junction. The reference `R(s)` enters at `s1`, is corrected by both feedback signals in turn, and the cascaded plants drive `Y(s)`. Two nested loops, one signal-flow spec.\"\n },\n {\n \"slug\": \"block-pid-loop\",\n \"diagram\": \"block\",\n \"title\": \"PID control loop\",\n \"description\": \"Closed-loop PID block diagram with summing junction, controller, and plant — rendered from a signal-flow description without manual layout.\",\n \"standard\": \"Ogata control systems\",\n \"tags\": [\n \"PID\",\n \"closed-loop\",\n \"feedback\",\n \"summing-junction\",\n \"signal-flow\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"PID control loop\\\"\\nC = block(\\\"PID C(s)\\\") [role: controller]\\nG = block(\\\"Plant G(s)\\\") [role: plant]\\nerr = sum(+r, -y)\\nr = signal(\\\"r (setpoint)\\\")\\ny = signal(\\\"y (output)\\\")\\nin -> r\\nr -> err\\nerr -> C\\nC -> G\\nG -> y\\nG -> err\",\n \"notes\": \"## Scenario\\n\\nThe standard closed-loop PID block diagram appears in every control systems textbook (Ogata, Franklin, Åström) and every control system design spec sheet. Schematex renders it from a signal-flow description — not a generic flowchart — using proper summing junction symbols and automatic feedback routing.\\n\\n## Annotation key\\n\\n- `block(\\\"label\\\") [role: ...]` — transfer function block; `role: controller` and `role: plant` affect visual styling\\n- `sum(+r, -y)` — summing junction: adds the `+r` (reference) signal and subtracts the `-y` (output feedback)\\n- `signal(\\\"label\\\")` — named signal node\\n- `G -> err` — the feedback path: plant output `y` routes back to the summing junction\\n\\n## How to read\\n\\nThe setpoint `r` enters the summing junction `err`, which subtracts the plant output `y` to compute the error signal. The PID controller `C(s)` processes the error and drives the plant `G(s)`. The plant output `y` is both the system output and the feedback signal. The loop is closed when `G -> err` feeds `y` back to the summing junction.\"\n },\n {\n \"slug\": \"bowtie-hot-work-fire\",\n \"diagram\": \"bowtie\",\n \"title\": \"Hot work — ignition of flammable atmosphere\",\n \"description\": \"A bowtie with escalation factors on both wings — a preventative and a mitigative barrier are each degraded by a named condition with its own escalation-factor barrier, exercising the full element vocabulary.\",\n \"standard\": \"CCPS / Energy Institute 2018\",\n \"tags\": [\n \"bowtie\",\n \"risk\",\n \"escalation-factor\",\n \"hot-work\",\n \"fire\",\n \"barrier\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"bowtie \\\"Hot work — fire bowtie\\\"\\nhazard \\\"Hot work near flammable materials\\\"\\ntopevent \\\"Ignition of flammable atmosphere\\\"\\nthreat \\\"Sparks / hot slag\\\"\\n prevent \\\"Hot-work permit\\\"\\n prevent \\\"Fire watch\\\"\\n escalation \\\"Fire watch leaves post early\\\"\\n barrier \\\"Post-work monitoring period (60 min)\\\"\\nthreat \\\"Static discharge\\\"\\n prevent \\\"Bonding + grounding\\\"\\n prevent \\\"Antistatic PPE\\\"\\nconsequence \\\"Flash fire\\\"\\n mitigate \\\"Fixed fire suppression\\\"\\n escalation \\\"Suppression isolated for maintenance\\\"\\n barrier \\\"Impairment register + MoC\\\"\\nconsequence \\\"Asset loss\\\"\\n mitigate \\\"Fire-rated separation\\\"\\n mitigate \\\"Business-continuity plan\\\"\",\n \"notes\": \"## What this shows\\n\\nThe complete element vocabulary, with **escalation factors on both wings** — because a mitigative barrier can be degraded just as a preventative one can. On the left, the \\\"Fire watch\\\" barrier is defeated if the watch leaves early, controlled by a mandatory post-work monitoring period. On the right, the \\\"Fixed fire suppression\\\" barrier is defeated when isolated for maintenance, controlled by an impairment register and management-of-change.\\n\\nThe left wing is taller than the right (its escalation drops deeper), so it sets the diagram height while the right wing stays centred about the knot. Each escalation hangs into the whitespace between bands on a muted *degrades* connector, never colliding with the next line.\"\n },\n {\n \"slug\": \"bowtie-lpg-loss-of-containment\",\n \"diagram\": \"bowtie\",\n \"title\": \"LPG storage — loss of containment\",\n \"description\": \"The canonical process-safety bowtie — three threats fan in through preventative barrier chains, three consequences fan out through mitigative chains, around the central loss-of-containment top event.\",\n \"standard\": \"CCPS / Energy Institute 2018\",\n \"tags\": [\n \"bowtie\",\n \"risk\",\n \"process-safety\",\n \"barrier\",\n \"hazard\",\n \"loss-of-containment\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"bowtie \\\"LPG storage — loss of containment\\\"\\nhazard \\\"LPG stored under pressure\\\"\\ntopevent \\\"Loss of containment\\\"\\nthreat \\\"Corrosion of vessel wall\\\"\\n prevent \\\"Corrosion-resistant coating\\\"\\n prevent \\\"UT thickness inspection\\\"\\nthreat \\\"Overpressure during filling\\\"\\n prevent \\\"High-pressure trip (SIL 2)\\\"\\n prevent \\\"Pressure relief valve\\\"\\nthreat \\\"Mechanical impact (vehicle)\\\"\\n prevent \\\"Bollards / vehicle barriers\\\"\\n prevent \\\"Site speed limit + banksman\\\"\\nconsequence \\\"Jet fire\\\"\\n mitigate \\\"Gas detection + ESD\\\"\\n mitigate \\\"Deluge / water spray\\\"\\nconsequence \\\"Vapour cloud explosion\\\"\\n mitigate \\\"Ignition-source control (ATEX)\\\"\\n mitigate \\\"Blast-resistant control room\\\"\\nconsequence \\\"Toxic / asphyxiation exposure\\\"\\n mitigate \\\"Personal gas monitors\\\"\\n mitigate \\\"Emergency evacuation plan\\\"\",\n \"notes\": \"## What this shows\\n\\nThe integrating picture of barrier-based risk management for one major-accident scenario. The **hazard** (\\\"LPG stored under pressure\\\") sits above the central **top event** — the moment control is lost. To the **left**, three credible **threats** each fan in through a chain of **preventative barriers** (grey, on the line) that stop them reaching the knot. To the **right**, three **consequences** each fan out through a chain of **mitigative barriers** that limit the damage if the top event occurs.\\n\\nThis is the shape a process-safety reviewer expects on an A3: defence-in-depth depth on both wings, the knot in the middle, the hazard above. **Correct by construction** — the engine would reject any threat or consequence drawn with no barrier (a Swiss-cheese cartoon), so every line you see genuinely passes through a control.\"\n },\n {\n \"slug\": \"bowtie-runway-excursion\",\n \"diagram\": \"bowtie\",\n \"title\": \"Runway excursion (aviation SMS)\",\n \"description\": \"A non-process-industry bowtie — the same threat / barrier / consequence grammar applied to an aviation safety-management scenario, showing the vocabulary travels across domains.\",\n \"standard\": \"ICAO Doc 9859 + CCPS / EI 2018\",\n \"tags\": [\n \"bowtie\",\n \"risk\",\n \"aviation\",\n \"SMS\",\n \"ICAO\",\n \"barrier\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"bowtie \\\"Runway excursion\\\"\\nhazard \\\"Aircraft landing in adverse conditions\\\"\\ntopevent \\\"Runway excursion on landing\\\"\\nthreat \\\"Unstable approach\\\"\\n prevent \\\"Stabilised-approach gate (go-around policy)\\\"\\n prevent \\\"Approach monitoring + callouts\\\"\\nthreat \\\"Contaminated runway\\\"\\n prevent \\\"Runway condition reporting (RCR)\\\"\\n prevent \\\"Landing performance assessment\\\"\\nthreat \\\"Excessive landing speed\\\"\\n prevent \\\"Speed / energy management SOP\\\"\\n prevent \\\"Autobrake selection\\\"\\nconsequence \\\"Hull damage\\\"\\n mitigate \\\"Runway end safety area (RESA)\\\"\\n mitigate \\\"Arrestor bed (EMAS)\\\"\\nconsequence \\\"Injuries / fatalities\\\"\\n mitigate \\\"Cabin-crew brace + evacuation\\\"\\n mitigate \\\"Airport emergency response\\\"\",\n \"notes\": \"## What this shows\\n\\nThe bowtie is mandated well beyond process industries — ICAO's Safety Management Manual (Doc 9859) makes it a primary hazard-analysis tool for airlines. The grammar is identical: a **hazard** (landing in adverse conditions), a **top event** (the runway excursion), **threats** that could cause it through preventative barrier chains, and **consequences** limited by mitigative chains.\\n\\nIt reads the same to a non-specialist as a chemical-plant bowtie, which is exactly the point: one A3 puts the entire defence-in-depth story for a single scenario in front of a board or a regulator, regardless of industry.\"\n },\n {\n \"slug\": \"bowtie-working-at-height\",\n \"diagram\": \"bowtie\",\n \"title\": \"Working at height — fall from height\",\n \"description\": \"A defence-in-depth bowtie with an escalation factor — a preventative barrier is degraded by a named condition, which is itself controlled by an escalation-factor barrier dropping below the line.\",\n \"standard\": \"CCPS / Energy Institute 2018\",\n \"tags\": [\n \"bowtie\",\n \"risk\",\n \"escalation-factor\",\n \"defence-in-depth\",\n \"construction\",\n \"safety\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"bowtie \\\"Working at height\\\"\\nhazard \\\"Working at height\\\"\\ntopevent \\\"Person falls from height\\\"\\nthreat \\\"Guardrail removed for access\\\"\\n prevent \\\"Permit-to-work system\\\"\\n prevent \\\"Temporary edge protection\\\"\\n escalation \\\"Edge protection not inspected\\\"\\n barrier \\\"Pre-use inspection regime\\\"\\n prevent \\\"Spotter / banksman\\\"\\nthreat \\\"Fragile roof surface\\\"\\n prevent \\\"Crawling boards + signage\\\"\\n prevent \\\"Roof-access risk assessment\\\"\\nconsequence \\\"Fatality\\\"\\n mitigate \\\"Fall-arrest harness + lanyard\\\"\\n mitigate \\\"Rescue plan + first aid\\\"\\nconsequence \\\"Serious injury\\\"\\n mitigate \\\"Safety netting below\\\"\\n mitigate \\\"On-site medic + evacuation\\\"\",\n \"notes\": \"## What this shows\\n\\nTwo threats, two consequences, multi-barrier chains — and an **escalation factor**, the element that makes a bowtie an honest defence-in-depth model rather than a wish list. The \\\"Temporary edge protection\\\" barrier is degraded by a specific named condition (\\\"Edge protection not inspected\\\", amber), which drops vertically below the barrier on a muted *degrades* connector. That escalation factor is itself controlled by an **escalation-factor barrier** (\\\"Pre-use inspection regime\\\") one level deeper.\\n\\nReading order along each line is declaration order: the first barrier is the **outermost** (first line of defence, nearest the threat); the last is the **innermost** (nearest the knot). The escalation hangs into the whitespace below without disturbing the symmetry of the two threat lines.\"\n },\n {\n \"slug\": \"bpmn-incident-response\",\n \"diagram\": \"bpmn\",\n \"title\": \"Production incident response (BPMN)\",\n \"description\": \"Three-lane BPMN of an on-call rotation handling a production page — L1 triage, L2 investigation, and a Comms lane that posts status updates. Exercises timer intermediate event, severity-based XOR routing, and a self-loop on the triage gate.\",\n \"standard\": \"OMG BPMN 2.0.2 / ISO/IEC 19510:2013\",\n \"tags\": [\n \"bpmn\",\n \"business-process\",\n \"incident-response\",\n \"timer-event\",\n \"on-call\",\n \"sre\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"bpmn\\ndirection: LR\\ntitle: \\\"Production incident response\\\"\\n\\npool \\\"Monitoring\\\" blackbox\\n\\npool \\\"Engineering\\\" {\\n lane \\\"On-call L1\\\" {\\n A: start message \\\"Page received\\\"\\n ACK: task user \\\"Acknowledge\\\"\\n TR: task user \\\"Triage\\\"\\n G1: gateway xor \\\"Severity?\\\"\\n }\\n lane \\\"On-call L2\\\" {\\n INV: task user \\\"Investigate\\\"\\n ROOT: task service \\\"Root cause\\\"\\n FIX: task user \\\"Implement fix\\\"\\n DEPLOY: task service \\\"Deploy patch\\\"\\n }\\n lane \\\"Comms\\\" {\\n SP: task send \\\"Status page\\\"\\n T1: intermediate timer \\\"30 min\\\"\\n UP: task send \\\"Update users\\\"\\n PM: task user \\\"Post-mortem\\\"\\n Z: end \\\"Resolved\\\"\\n }\\n}\\n\\nflows\\nA --> ACK\\nACK --> TR\\nTR --> G1\\nG1 --? \\\"P1\\\" --> SP\\nG1 --? \\\"P2-P3\\\" --> INV\\nG1 --* \\\"info\\\" --> TR\\nSP --> INV\\nINV --> ROOT\\nROOT --> FIX\\nFIX --> DEPLOY\\nDEPLOY --> T1\\nT1 --> UP\\nUP --> PM\\nPM --> Z\\n\\\"Monitoring\\\" ~~> A : \\\"Alert\\\"\\nSP ~~> \\\"Monitoring\\\" : \\\"Status\\\"\",\n \"notes\": \"The shape of an incident-response runbook is exactly what BPMN was designed for: multiple roles handing off to each other under time pressure, with a clear escalation path and a hard line between \\\"what we did internally\\\" and \\\"what we told users\\\". Generic flowcharts blur those distinctions; BPMN's lanes make them auditable.\\n\\n**Three lanes, three roles.** L1 owns the page-acknowledgement SLA. L2 owns the technical fix. Comms owns the user-facing narrative. Every cross-lane handoff is visible as a sequence-flow that crosses a lane partition. When the post-mortem arrives, you can answer \\\"why did Comms post the all-clear before L2 confirmed?\\\" by reading the lane crossings.\\n\\n**Timer intermediate event.** `T1: intermediate timer \\\"30 min\\\"` is a double-ringed circle with a clock-face inner glyph. It says: *wait 30 minutes after the patch deploys before telling users the problem is fixed*. That delay isn't an arbitrary process step — it's the empirical bake time most SRE teams use to confirm a regression hasn't surfaced. Encoding it as a timer event (rather than a vague \\\"wait\\\" task) lets process-mining tools measure the actual wait distribution in production.\\n\\n**Self-loop on the triage XOR.** The default flow `G1 --* \\\"info\\\" --> TR` routes back to triage for info-level pages — the engineer keeps revisiting the page in their queue rather than escalating. This is a real cycle in the process graph; the layout's DFS cycle-break detects the back edge and lays out the rest as a forward DAG so the columns don't collapse.\\n\\n**Message flow to the monitoring system.** Status-page updates go *out* to the monitoring system as a message flow (`SP ~~> \\\"Monitoring\\\"`). The monitoring system is rendered as a black-box pool — Datadog / PagerDuty / Sentry / whatever your stack uses, you don't model their internals, you just model the message exchange.\"\n },\n {\n \"slug\": \"bpmn-loan-approval\",\n \"diagram\": \"bpmn\",\n \"title\": \"Loan application approval (BPMN)\",\n \"description\": \"Single-pool, two-lane BPMN of a bank loan approval workflow. Clerk completeness check feeds underwriter risk-scoring + review with two end states (approved / rejected). Canonical BPMN test case 7.2.\",\n \"standard\": \"OMG BPMN 2.0.2 / ISO/IEC 19510:2013\",\n \"tags\": [\n \"bpmn\",\n \"business-process\",\n \"loan\",\n \"banking\",\n \"xor-gateway\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"bpmn\\ndirection: LR\\ntitle: \\\"Loan Application Approval\\\"\\n\\npool \\\"Bank\\\" {\\n lane \\\"Clerk\\\" {\\n A: start \\\"Application received\\\"\\n B: task user \\\"Check completeness\\\"\\n G1: gateway xor \\\"Complete?\\\"\\n }\\n lane \\\"Underwriter\\\" {\\n C: task service \\\"Risk score\\\"\\n D: task user \\\"Underwriter review\\\"\\n G2: gateway xor \\\"Decision\\\"\\n E: end \\\"Approved\\\"\\n F: end \\\"Rejected\\\"\\n }\\n}\\n\\nflows\\nA --> B\\nB --> G1\\nG1 --? \\\"yes\\\" --> C\\nG1 --* \\\"no\\\" --> F\\nC --> D\\nD --> G2\\nG2 --? \\\"approve\\\" --> E\\nG2 --* \\\"reject\\\" --> F\",\n \"notes\": \"A real loan approval has more steps — KYC, fraud screening, document collection, escalation tiers — but every variant collapses onto this skeleton. The reason a *flowchart* doesn't suffice is the **swim-lane semantics**: Clerk and Underwriter are different roles with different SLAs, often different software, sometimes different legal liability. BPMN encodes that division as first-class lanes; a generic flowchart can only hint at it with shape colours.\\n\\nThe two **XOR gateways** (G1, G2) each have one **conditional flow** (`--?`) and one **default flow** (`--*`). The default flow is rendered with a slash mark at the source — it's the branch taken when no condition matches, and Schematex enforces *exactly one* default per gateway. Both conditional and default flows share the same gateway label (\\\"Complete?\\\" / \\\"Decision\\\"); the branch labels live on the connectors themselves.\\n\\nThe two end events (Approved / Rejected) sit in the underwriter lane because that's who owns the outcome. F is referenced from both gateways — the rejection path joins from either \\\"incomplete\\\" or \\\"rejected\\\" decisions, which is exactly how a human auditor would expect to read the process.\"\n },\n {\n \"slug\": \"bpmn-pizza-order\",\n \"diagram\": \"bpmn\",\n \"title\": \"Pizza order with black-box customer (BPMN)\",\n \"description\": \"Two-pool BPMN — external Customer (black-box) and a Pizzeria with Clerk / Chef / Delivery lanes. Exercises message flows across pools, manual / send task markers, and a rework loop on the chef's quality check. Canonical BPMN test case 7.1.\",\n \"standard\": \"OMG BPMN 2.0.2 / ISO/IEC 19510:2013\",\n \"tags\": [\n \"bpmn\",\n \"business-process\",\n \"message-flow\",\n \"black-box-pool\",\n \"rework-loop\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"bpmn\\ndirection: LR\\ntitle: \\\"Pizza order\\\"\\n\\npool \\\"Customer\\\" blackbox\\n\\npool \\\"Pizzeria\\\" {\\n lane \\\"Clerk\\\" {\\n A: start message \\\"Order received\\\"\\n B: task user \\\"Take order\\\"\\n }\\n lane \\\"Chef\\\" {\\n C: task manual \\\"Make pizza\\\"\\n G1: gateway xor \\\"Pizza ok?\\\"\\n D: task manual \\\"Rework\\\"\\n }\\n lane \\\"Delivery\\\" {\\n E: task send \\\"Deliver\\\"\\n F: end \\\"Done\\\"\\n }\\n}\\n\\nflows\\nA --> B\\nB --> C\\nC --> G1\\nG1 --? \\\"yes\\\" --> E\\nG1 --* \\\"no\\\" --> D\\nD --> C\\nE --> F\\n\\\"Customer\\\" ~~> A : \\\"Place order\\\"\\nE ~~> \\\"Customer\\\" : \\\"Pizza delivered\\\"\",\n \"notes\": \"This is the OMG-tutorial *hello world* for BPMN — every BPM textbook and certification course uses some version of it. It's a deceptively rich example: in 12 elements it covers every concept that distinguishes BPMN from a generic flowchart.\\n\\n**Black-box pool.** The customer's internal process is unknown (and irrelevant) to the pizzeria, so Customer is rendered as an empty rectangle with no flow objects. Schematex enforces this — adding a lane or a task inside a `blackbox` pool fails the parse. Black-box pools exist purely as message-flow endpoints.\\n\\n**Message flows cross pools, sequence flows do not.** The two `~~>` connectors are dashed with an open arrowhead and a small unfilled circle at the source. That's the *only* legal way information crosses a pool boundary in BPMN. Schematex's parser will reject `A --> \\\"Customer\\\"` with a clear error.\\n\\n**Rework loop.** `D --> C` creates a back-edge. The layout's longest-path layering would normally fail on cycles; Schematex's DFS-based cycle-break tags `D → C` as a back edge, runs longest-path on the remaining DAG, then routes the loop manually. This is exactly how real processes look — quality gates always have a \\\"go back and redo it\\\" branch.\\n\\n**Task markers communicate intent.** `start message` (envelope) means \\\"wait for an inbound message before starting\\\"; `task manual` means a person performs the work without software (\\\"hand-toss the dough\\\"); `task send` means \\\"send a message and continue\\\". An LLM picking markers correctly turns a vague flowchart into a precise process spec.\"\n },\n {\n \"slug\": \"bpmn-refund-escalation-compensation\",\n \"diagram\": \"bpmn\",\n \"title\": \"Refund escalation workflow\",\n \"description\": \"BPMN process for refund handling across Support, Risk, Finance, and an external payment processor, with SLA timer escalation and customer-facing message flows.\",\n \"standard\": \"OMG BPMN 2.0.2 / ISO/IEC 19510:2013\",\n \"tags\": [\n \"bpmn\",\n \"refund\",\n \"escalation\",\n \"timer\",\n \"finance\",\n \"support\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"bpmn\\ndirection: LR\\ntitle: \\\"Refund escalation\\\"\\n\\npool \\\"Customer\\\" blackbox\\npool \\\"Payment Processor\\\" blackbox\\n\\npool \\\"Merchant\\\" {\\n lane \\\"Support\\\" {\\n S: start message \\\"Refund request\\\"\\n TRIAGE: task user \\\"Triage request\\\"\\n DOCS: gateway xor \\\"Enough evidence?\\\"\\n ASK: task send \\\"Ask for documents\\\"\\n SLA: intermediate timer \\\"48h SLA\\\"\\n ESC: task user \\\"Escalate case\\\"\\n }\\n lane \\\"Risk\\\" {\\n RISK: task user \\\"Risk review\\\"\\n G1: gateway xor \\\"Policy breach?\\\"\\n DENY: task send \\\"Deny refund\\\"\\n }\\n lane \\\"Finance\\\" {\\n CALC: task service \\\"Calculate amount\\\"\\n APPROVE: task user \\\"Approve refund\\\"\\n ISSUE: task send \\\"Issue refund\\\"\\n ENDOK: end message \\\"Refund sent\\\"\\n ENDDENY: end message \\\"Denied\\\"\\n }\\n}\\n\\nflows\\nS --> TRIAGE\\nTRIAGE --> DOCS\\nDOCS --? \\\"missing\\\" --> ASK\\nASK --> SLA\\nSLA --> ESC\\nESC --> RISK\\nDOCS --* \\\"complete\\\" --> RISK\\nRISK --> G1\\nG1 --? \\\"yes\\\" --> DENY\\nDENY --> ENDDENY\\nG1 --* \\\"no\\\" --> CALC\\nCALC --> APPROVE\\nAPPROVE --> ISSUE\\nISSUE --> ENDOK\\n\\\"Customer\\\" ~~> S : \\\"Refund request\\\"\\nASK ~~> \\\"Customer\\\" : \\\"Need documents\\\"\\nDENY ~~> \\\"Customer\\\" : \\\"Denial notice\\\"\\nISSUE ~~> \\\"Payment Processor\\\" : \\\"Refund API\\\"\\n\\\"Payment Processor\\\" ~~> ENDOK : \\\"Refund confirmed\\\"\",\n \"notes\": \"## Scenario\\n\\nRefund handling is a process-governance problem: support receives the customer request, risk decides whether policy blocks the refund, finance approves and issues the money movement, and the payment processor confirms settlement. BPMN is the right notation because lanes and message flows are part of the meaning.\\n\\n## Annotation key\\n\\n- The `48h SLA` timer event makes escalation a timed process milestone rather than a vague task.\\n- Message flows (`~~>`) cross pool boundaries for customer and processor communication.\\n- The XOR gateway separates policy denial from the refund issuance path.\"\n },\n {\n \"slug\": \"breadboard-blink-led\",\n \"diagram\": \"breadboard\",\n \"title\": \"Blink LED on Arduino Uno\",\n \"description\": \"The maker hello-world. Arduino Uno + 220Ω resistor + 5mm red LED — D13 → resistor → LED → GND. Tests basic part placement, beside-left MCU, and the iconic Bézier wire arc.\",\n \"standard\": \"Fritzing visual conventions (no ISO standard)\",\n \"tags\": [\n \"breadboard\",\n \"arduino\",\n \"uno\",\n \"led\",\n \"blink\",\n \"tutorial\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"breadboard\\nboard: half\\ntitle: \\\"Blink LED — Arduino Uno hello-world\\\"\\n\\nparts\\n uno: mcu uno @beside-left\\n r1: resistor 220 @5e..9e\\n d1: led red @10e..10f\\n\\nwires\\n uno:5V --red-- @+t1\\n uno:GND --black-- @-t1\\n @+t1 --red-- @5a\\n uno:D13 --yellow-- @9a\\n @10j --black-- @-t1\",\n \"notes\": \"The \\\"Blink\\\" sketch is the Arduino equivalent of `printf(\\\"hello\\\\n\\\")` — the smallest program that proves the toolchain, board, and wiring all work. The breadboard wiring routes D13 through a 220Ω current-limiting resistor into the LED's anode (long lead, row e), and pulls the cathode (short lead, row f) down to ground via the bottom rail. Power and ground rails are jumpered from the Uno's 5V and GND pins on the left.\\n\\nIf the LED doesn't light up, three things to check, in order: LED polarity (the flat-side flag in the diagram is the cathode); resistor value (220–330Ω works for a 5mm red LED at 5V); and that D13 is the actual pin you're toggling in your sketch.\"\n },\n {\n \"slug\": \"breadboard-esp32-oled\",\n \"diagram\": \"breadboard\",\n \"title\": \"ESP32 + SSD1306 OLED I²C\",\n \"description\": \"ESP32 DevKit driving a 128×64 OLED display over I²C — four wires (3V3 / GND / SDA / SCL). The standard \\\"first display\\\" project for ESP32 learners.\",\n \"standard\": \"Fritzing visual conventions (no ISO standard)\",\n \"tags\": [\n \"breadboard\",\n \"esp32\",\n \"oled\",\n \"ssd1306\",\n \"i2c\",\n \"display\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"breadboard\\nboard: half\\ntitle: \\\"ESP32 + SSD1306 OLED I²C\\\"\\n\\nparts\\n esp: mcu esp32 @beside-left\\n oled: display oled-ssd1306 @8a\\n\\nwires\\n oled:GND --black-- @-t1\\n oled:VCC --red-- @+t1\\n oled:SCL --white-- @10c\\n oled:SDA --green-- @11c\\n esp:3V3 --red-- @+t1\\n esp:GND --black-- @-t1\\n esp:GPIO22 --white-- @10c\\n esp:GPIO21 --green-- @11c\",\n \"notes\": \"The SSD1306 OLED is the canonical first display project for an ESP32. Four wires get a 128×64 pixel monochrome display running over I²C. Two things differ from the equivalent Arduino Uno setup:\\n\\n**3.3 V supply, not 5 V.** The ESP32 runs at 3.3 V on every pin including its supply rail. Wiring an OLED to the Uno's 5 V will work, but mixing in 5 V signals from a Uno into the same I²C bus as the ESP32 will damage the ESP32. Stay on the 3V3 rail.\\n\\n**Default I²C pins are GPIO21 (SDA) and GPIO22 (SCL).** The Adafruit / Espressif convention is green for SDA and white for SCL — preserved here. These pins are remappable in firmware via `Wire.begin(sda, scl)` if you need them elsewhere.\"\n },\n {\n \"slug\": \"breadboard-hcsr04-distance\",\n \"diagram\": \"breadboard\",\n \"title\": \"HC-SR04 distance sensor + Arduino Uno\",\n \"description\": \"Four-wire ultrasonic distance sensor wiring — VCC / GND / TRIG / ECHO. The textbook Adafruit / SparkFun tutorial layout used in robotics intro classes.\",\n \"standard\": \"Fritzing visual conventions (no ISO standard)\",\n \"tags\": [\n \"breadboard\",\n \"arduino\",\n \"ultrasonic\",\n \"sensor\",\n \"hc-sr04\",\n \"robotics\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"breadboard\\nboard: half\\ntitle: \\\"HC-SR04 distance sensor + Arduino Uno\\\"\\n\\nparts\\n uno: mcu uno @beside-left\\n s1: sensor hcsr04 @8a\\n\\nwires\\n s1:VCC --red-- @+t1\\n s1:GND --black-- @-t1\\n s1:TRIG --yellow-- @9c\\n s1:ECHO --green-- @10c\\n uno:5V --red-- @+t1\\n uno:GND --black-- @-t1\\n uno:D9 --yellow-- @9c\\n uno:D10 --green-- @10c\",\n \"notes\": \"The HC-SR04 is the most common ultrasonic distance sensor in beginner Arduino kits. Four pins, four wires, no driver IC needed. The sensor module is rendered as a blue PCB tile with its four pin labels (VCC / TRIG / ECHO / GND) sitting above the breadboard rows where they plug in.\\n\\nThe TRIG line is a digital output from the Arduino — pulse it high for 10 µs and the sensor fires an ultrasonic chirp. The ECHO line is a digital input — its high-time, in microseconds, is twice the round-trip distance divided by the speed of sound. Conventional wiring uses yellow for TRIG and green for ECHO so the two signals are visually distinguishable, though the colors carry no electrical meaning.\"\n },\n {\n \"slug\": \"causalloop-growth-engine\",\n \"diagram\": \"causalloop\",\n \"title\": \"Startup growth engine (R and B loops)\",\n \"description\": \"A system-dynamics model of a viral product whose growth is capped by scaling strain. The engine enumerates every feedback loop and classifies each reinforcing (R) or balancing (B) by Sterman's even/odd rule.\",\n \"standard\": \"Sterman, Business Dynamics (2000)\",\n \"tags\": [\n \"causalloop\",\n \"cld\",\n \"system-dynamics\",\n \"feedback\",\n \"reinforcing\",\n \"balancing\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"causalloop \\\"Startup growth engine\\\"\\n \\\"Active users\\\" -> \\\"Word of mouth\\\" : +\\n \\\"Word of mouth\\\" -> \\\"New signups\\\" : +\\n \\\"New signups\\\" -> \\\"Active users\\\" : +\\n \\\"Active users\\\" -> \\\"Server load\\\" : +\\n \\\"Server load\\\" -> \\\"App performance\\\" : -\\n \\\"App performance\\\" -> \\\"Active users\\\" : + delay\\n \\\"Active users\\\" -> Revenue : +\\n Revenue -> \\\"Infra investment\\\" : +\\n \\\"Infra investment\\\" -> \\\"App performance\\\" : + delay\\n loop R1 \\\"Viral flywheel\\\"\\n loop B1 \\\"Scaling strain\\\"\",\n \"notes\": \"## What this shows\\n\\nThe two-sided story of every viral product. One reinforcing loop drives growth: more active users produce more word of mouth, which drives signups, which adds users — an amplifying cycle. A second, balancing loop pushes back: more users raise server load, which degrades app performance, which (after a delay) loses users. The `delay` markers put the system-dynamics hash mark on the slow legs, where the lag between cause and effect is what makes the system overshoot.\\n\\nThe engine finds and labels the loops for you, which a drawing tool cannot. It enumerates every elementary cycle in the signed graph with Johnson's algorithm, then applies Sterman's rule — count the negative links, even means reinforcing (R), odd means balancing (B) — and numbers them R1, B1… The growth cycle comes back R (zero negatives), the load cycle B (one negative). The named `loop` declarations attach the human phrasing — \\\"Viral flywheel\\\", \\\"Scaling strain\\\" — onto the loops the engine detects.\"\n },\n {\n \"slug\": \"causalloop-traffic-congestion\",\n \"diagram\": \"causalloop\",\n \"title\": \"Urban traffic congestion (two balancing loops)\",\n \"description\": \"The classic system-dynamics counterintuitive result — widening roads induces demand. The engine enumerates the feedback loops and classifies each reinforcing or balancing by link polarity.\",\n \"standard\": \"Sterman, Business Dynamics (2000)\",\n \"tags\": [\n \"causalloop\",\n \"cld\",\n \"system-dynamics\",\n \"induced-demand\",\n \"balancing\",\n \"transit\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"causalloop \\\"Urban traffic congestion\\\"\\n \\\"Road capacity\\\" -> \\\"Travel speed\\\" : +\\n \\\"Travel speed\\\" -> \\\"Driving attractiveness\\\" : +\\n \\\"Driving attractiveness\\\" -> \\\"Number of cars\\\" : +\\n \\\"Number of cars\\\" -> Congestion : +\\n Congestion -> \\\"Travel speed\\\" : -\\n Congestion -> \\\"Public transit use\\\" : +\\n \\\"Public transit use\\\" -> \\\"Number of cars\\\" : -\\n loop B1 \\\"Congestion brake\\\"\\n loop B2 \\\"Transit substitution\\\"\",\n \"notes\": \"## What this shows\\n\\nThe system-dynamics model behind one of the most counterintuitive results in transport policy: widening a road does not durably cut congestion, because faster travel makes driving more attractive, which pulls more cars onto the road until it clogs again. Two balancing loops fight the build-up — congestion itself slows travel and dampens demand, and congestion pushes commuters onto public transit, which removes cars.\\n\\nThe engine classifies the loops by polarity rather than asking you to. It walks the signed graph, enumerates each elementary cycle, and counts the negative links: both feedback loops here carry an odd number of negative links, so both come back **balancing (B)** and are numbered B1, B2. That even/odd classification — Sterman's textbook rule — is the analysis a drawing tool skips, and it is what explains why the system settles back to congestion no matter how much capacity is added.\"\n },\n {\n \"slug\": \"circuit-bridge-rectifier-supply\",\n \"diagram\": \"circuit\",\n \"title\": \"Bridge rectifier power supply\",\n \"description\": \"Four-diode full-wave bridge rectifier with a smoothing capacitor and load resistor, written as a compact electrical netlist.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"rectifier\",\n \"diode\",\n \"power-supply\",\n \"capacitor\",\n \"netlist\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Bridge Rectifier Supply\\\" netlist\\nV1 ac1 ac2 12Vac\\nD1 ac1 vout 1N4007\\nD2 ac2 vout 1N4007\\nD3 0 ac1 1N4007\\nD4 0 ac2 1N4007\\nC1 vout 0 470u\\nRload vout 0 1k\",\n \"notes\": \"## Scenario\\n\\nA technician needs a quick schematic for the textbook AC-to-DC rectifier: a transformer secondary, four rectifier diodes, a reservoir capacitor, and a load. The netlist form keeps the topology precise while the renderer chooses the schematic placement.\\n\\n## Annotation key\\n\\n- `D1` to `D4` are ordinary diode components inferred from the `D` prefix.\\n- `0` is the canonical ground net.\\n- `C1` smooths the rectified output across `vout` and ground.\\n\\n## How to read\\n\\nDuring each half-cycle, two diodes conduct and steer current into `vout` with the same polarity. The capacitor charges near the peak and supplies the load between peaks, reducing ripple at `Rload`.\"\n },\n {\n \"slug\": \"circuit-ce-amplifier\",\n \"diagram\": \"circuit\",\n \"title\": \"NPN common-emitter amplifier\",\n \"description\": \"NPN common-emitter amplifier rendered from a five-line SPICE netlist with automatic component placement per IEEE 315.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"SPICE\",\n \"netlist\",\n \"BJT\",\n \"amplifier\",\n \"auto-layout\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"circuit \\\"CE Amp (netlist)\\\" netlist\\nV1 vcc 0 9V\\nRc vcc c 2.2k\\nRb vcc b 100k\\nQ1 c b e npn\\nRe e 0 1k\",\n \"notes\": \"## Scenario\\n\\nThe NPN common-emitter amplifier is the first transistor circuit every electronics student builds. Schematex renders it from a five-line SPICE netlist — the same format used in LTspice, ngspice, and Cadence — with automatic component placement and rail routing, so the diagram matches the hand-drawn textbook version without any manual layout.\\n\\n## Annotation key\\n\\n- `circuit \\\"...\\\" netlist` — enables netlist parsing mode (SPICE syntax)\\n- `V1 vcc 0 9V` — voltage source named V1, positive terminal at node `vcc`, negative at `0` (ground), value 9V\\n- `Rc vcc c 2.2k` — resistor Rc between nodes `vcc` and `c` with value 2.2 kΩ\\n- `Rb vcc b 100k` — base bias resistor between `vcc` and node `b`\\n- `Q1 c b e npn` — NPN BJT transistor: collector=c, base=b, emitter=e\\n- `Re e 0 1k` — emitter degeneration resistor between node `e` and ground\\n\\n## How to read\\n\\nThe supply rail (Vcc = 9 V) connects to the top of both resistors. Rc is the collector load; the output signal is taken across it. Rb biases the base into the active region. Re provides emitter degeneration for stability. Q1 amplifies a small base current into a large collector-to-emitter current flow. The auto-layout positions Vcc at top, ground at bottom, and Q1 in the center.\"\n },\n {\n \"slug\": \"circuit-opamp-inverting-amplifier\",\n \"diagram\": \"circuit\",\n \"title\": \"Inverting op-amp amplifier\",\n \"description\": \"A practical inverting op-amp stage rendered from a SPICE-style netlist with feedback and input resistors, split supply rails, and a labelled output node.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"op-amp\",\n \"amplifier\",\n \"feedback\",\n \"netlist\",\n \"analog\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Inverting Op-Amp (netlist)\\\" netlist\\nVin vin 0 AC1V\\nRin vin inv 10k\\nRf out inv 100k\\nU1 noninv inv out type=opamp label=\\\"U1 TL072\\\"\\nRbias noninv 0 10k\\nVp vcc 0 +12V\\nVn vee 0 -12V\",\n \"notes\": \"## Scenario\\n\\nAn analog engineer documents a standard inverting gain stage before moving to PCB layout. The two resistors make the gain visible in the schematic: `Rf / Rin = 10`, so the output is an inverted, amplified version of the input.\\n\\n## Annotation key\\n\\n- `type=opamp` selects the three-pin op-amp symbol in netlist mode.\\n- `Rin` and `Rf` are ordinary SPICE-style resistor lines.\\n- `noninv`, `inv`, and `out` are named nets, not pixel coordinates.\\n\\n## How to read\\n\\nThe input signal enters through `Rin` into the inverting input. `Rf` feeds the output back to the same node, closing the negative feedback loop. The non-inverting input is tied to ground through `Rbias`, giving the stage a stable reference.\"\n },\n {\n \"slug\": \"circuit-pullup-orientation-hint\",\n \"diagram\": \"circuit\",\n \"title\": \"Pull-up resistor circuit with dir= orientation hint\",\n \"description\": \"A netlist-mode circuit that uses the optional dir= orientation hint to draw the pull-up resistor vertically, showing lightweight layout control on top of automatic placement.\",\n \"standard\": \"IEEE 315 / IEC 60617\",\n \"tags\": [\n \"netlist\",\n \"pull-up\",\n \"dir\",\n \"orientation\",\n \"push-button\",\n \"SPICE\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Pull-up + push button\\\" netlist\\nV1 vcc 0 5V\\nR1 vcc sig 10k dir=down\\nSW1 sig 0 type=switch\\nC1 sig 0 100n\",\n \"notes\": \"## Scenario\\n\\nAn embedded engineer documents a classic active-low input: a pull-up resistor\\nholds the signal high, a push button pulls it to ground, and a small capacitor\\ndebounces it. The connectivity is written as a SPICE-style netlist — the engine\\nplaces everything from the node names — and one optional hint refines the look.\\n\\n## Annotation key\\n\\n- **netlist line** — `id node-A node-B value`; components that share a node name\\n are wired together. `0` is ground.\\n- **`dir=down`** — the optional orientation hint. `R1` connects `vcc` to `sig`;\\n by default the engine would lay it horizontally, but a pull-up reads best drawn\\n vertically from the supply rail down to the signal node, so `dir=down` rotates\\n just that symbol. Connectivity is unchanged — `dir=` only rotates the glyph.\\n- **`type=switch`** — the `SW1` id prefix is ambiguous, so the component type is\\n made explicit.\\n\\n## How to read\\n\\n`R1` ties `sig` up to `vcc` (drawn vertically thanks to `dir=down`). `SW1` and the\\ndebounce cap `C1` both go from `sig` to ground, so the engine recognises them as\\nshunt legs and drops them beneath the node. Pressing the button shorts `sig` to\\nground, pulling the input low.\"\n },\n {\n \"slug\": \"decisiontree-influence-market-entry\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Market entry (influence diagram)\",\n \"description\": \"A go/no-go market-entry decision as a compact influence diagram — demand observed before entering, a competitor response, and the profit objective — using the inline mode directive form.\",\n \"standard\": \"Howard & Matheson (1981) influence diagram\",\n \"tags\": [\n \"decisiontree\",\n \"influence\",\n \"decision-analysis\",\n \"dag\",\n \"strategy\",\n \"go-no-go\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"decisiontree \\\"Market Entry\\\"\\n mode: influence\\n decision Enter \\\"Enter market?\\\"\\n chance Demand \\\"Market demand\\\"\\n chance Competition \\\"Competitor response\\\"\\n value V \\\"Profit\\\" utility=120\\n Demand -> Enter\\n Demand -> V\\n Competition -> V\\n Enter -> V\",\n \"notes\": \"## What this shows\\n\\nA classic go/no-go framed as an **influence diagram**, written with the inline `mode: influence` directive (the alternative to the `decisiontree:influence` header). The decision-maker controls one **rectangle** — whether to enter — against two uncertain **ovals**, market demand and the competitor's response, all feeding a single profit **octagon**.\\n\\nTwo arcs land on the decision and the value node from demand. `Demand -> Enter` is a **dashed informational arc**: demand is read before committing to entry, so the choice can react to it. `Demand -> V` and `Competition -> V` are functional arcs — both directly shape profit — while `Enter -> V` ties the chosen action into the payoff. The graph stays acyclic and carries exactly one value node, the two structural rules the engine enforces; it captures the shape of the bet without unrolling every demand-by-competitor branch into a tree.\"\n },\n {\n \"slug\": \"decisiontree-influence-oil-wildcatter\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Oil wildcatter (influence diagram)\",\n \"description\": \"The canonical decision-analysis teaching problem as a compact influence diagram — a drill decision informed by a seismic test, the uncertain oil state, and the profit objective, wired as a clean acyclic graph instead of an unrolled tree.\",\n \"standard\": \"Howard & Matheson (1981) influence diagram\",\n \"tags\": [\n \"decisiontree\",\n \"influence\",\n \"decision-analysis\",\n \"dag\",\n \"oil-and-gas\",\n \"howard-matheson\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"decisiontree:influence \\\"Oil Wildcatter\\\"\\n decision Drill \\\"Drill?\\\"\\n chance Oil \\\"Oil present\\\"\\n chance Seismic \\\"Seismic test\\\"\\n value Profit \\\"Net profit\\\" utility=42\\n Seismic -> Oil\\n Seismic -> Drill\\n Oil -> Profit\\n Drill -> Profit\",\n \"notes\": \"## What this shows\\n\\nThe textbook oil-wildcatter problem drawn the way a decision analyst frames it first — as an **influence diagram** rather than a fully unrolled decision tree. One **rectangle** for the drill decision, two **ovals** for the uncertainties (whether oil is present, what the seismic test reads), and one **octagon** for the profit objective. The whole problem is four nodes and four arcs, no matter how many states each variable could take.\\n\\nThe arcs carry the structure. `Seismic -> Drill` is a **dashed informational arc**: the seismic result is observed *before* the drill choice is made — that's the entire reason the test is worth running. `Seismic -> Oil` is a relevance arc (the reading is conditioned on the true oil state), and `Oil -> Profit` plus `Drill -> Profit` are functional arcs feeding the payoff. This mode is deliberately structural — it shows what informs what, without solving for expected value; reach for decision-analysis mode when you want the numbers folded back.\"\n },\n {\n \"slug\": \"decisiontree-investment-analysis\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Investment decision analysis\",\n \"description\": \"Decision-analysis tree evaluating build-vs-buy vs hybrid for a platform choice — chance nodes with probabilities, automatic expected-value rollback.\",\n \"standard\": \"Raiffa & Schlaifer (1961)\",\n \"tags\": [\n \"decisiontree\",\n \"decision-analysis\",\n \"expected-value\",\n \"investment\",\n \"buildvbuy\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:decision \\\"Platform Vendor Choice\\\"\\n\\ndecision \\\"Which vendor?\\\"\\n choice \\\"Build in-house\\\"\\n chance \\\"Project outcome\\\"\\n prob 0.6 end \\\"On-time delivery\\\" payoff=900000\\n prob 0.4 end \\\"Over budget / delayed\\\" payoff=150000\\n choice \\\"Managed SaaS vendor\\\"\\n end \\\"Predictable cost\\\" payoff=500000\\n choice \\\"Hybrid approach\\\"\\n chance \\\"Integration complexity\\\"\\n prob 0.5 end \\\"Smooth integration\\\" payoff=700000\\n prob 0.5 end \\\"Integration rework\\\" payoff=300000\",\n \"notes\": \"## Scenario\\n\\nA CTO is deciding how to stand up a new data-platform layer: build internally, buy managed SaaS, or take a hybrid. Each path has outcomes with probabilities and net-value estimates. The decision-analysis tree rolls the expected value back to the decision node so the optimal branch is identified automatically.\\n\\n## Annotation key\\n\\n- `decision \\\"…\\\"` — actor chooses a branch\\n- `chance \\\"…\\\"` — nature chooses; `prob N` on each child (must sum to 1)\\n- `end \\\"…\\\" payoff=N` — terminal payoff\\n- `choice \\\"label\\\"` — label on an outgoing decision branch\\n- EV rollback: chance = probability-weighted sum; decision = max child EV\\n\\n## How to read\\n\\nEvaluate each branch's expected value. Build in-house: 0.6 × 900k + 0.4 × 150k = **600k**. Managed SaaS: flat **500k**. Hybrid: 0.5 × 700k + 0.5 × 300k = **500k**. Under these estimates the optimal branch is *Build in-house* — the parser flags it on render. The chart's real value is in forcing stakeholders to state probabilities explicitly; sensitivity to them is where the interesting argument happens.\"\n },\n {\n \"slug\": \"decisiontree-iris-cart-ml\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Iris CART decision tree\",\n \"description\": \"Machine-learning decision tree for the classic Iris classifier with split thresholds, sample counts, Gini impurity, and class leaves.\",\n \"standard\": \"CART / scikit-learn plot_tree convention\",\n \"tags\": [\n \"decisiontree\",\n \"ml\",\n \"cart\",\n \"iris\",\n \"gini\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:ml \\\"Iris CART Classifier\\\"\\ndirection: top-down\\nimpurity: gini\\nclasses: setosa, versicolor, virginica\\n\\nsplit \\\"Petal length <= 2.45\\\" feature=petal_length op=\\\"<=\\\" threshold=2.45 samples=150 gini=0.667\\n true leaf \\\"Setosa\\\" class=setosa value=50 gini=0.0 samples=50\\n false split \\\"Petal width <= 1.75\\\" feature=petal_width op=\\\"<=\\\" threshold=1.75 samples=100 gini=0.5\\n true split \\\"Petal length <= 4.95\\\" feature=petal_length op=\\\"<=\\\" threshold=4.95 samples=54 gini=0.168\\n true leaf \\\"Versicolor\\\" class=versicolor value=49 gini=0.04 samples=49\\n false leaf \\\"Virginica\\\" class=virginica value=5 gini=0.32 samples=5\\n false leaf \\\"Virginica\\\" class=virginica value=45 gini=0.0 samples=45\",\n \"notes\": \"## Scenario\\n\\nModel explainability often starts with a small tree. This Iris example mirrors the structure exported by CART tools: feature thresholds inside split nodes, impurity metrics, samples, and class-labelled leaves.\\n\\n## Annotation key\\n\\n- `decisiontree:ml` selects ML mode.\\n- `split` nodes carry `feature`, `threshold`, `samples`, and `gini`.\\n- `true` and `false` prefixes define the branch semantics.\"\n },\n {\n \"slug\": \"decisiontree-support-triage\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Support ticket triage\",\n \"description\": \"Taxonomy-mode decision tree for front-line support — routes an incoming ticket through outage, billing, and reproducibility gates to the right team.\",\n \"standard\": \"Clinical/support decision flow\",\n \"tags\": [\n \"decisiontree\",\n \"support\",\n \"triage\",\n \"routing\",\n \"runbook\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"decisiontree \\\"Customer Support Triage\\\"\\ndirection: top-down\\n\\nquestion \\\"Is the service completely down?\\\"\\n yes: question \\\"Outage confirmed on status page?\\\"\\n yes: answer \\\"Follow incident protocol — page on-call\\\"\\n no: answer \\\"Check monitoring — open severity-1 ticket\\\"\\n no: question \\\"Is the issue affecting billing?\\\"\\n yes: answer \\\"Escalate to billing team — SLA breach risk\\\"\\n no: question \\\"Can user reproduce consistently?\\\"\\n yes: answer \\\"Collect HAR trace — file bug report\\\"\\n no: answer \\\"Ask for screenshot — watch for recurrence\\\"\",\n \"notes\": \"## Scenario\\n\\nThe support lead bakes this tree into the agent runbook so new hires can triage in week one without a buddy. Three gates — outage, billing, reproducibility — route 90% of tickets deterministically. The remaining 10% (edge cases, multi-category) get flagged for human escalation instead of guessed at.\\n\\n## Annotation key\\n\\n- `question \\\"text\\\"` — internal decision node\\n- `answer \\\"text\\\"` — terminal outcome\\n- `yes:` / `no:` — branch label\\n- Indentation (2 spaces) — parent-child nesting\\n\\n## How to read\\n\\nStart at the root. At each `question` node the agent answers yes or no and follows the matching branch. Every path terminates in an `answer` — a concrete next action, not another decision. The tree is deliberately shallow (max depth 3) so agents can hold it in their head; deeper branches would push into a runbook rather than a decision tree.\"\n },\n {\n \"slug\": \"ecomap-refugee-resettlement\",\n \"diagram\": \"ecomap\",\n \"title\": \"Refugee family resettlement\",\n \"description\": \"Ecomap of a refugee family's support network — IRC office, school, clinic, and sponsor family — categorized by resource type per Hartman 1978.\",\n \"standard\": \"Hartman 1978\",\n \"tags\": [\n \"resettlement\",\n \"cultural\",\n \"category\",\n \"arrow-direction\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"ecomap \\\"Nguyen Family Resettlement\\\"\\n center: family [label: \\\"Nguyen Family\\\"]\\n resettlement [label: \\\"IRC Office\\\", category: government]\\n school [label: \\\"Lincoln Elementary\\\", category: education]\\n esl [label: \\\"Adult ESL Class\\\", category: education]\\n clinic [label: \\\"Community Clinic\\\", category: health]\\n caseworker [label: \\\"Ms. Patel\\\", category: mental-health]\\n temple [label: \\\"Vietnamese Temple\\\", category: cultural]\\n neighbors [label: \\\"Sponsor Family\\\", category: community]\\n employer [label: \\\"Warehouse Job\\\", category: work]\\n cousins [label: \\\"Cousins (CA)\\\", category: family]\\n family === resettlement [label: \\\"active case\\\"]\\n family === school\\n family --- esl [label: \\\"twice weekly\\\"]\\n clinic --> family [label: \\\"vaccinations\\\"]\\n caseworker <-> family [label: \\\"weekly\\\"]\\n family === temple [label: \\\"anchor\\\"]\\n neighbors === family [label: \\\"housing host\\\"]\\n family --- employer [label: \\\"new, part-time\\\"]\\n cousins == family [label: \\\"phone support\\\"]\",\n \"notes\": \"## Scenario\\n\\nA resettlement caseworker at the IRC maps the Nguyen family's ecological support network during an initial home visit. The diagram surfaces which systems are strong anchors (temple, sponsor family) and which are fragile (new job, ESL class), guiding case prioritization and resource allocation.\\n\\n## Annotation key\\n\\n- `center: family [...]` — designates the central node (the family unit)\\n- `category: government / education / health / cultural / community / work / family` — color-codes each system node by domain\\n- `===` — strong, supportive tie; `==` — moderately strong; `---` — tenuous\\n- `-->` — unidirectional support (clinic delivers vaccinations to family)\\n- `<->` — reciprocal relationship (caseworker and family both invest in the relationship)\\n\\n## How to read\\n\\nThe family sits at the center with nine surrounding systems. The IRC and temple are the two strongest connections (===). The employer and ESL class are tenuous (---), representing early-stage relationships. The cousins in California provide moderate phone support (==) but no in-person resources. The caseworker's bidirectional arrow marks the primary professional support relationship.\"\n },\n {\n \"slug\": \"ecomap-substance-recovery\",\n \"diagram\": \"ecomap\",\n \"title\": \"Substance abuse recovery\",\n \"description\": \"Ecomap charting a client's recovery support network — AA group, family, probation, and therapist — with relationship strength and directional connections.\",\n \"standard\": \"Hartman 1978\",\n \"tags\": [\n \"recovery\",\n \"relationships\",\n \"line-types\",\n \"arrow-direction\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"ecomap \\\"Substance Abuse Recovery\\\"\\n center: client [male, age: 28, label: \\\"James\\\"]\\n aa [label: \\\"AA Group\\\", category: substance, importance: major]\\n sponsor [label: \\\"Bill (Sponsor)\\\", category: substance]\\n employer [label: \\\"Warehouse Job\\\", category: work]\\n mother [label: \\\"Mom\\\", category: family]\\n exwife [label: \\\"Ex-wife\\\", category: family]\\n kids [label: \\\"Children (2)\\\", category: family]\\n dealer [label: \\\"Old Friends\\\", category: substance]\\n probation [label: \\\"P.O. Johnson\\\", category: legal]\\n therapist [label: \\\"CBT Therapist\\\", category: mental-health]\\n client === aa\\n sponsor --> client\\n client --- employer [label: \\\"new, probationary\\\"]\\n client == mother [label: \\\"supportive\\\"]\\n client ~~~ exwife [label: \\\"custody conflict\\\"]\\n client - - kids [label: \\\"supervised visits\\\"]\\n client -/- dealer [label: \\\"trying to cut off\\\"]\\n probation --> client\\n therapist <-> client [label: \\\"weekly\\\"]\",\n \"notes\": \"## Scenario\\n\\nA case manager at a substance abuse recovery center creates this ecomap during an initial biopsychosocial assessment. The diagram externalises the client's full ecological field — every system pressing on his recovery — and immediately surfaces the imbalance: most energy flows inward (legal supervision, sponsor), almost nothing flows outward. The visual becomes the conversation starter for the treatment plan.\\n\\n## Annotation key\\n\\n- `===` — strong, supportive connection\\n- `==` — moderately strong connection\\n- `---` — tenuous or fragile connection\\n- `~~~` — stressful, conflicted connection\\n- `-/-` — severing or cut-off relationship\\n- `- - ` — currently restricted (supervised visits shown with spaces)\\n- `-->` — one-way energy or support flow (giver → receiver)\\n- `<->` — reciprocal, mutual relationship\\n- `category: mental-health / family / legal / work / substance` — colors the node by domain\\n- `importance: major` — increases node prominence in the layout\\n\\n## How to read\\n\\nThe client sits at the center. Arrow directions show who gives energy to whom: the probation officer and sponsor both point *toward* James (external pressure / support), while James gives energy *toward* the AA group. The therapist is the only `<->` reciprocal relationship — the treatment alliance. The `-/-` (severing) line to the dealer marks the highest-risk edge in early recovery. Supervised visits (`- -`) with the children shows the family system is strained but not severed.\"\n },\n {\n \"slug\": \"ecomap-teen-client\",\n \"diagram\": \"ecomap\",\n \"title\": \"Teen client intake\",\n \"description\": \"Quick intake ecomap for a 15-year-old showing family, school, soccer peers, and therapist — drawn in under five minutes during a counseling session.\",\n \"standard\": \"Hartman 1978\",\n \"tags\": [\n \"adolescent\",\n \"intake\",\n \"minimal\",\n \"school\",\n \"peers\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"ecomap \\\"Marcus, age 15\\\"\\n center: client [label: \\\"Marcus\\\"]\\n mom [label: \\\"Mother\\\", category: family]\\n dad [label: \\\"Father (divorced)\\\", category: family]\\n school [label: \\\"East High School\\\", category: education]\\n coach [label: \\\"Soccer Coach\\\", category: community]\\n peers [label: \\\"Soccer team\\\", category: community]\\n therapist [label: \\\"Ms. Chen\\\", category: mental-health]\\n mom === client [label: \\\"primary caregiver\\\"]\\n dad --- client [label: \\\"EOW weekends\\\"]\\n school === client\\n coach --> client [label: \\\"mentor\\\"]\\n peers === client\\n therapist <-> client [label: \\\"weekly\\\"]\",\n \"notes\": \"## Scenario\\n\\nA school-based counselor draws this ecomap during an initial intake session with Marcus, a 15-year-old referred for behavioral issues. The diagram takes under five minutes and immediately shows where Marcus's support is concentrated (peers, soccer team) and where it's fragile (divorced father, every-other-weekend contact).\\n\\n## Annotation key\\n\\n- `center: client` — the identified young person\\n- `===` — strong connection; `---` — tenuous connection\\n- `-->` — mentor/support flows toward client\\n- `<->` — reciprocal therapeutic alliance\\n- `EOW weekends` — edge label capturing the visitation schedule\\n\\n## How to read\\n\\nMarcus's strongest systems are his mother (primary caregiver), school, and soccer peers — all strong ties (===). His father is a tenuous connection (---). The therapist and soccer coach have supportive directional relationships pointing toward Marcus. The soccer team appears to be the central protective factor in this adolescent's life.\"\n },\n {\n \"slug\": \"entity-family-office-trust\",\n \"diagram\": \"entity\",\n \"title\": \"Family office trust structure\",\n \"description\": \"Estate-planning entity structure with a grantor, irrevocable trust, trustee LLC, holding company, investment LLCs, and beneficiary distributions.\",\n \"standard\": \"Trust and estate planning conventions\",\n \"tags\": [\n \"entity\",\n \"trust\",\n \"family-office\",\n \"estate-planning\",\n \"distributions\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Family Office Trust\\\"\\njurisdiction SD \\\"South Dakota\\\" [color: \\\"#2563eb\\\"]\\njurisdiction DE \\\"Delaware\\\" [color: \\\"#059669\\\"]\\n\\nentity grantor \\\"Grantor\\\" individual [role: \\\"Settlor\\\"]\\nentity trust1 \\\"Irrevocable Dynasty Trust\\\" trust@SD [est: \\\"2021-04-01\\\", note: \\\"GST exempt\\\"]\\nentity trustee \\\"Trustee Services LLC\\\" llc@SD [role: \\\"Directed trustee\\\"]\\nentity holdco \\\"Family Holdings, Inc.\\\" corp@DE\\nentity realestate \\\"Real Estate LLC\\\" llc@DE\\nentity markets \\\"Marketable Securities LLC\\\" llc@DE\\nentity beneficiary \\\"Children Trust Share\\\" trust@SD\\n\\ngrantor -> trust1 : contribution\\ntrustee ==> trust1 [label: \\\"administrative control\\\"]\\ntrust1 -> holdco : 100%\\nholdco -> realestate : 100%\\nholdco -> markets : 100%\\ntrust1 --> beneficiary [label: \\\"distributions\\\"]\",\n \"notes\": \"## Scenario\\n\\nEstate attorneys often need to explain control, economics, and fiduciary roles on one page. This structure separates voting/control relationships from ownership and beneficiary distributions.\\n\\n## Annotation key\\n\\n- `trust` renders as an ellipse, distinct from corporate entities.\\n- `==>` marks voting or control without economic ownership.\\n- `-->` marks distributions to beneficiaries.\"\n },\n {\n \"slug\": \"entity-holding-company\",\n \"diagram\": \"entity\",\n \"title\": \"Multi-jurisdiction holding company\",\n \"description\": \"Multi-jurisdiction holding structure with a Delaware corp, UK subsidiary, and Cayman growth fund — the first document in any M&A due diligence package.\",\n \"standard\": \"Tier ownership\",\n \"tags\": [\n \"holding\",\n \"multi-jurisdiction\",\n \"trust\",\n \"fund\",\n \"Delaware\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Holdings\\\"\\nentity trust_a \\\"Founder Trust\\\" trust@SD\\nentity acme_inc \\\"Acme Inc.\\\" corp@DE\\nentity acme_uk \\\"Acme UK Ltd.\\\" llc@UK\\nentity acme_fund \\\"Acme Growth Fund LP\\\" fund@KY\\ntrust_a -> acme_inc : 100%\\nacme_inc -> acme_uk : 100%\\nacme_inc -> acme_fund : 60%\",\n \"notes\": \"## Scenario\\n\\nAn M&A attorney or corporate counsel draws this structure for a client engagement letter, board minutes, or due diligence data room. The entity diagram is the first document requested in any M&A transaction, debt financing, or regulatory review — it maps the corporate family tree with jurisdiction and ownership percentages.\\n\\n## Annotation key\\n\\n- `entity id \\\"Display Name\\\" type@jurisdiction` — creates an entity node\\n- `corp` — C-corporation or equivalent; `llc` — limited liability company; `trust` — trust entity; `fund` — investment fund/LP\\n- `@SD / @DE / @UK / @KY` — state or country jurisdiction\\n- `->` — equity ownership relationship\\n- `: 100% / 60%` — percentage label on the ownership line\\n\\n## How to read\\n\\nThe South Dakota founder trust owns 100% of the Delaware C-corp (the operating parent). The Delaware entity owns 100% of the UK subsidiary and 60% of the Cayman Islands fund (implying 40% external LP interest). This is a typical private equity or founder-led holding structure for multi-market operations.\"\n },\n {\n \"slug\": \"entity-international-tax\",\n \"diagram\": \"entity\",\n \"title\": \"International tax holding structure\",\n \"description\": \"Cross-border tax holding structure with Irish IP company, Dutch distribution, and APAC entity — per OECD BEPS transfer-pricing documentation requirements.\",\n \"standard\": \"Tier ownership\",\n \"tags\": [\n \"cross-border\",\n \"IP-license\",\n \"royalty\",\n \"BEPS\",\n \"holding\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"entity-structure \\\"Acme Global Holdings\\\"\\nentity parent \\\"Acme Global, Inc.\\\" corp@US [note: \\\"Ultimate Parent\\\"]\\nentity ie-holdco \\\"Acme Ireland Holdings\\\" corp@IE\\nentity ie-ip \\\"Acme IP Ltd\\\" corp@KY [note: \\\"Holds group IP\\\"]\\nentity nl-bv \\\"Acme EU Distribution\\\" corp@NL\\nentity sg-apac \\\"Acme APAC Trading\\\" corp@SG\\nparent -> ie-holdco : 100%\\nie-holdco -> ie-ip : 100%\\nie-holdco -> nl-bv : 100%\\nie-ip -~-> nl-bv [label: \\\"IP License · royalty\\\"]\\nparent -> sg-apac : 100%\",\n \"notes\": \"## Scenario\\n\\nCorporate counsel or a Big Four tax team draws this structure during cross-border M&A due diligence or transfer-pricing documentation. The OECD BEPS framework requires taxpayers to document the substance and economic rationale of every intercompany flow — this diagram is the first attachment to the TP master file and the tax opinion memo.\\n\\n## Annotation key\\n\\n- `entity name \\\"Display Name\\\" corp@US` — creates an entity node; `corp` is the entity type, `US` is the jurisdiction\\n- `corp / llc / fund / trust` — entity type; determines the symbol rendered\\n- `@US / @IE / @KY / @NL / @SG` — ISO country code for jurisdiction labeling\\n- `[note: \\\"...\\\"]` — adds a subsidiary note below the entity name\\n- `->` — solid directed line; represents an equity ownership relationship\\n- `-~->` — dashed directed line; represents a contractual (non-equity) relationship such as an IP license or intercompany loan\\n- `: 100%` — label on a directed edge; shows the ownership percentage\\n\\n## How to read\\n\\nThe US parent owns 100% of the Irish holdco, which in turn holds both the Cayman IP entity and the Dutch distribution subsidiary. The dashed arrow from the IP entity to the Dutch entity represents the IP license — royalties flow from the Netherlands up to Cayman, shifting taxable income to a low-rate jurisdiction. Singapore APAC is a parallel branch for Asia-Pacific operations, owned directly by the US parent.\"\n },\n {\n \"slug\": \"entity-series-a-cap-table\",\n \"diagram\": \"entity\",\n \"title\": \"Series A cap table\",\n \"description\": \"Post-Series A cap table showing founders, seed fund, lead VC, angel group, and ESOP pool with ownership percentages — for 409A valuations and board consents.\",\n \"standard\": \"Tier ownership\",\n \"tags\": [\n \"cap-table\",\n \"Series-A\",\n \"ESOP\",\n \"VC\",\n \"founders\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Inc. — post Series A\\\"\\nentity acme \\\"Acme Inc.\\\" corp@DE\\nentity founders \\\"Founders (2)\\\" individual\\nentity seed \\\"Seed Fund I\\\" lp@DE\\nentity lead \\\"Sequoia Series A\\\" lp@DE\\nentity angels \\\"Angel group\\\" individual\\nentity esop \\\"Employee Option Pool\\\" trust@DE\\nfounders -> acme : 45%\\nseed -> acme : 12%\\nlead -> acme : 22%\\nangels -> acme : 6%\\nesop -> acme : 15%\",\n \"notes\": \"## Scenario\\n\\nA startup attorney or CFO documents the post-Series A ownership table for a 409A valuation, board consent, or investor report. The cap table diagram makes the dilution story visual — founders can immediately see their post-money percentage, and the VC can verify their ownership stake before signing the term sheet.\\n\\n## Annotation key\\n\\n- `-> acme : 45%` — ownership arrow with percentage label; all percentages should sum to 100%\\n- `individual` — natural person (founder, angel)\\n- `lp` — institutional investor entity (fund/LP)\\n- `trust` — the ESOP/option pool (typically a Delaware trust or reserved pool)\\n- `corp@DE` — the issuer (Delaware C-corp)\\n\\n## How to read\\n\\nAcme Inc. (Delaware C-corp) sits at the bottom as the issuer. Five shareholder classes flow down with their ownership arrows: founders at 45%, the lead Series A investor at 22%, the employee option pool at 15%, the seed fund at 12%, and angels at 6%. Percentages sum to 100%, representing a clean fully-diluted cap table on the day of Series A close.\"\n },\n {\n \"slug\": \"epc-procurement\",\n \"diagram\": \"epc\",\n \"title\": \"Procurement EPC with XOR split\",\n \"description\": \"An ARIS event-driven process chain for purchase requisitions, branching on an XOR connector and re-joining on an AND. The engine validates EPC well-formedness — event/function alternation and the event-cannot-decide rule.\",\n \"standard\": \"ARIS EPC (Scheer)\",\n \"tags\": [\n \"epc\",\n \"aris\",\n \"business-process\",\n \"xor\",\n \"and\",\n \"control-flow\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"epc \\\"Purchase requisition\\\"\\n layout: tb\\n event E1 \\\"Material need identified\\\"\\n function F1 \\\"Create requisition\\\"\\n function F2 \\\"Determine source of supply\\\"\\n xor X1\\n event E2 \\\"Stock supplier exists\\\"\\n event E3 \\\"New supplier needed\\\"\\n function F3 \\\"Issue purchase order\\\"\\n function F4 \\\"Run tender process\\\"\\n and A1\\n event E4 \\\"Order dispatched\\\"\\n event E5 \\\"Supplier qualified\\\"\\n E1 -> F1 -> F2 -> X1\\n X1 -> E2\\n X1 -> E3\\n E2 -> F3 -> A1\\n E3 -> F4 -> A1\\n A1 -> E4\\n A1 -> E5\",\n \"notes\": \"## What this shows\\n\\nA SAP-style procurement process modelled as an ARIS event-driven process chain (EPC), the notation that strictly alternates passive **events** (\\\"Material need identified\\\") and active **functions** (\\\"Create requisition\\\"). After sourcing, an **XOR** connector splits the flow on a real decision — an existing stock supplier versus a new supplier needing a tender — and the two paths re-converge on an **AND** connector that fans back out to the dispatched order and the qualified-supplier outcome.\\n\\nEPC's value here is structural validation, not a computed number. The engine checks the well-formedness rules and flags violations rather than silently drawing a broken model: event/function alternation along every path, single-in/single-out multiplicity carried by the connectors, reachability from start to end, and the **event-cannot-decide signature rule** — a passive event may not be the source of an XOR/OR split. That's why the decision routes *through* function `F2` before reaching the XOR, which is the correct ARIS form.\"\n },\n {\n \"slug\": \"erd-billing-ledger-audit-trail\",\n \"diagram\": \"erd\",\n \"title\": \"Billing ledger and audit trail\",\n \"description\": \"Crow's-foot ERD for an immutable SaaS billing ledger with customers, invoices, payments, refunds, ledger entries, and audit events.\",\n \"standard\": \"Crow's-foot ERD\",\n \"tags\": [\n \"erd\",\n \"billing\",\n \"ledger\",\n \"audit-trail\",\n \"finance\",\n \"schema\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"erd\\ntitle: \\\"Billing Ledger\\\"\\ndirection: LR\\n\\ntable Customer {\\n customer_id uuid PK\\n email varchar UK\\n billing_currency char NN\\n}\\ntable Subscription {\\n subscription_id uuid PK\\n customer_id uuid FK -> Customer.customer_id\\n status varchar NN\\n current_period_end timestamptz\\n}\\ntable Invoice {\\n invoice_id uuid PK\\n customer_id uuid FK -> Customer.customer_id\\n subscription_id uuid FK -> Subscription.subscription_id\\n number varchar UK\\n total_cents bigint NN\\n status varchar NN\\n}\\ntable Payment {\\n payment_id uuid PK\\n invoice_id uuid FK -> Invoice.invoice_id\\n provider_ref varchar UK\\n amount_cents bigint NN\\n captured_at timestamptz\\n}\\ntable Refund {\\n refund_id uuid PK\\n payment_id uuid FK -> Payment.payment_id\\n amount_cents bigint NN\\n reason varchar\\n}\\ntable LedgerEntry {\\n entry_id uuid PK\\n customer_id uuid FK -> Customer.customer_id\\n invoice_id uuid FK -> Invoice.invoice_id\\n payment_id uuid FK -> Payment.payment_id\\n refund_id uuid FK -> Refund.refund_id\\n entry_type varchar NN\\n amount_cents bigint NN\\n posted_at timestamptz NN\\n}\\ntable AuditEvent {\\n event_id uuid PK\\n actor_id uuid\\n entity_type varchar NN\\n entity_id uuid NN\\n action varchar NN\\n created_at timestamptz NN\\n}\\n\\nref Subscription.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"belongs to\\\"\\nref Invoice.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"billed to\\\"\\nref Invoice.subscription_id many-optional .. one-optional Subscription.subscription_id : \\\"for plan\\\"\\nref Payment.invoice_id many-optional -- one-mandatory Invoice.invoice_id : \\\"settles\\\"\\nref Refund.payment_id many-optional -- one-mandatory Payment.payment_id : \\\"reverses\\\"\\nref LedgerEntry.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"posts for\\\"\\nref LedgerEntry.invoice_id many-optional .. one-optional Invoice.invoice_id : \\\"source invoice\\\"\\nref LedgerEntry.payment_id many-optional .. one-optional Payment.payment_id : \\\"source payment\\\"\\nref LedgerEntry.refund_id many-optional .. one-optional Refund.refund_id : \\\"source refund\\\"\",\n \"notes\": \"## Scenario\\n\\nBilling schemas become risky when money movement and auditability are mixed into mutable order tables. This ERD separates commercial objects from immutable ledger entries, making it clear which facts can change and which entries are accounting evidence.\\n\\n## Annotation key\\n\\n- `LedgerEntry` points optionally to invoices, payments, and refunds because each entry has exactly one accounting source.\\n- Solid `--` relationships show identifying operational ownership.\\n- Dashed `..` relationships show optional audit/source references that should not control the lifecycle of the ledger row.\"\n },\n {\n \"slug\": \"erd-ecommerce-schema\",\n \"diagram\": \"erd\",\n \"title\": \"E-commerce schema\",\n \"description\": \"Production-style schema with Customer / Order / OrderLine / Product / Category — typical mid-complexity backend ERD with composite PK on the line-item table.\",\n \"standard\": \"Crow's-foot (Everest 1976) / DBML compatible\",\n \"tags\": [\n \"ERD\",\n \"crow's-foot\",\n \"schema\",\n \"e-commerce\",\n \"FK\",\n \"composite-PK\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"erd\\ntitle: \\\"E-commerce Schema\\\"\\ndirection: LR\\n\\ntable Customer {\\n customer_id int PK\\n email varchar UK\\n name varchar\\n created_at timestamp\\n}\\n\\ntable Address {\\n address_id int PK\\n customer_id int FK -> Customer.customer_id\\n line1 varchar\\n city varchar\\n zip varchar\\n}\\n\\ntable Category {\\n category_id int PK\\n name varchar\\n}\\n\\ntable Product {\\n product_id int PK\\n category_id int FK -> Category.category_id\\n name varchar\\n price decimal\\n}\\n\\ntable Order {\\n order_id int PK\\n customer_id int FK -> Customer.customer_id\\n placed_at timestamp\\n status varchar\\n}\\n\\ntable OrderLine {\\n order_id int PK FK -> Order.order_id\\n line_no int PK\\n product_id int FK -> Product.product_id\\n qty int\\n price decimal\\n}\\n\\nref Address.customer_id many-mandatory -- one-mandatory Customer.customer_id\\nref Order.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"places\\\"\\nref Product.category_id many-mandatory -- one-mandatory Category.category_id\\nref OrderLine.order_id many-mandatory -- one-mandatory Order.order_id\\nref OrderLine.product_id many-mandatory -- one-mandatory Product.product_id\",\n \"notes\": \"A six-table schema spanning four FK-depth layers: Category and Customer at the root; Product and Address at depth one; Order at depth two; OrderLine at depth three with a composite PK `(order_id, line_no)`. Demonstrates layered LR routing and labelled relationships (\\\"places\\\").\"\n },\n {\n \"slug\": \"erd-saas-rbac-multitenant\",\n \"diagram\": \"erd\",\n \"title\": \"Multi-tenant SaaS RBAC schema\",\n \"description\": \"Crow's-foot ERD for tenants, users, memberships, roles, permissions, invitations, and audit events in a SaaS workspace product.\",\n \"standard\": \"Crow's-foot ERD\",\n \"tags\": [\n \"erd\",\n \"saas\",\n \"multitenant\",\n \"rbac\",\n \"schema\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"erd\\ntitle: \\\"SaaS RBAC\\\"\\ndirection: LR\\n\\ntable Tenant {\\n tenant_id uuid PK\\n name varchar NN\\n plan varchar\\n}\\ntable User {\\n user_id uuid PK\\n email varchar UK\\n name varchar\\n}\\ntable Membership {\\n tenant_id uuid PK FK -> Tenant.tenant_id\\n user_id uuid PK FK -> User.user_id\\n role_id uuid FK -> Role.role_id\\n status varchar NN\\n}\\ntable Role {\\n role_id uuid PK\\n tenant_id uuid FK -> Tenant.tenant_id\\n name varchar NN\\n}\\ntable Permission {\\n permission_id uuid PK\\n key varchar UK\\n}\\ntable RolePermission {\\n role_id uuid PK FK -> Role.role_id\\n permission_id uuid PK FK -> Permission.permission_id\\n}\\ntable Invitation {\\n invitation_id uuid PK\\n tenant_id uuid FK -> Tenant.tenant_id\\n email varchar NN\\n}\\ntable AuditEvent {\\n event_id uuid PK\\n tenant_id uuid FK -> Tenant.tenant_id\\n actor_user_id uuid FK -> User.user_id\\n}\\n\\nref Membership.tenant_id many-mandatory -- one-mandatory Tenant.tenant_id : \\\"belongs to\\\"\\nref Membership.user_id many-mandatory -- one-mandatory User.user_id : \\\"joins\\\"\\nref Membership.role_id many-optional -- one-mandatory Role.role_id : \\\"has role\\\"\\nref Role.tenant_id many-mandatory -- one-mandatory Tenant.tenant_id : \\\"scoped to\\\"\\nref RolePermission.role_id many-mandatory -- one-mandatory Role.role_id\\nref RolePermission.permission_id many-mandatory -- one-mandatory Permission.permission_id\\nref Invitation.tenant_id many-optional .. one-mandatory Tenant.tenant_id\\nref AuditEvent.tenant_id many-mandatory -- one-mandatory Tenant.tenant_id\\nref AuditEvent.actor_user_id many-optional .. one-optional User.user_id\",\n \"notes\": \"## Scenario\\n\\nRBAC schemas are where generic ERD examples stop being useful. A SaaS product needs tenant scoping, composite keys on join tables, optional actor references for system events, and non-identifying edges for nullable audit metadata.\\n\\n## Annotation key\\n\\n- `Membership` and `RolePermission` use composite primary keys.\\n- `..` marks a non-identifying relationship.\\n- FK targets are declared inline and repeated as explicit `ref` lines for crow's-foot cardinality.\"\n },\n {\n \"slug\": \"erd-university-schema\",\n \"diagram\": \"erd\",\n \"title\": \"University schema (academic ERD)\",\n \"description\": \"Classic textbook schema with Student / Course / Enrollment associative entity and labelled relationships — the canonical Elmasri & Navathe ch.3 example.\",\n \"standard\": \"Crow's-foot (Everest 1976) / DBML compatible\",\n \"tags\": [\n \"ERD\",\n \"crow's-foot\",\n \"schema\",\n \"associative-entity\",\n \"M-N\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"erd\\ntitle: \\\"University Schema\\\"\\n\\ntable Student {\\n student_id int PK\\n name varchar\\n email varchar UK\\n major_id int FK -> Major.major_id\\n}\\n\\ntable Major {\\n major_id int PK\\n name varchar\\n}\\n\\ntable Course {\\n course_id int PK\\n title varchar\\n credits int\\n}\\n\\ntable Enrollment {\\n student_id int PK FK -> Student.student_id\\n course_id int PK FK -> Course.course_id\\n grade char\\n}\\n\\nref Student.major_id many-mandatory -- one-mandatory Major.major_id : \\\"majors in\\\"\\nref Enrollment.student_id many-mandatory -- one-mandatory Student.student_id\\nref Enrollment.course_id many-mandatory -- one-mandatory Course.course_id\",\n \"notes\": \"The university schema is the canonical introduction to associative entities. The M:N relationship between Student and Course is resolved through Enrollment, which carries the relationship attribute `grade`. Both Student and Course join Enrollment via composite primary keys (each FK column doubles as part of the PK).\"\n },\n {\n \"slug\": \"eventtree-flammable-release\",\n \"diagram\": \"eventtree\",\n \"title\": \"Flammable release event tree (process QRA)\",\n \"description\": \"A loss-of-containment release branched through detection, isolation, and ignition. The engine computes each outcome frequency — safe shutdown, jet fire, dispersion, vapour-cloud explosion — and flags the dominant one.\",\n \"standard\": \"IEC 62502 / process QRA\",\n \"tags\": [\n \"eventtree\",\n \"eta\",\n \"qra\",\n \"loss-of-containment\",\n \"ignition\",\n \"explosion\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"eventtree \\\"Flammable release\\\"\\n initiating REL \\\"Loss of containment\\\" freq: 0.02\\n function DET \\\"Gas detection alarms\\\" p: 0.05\\n function ISO \\\"Emergency isolation\\\" p: 0.1\\n function IGN \\\"No ignition source\\\" p: 0.3\\n outcome s s s -> \\\"Safe shutdown\\\"\\n outcome s s f -> \\\"Jet fire\\\"\\n outcome s f * -> \\\"Large dispersion\\\"\\n outcome f * * -> \\\"Vapour cloud explosion\\\"\",\n \"notes\": \"## What this shows\\n\\nThe quantitative risk assessment (QRA) event tree a process-safety study runs after a HAZOP flags a credible leak. The initiating event — a flammable release at `0.02` per year — is challenged by three safety functions in order: gas detection, emergency isolation, and the chance of no ignition source. The `IGN` function reads as a *success* when there is no ignition (`s`), so its failure leg `f` is where the fire or explosion lives.\\n\\nThe value is the computed end-state frequencies. The engine propagates the release frequency through each branch's success/failure probability to size each consequence — safe shutdown, jet fire, large dispersion, vapour-cloud explosion — and accents the dominant sequence in red, the same role the single point of failure plays in a fault tree. That ranked, numeric reading is what turns a forking ladder into an analysis.\"\n },\n {\n \"slug\": \"eventtree-loca\",\n \"diagram\": \"eventtree\",\n \"title\": \"Large LOCA event tree (reactor PRA)\",\n \"description\": \"A large-break loss-of-coolant accident branched through four reactor safety functions. The engine computes every sequence frequency from the initiating rate and per-function failure probabilities, then highlights the dominant accident sequence.\",\n \"standard\": \"IEC 62502 / NUREG (WASH-1400)\",\n \"tags\": [\n \"eventtree\",\n \"eta\",\n \"pra\",\n \"nuclear\",\n \"sequence-frequency\",\n \"core-damage\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"eventtree \\\"Large LOCA\\\"\\n initiating LOCA \\\"Large-break LOCA\\\" freq: 1e-4\\n function RT \\\"Reactor trips\\\" p: 0.001\\n function ECCS \\\"ECCS injection\\\" p: 0.01\\n function CHR \\\"Containment heat removal\\\" p: 0.02\\n function CI \\\"Containment integrity\\\" p: 0.005\\n outcome s s s s -> \\\"OK\\\"\\n outcome s s s f -> \\\"Late release\\\"\\n outcome s s f * -> \\\"Late release\\\"\\n outcome s f * * -> \\\"Early release\\\"\\n outcome f * * * -> \\\"Core damage\\\"\",\n \"notes\": \"## What this shows\\n\\nThe textbook nuclear probabilistic-risk-assessment (PRA) tree. One initiating event — a large pipe break draining the coolant at a frequency of `1e-4` per year — is asked, left to right, whether each safety function holds: reactor trip, emergency core cooling (ECCS), containment heat removal, then containment integrity. Each `*` prunes a path that has already terminated, so the tree stays compact instead of ballooning to a full 2⁴ ladder.\\n\\nThe engine does the arithmetic an event tree exists to give. It multiplies the initiating frequency by the success leg (`1 − p`) or failure leg (`p`) at each branch to get every sequence frequency, sums the two `\\\"Late release\\\"` leaves into one rolled-up outcome, and paints the largest-frequency path — the dominant accident sequence — in red. That computed answer, not the forking picture, is the deliverable a drawing tool can't produce.\"\n },\n {\n \"slug\": \"faulttree-pump-redundancy\",\n \"diagram\": \"faulttree\",\n \"title\": \"Redundant pump failure (AND gate)\",\n \"description\": \"The smallest quantified fault tree — two redundant pumps in an AND gate, so the system fails only if both fail. One minimal cut set, no single point of failure, with a computed top-event probability.\",\n \"standard\": \"NUREG-0492 / IEC 61025\",\n \"tags\": [\n \"faulttree\",\n \"fta\",\n \"reliability\",\n \"and-gate\",\n \"cut-sets\",\n \"probability\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"faulttree \\\"Both pumps fail\\\"\\n analysis: cutsets, probability\\n top T \\\"Both redundant pumps fail\\\" = AND(PA, PB)\\n basic PA \\\"Pump A fails\\\" p: 0.01\\n basic PB \\\"Pump B fails\\\" p: 0.01\",\n \"notes\": \"## What this shows\\n\\nThe canonical reliability argument for redundancy. The top event occurs only when **both** pumps fail, so the gate is an **AND** (drawn as the flat-bottomed dome). The engine computes the one **minimal cut set `{PA, PB}`** (order 2, boxed in red) and — because no single component alone causes the top event — reports **no single point of failure**.\\n\\n**P(top) is computed, not drawn.** With independent basic events, `P(top) ≈ P(PA)·P(PB) = 1.0e-4` (rare-event). Adding a second pump turned two 1-in-100 components into a 1-in-10,000 system — exactly the quantified payoff redundancy is meant to deliver.\"\n },\n {\n \"slug\": \"faulttree-repeated-event\",\n \"diagram\": \"faulttree\",\n \"title\": \"Repeated event with cut-set absorption\",\n \"description\": \"A shared basic event feeds two gates — the case naive fault-tree tools get wrong. MOCUS applies absorption so the supersets collapse, leaving two single points of failure that a shape stencil would miss.\",\n \"standard\": \"NUREG-0492 / MOCUS (Fussell-Vesely 1972)\",\n \"tags\": [\n \"faulttree\",\n \"fta\",\n \"cut-sets\",\n \"repeated-event\",\n \"absorption\",\n \"spof\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"faulttree \\\"Product not removed\\\"\\n analysis: cutsets, probability\\n top T \\\"Failure to remove product\\\" = OR(G1, G2)\\n gate G1 \\\"Arm jams or collides\\\" = AND(MSF, G3)\\n gate G2 \\\"Wrong slot commanded\\\" = OR(CDM, MSF)\\n gate G3 \\\"Loss of position feedback\\\" = OR(ESF, RCF)\\n basic MSF \\\"Manipulator system failure\\\" p: 0.0035\\n basic CDM \\\"Controller command error\\\" p: 0.0009\\n basic ESF \\\"Encoder sensor failure\\\" p: 0.0021\\n basic RCF \\\"Resolver cable fault\\\" p: 0.0012\",\n \"notes\": \"## What this shows\\n\\n`MSF` feeds **both** `G1` and `G2` — a *repeated event*, the DAG case that separates a real engine from a shape stencil. It is drawn once per reference with the shared-event mark, but the cut-set engine treats every instance as the same Boolean variable.\\n\\n**Absorption is the point.** MOCUS first expands the tree to `{MSF, ESF}`, `{MSF, RCF}`, `{MSF}`, `{CDM}`. Because `{MSF}` is itself a cut set (via `G2`), the larger sets `{MSF, ESF}` and `{MSF, RCF}` are *absorbed* — a superset of a cut set is not minimal. The **two minimal cut sets are `{MSF}` and `{CDM}`**, both order-1 **single points of failure** (boxed in the strongest red). A naive expander that forgets absorption would wrongly report four. `P(top) ≈ P(MSF) + P(CDM) = 0.0044`.\"\n },\n {\n \"slug\": \"faulttree-vessel-rupture\",\n \"diagram\": \"faulttree\",\n \"title\": \"Pressure vessel rupture (full vocabulary)\",\n \"description\": \"Voting, inhibit, house and undeveloped events in one tree — a 2-of-2 relief group, an over-pressure inhibited by a heater condition, and an order-3 minimal cut set with the tighter MCUB probability.\",\n \"standard\": \"NUREG-0492 / IEC 61025\",\n \"tags\": [\n \"faulttree\",\n \"fta\",\n \"voting\",\n \"inhibit\",\n \"house-event\",\n \"undeveloped\",\n \"mcub\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"faulttree \\\"Vessel ruptures\\\"\\n analysis: cutsets, probability\\n prob: mcub\\n top TOP \\\"Pressure vessel ruptures\\\" = AND(OVP, RELIEF)\\n gate OVP \\\"Sustained over-pressure\\\" = INHIBIT(PUMP) if HEATER\\n gate RELIEF \\\"Both reliefs fail\\\" = VOTING(2/2; PRV_A, PRV_B)\\n basic PUMP \\\"Pump runaway\\\" p: 0.004\\n basic PRV_A \\\"Relief A stuck\\\" p: 0.02\\n basic PRV_B \\\"Relief B stuck\\\" p: 0.02\\n house HEATER \\\"Heater energised\\\" state: 1\\n undeveloped EXT \\\"External fire (not modelled)\\\"\",\n \"notes\": \"## What this shows\\n\\nThe full NUREG-0492 vocabulary in one tree. **INHIBIT** renders as a hexagon with the `HEATER` conditioning event as an ellipse on its side; because `HEATER` is a **house event** forced to `state: 1`, it is absorbed as a constant TRUE and `OVP` reduces to `{PUMP}`. **VOTING `2/2`** is a redundant relief group that fails only when both valves stick.\\n\\nThe single **minimal cut set is `{PUMP, PRV_A, PRV_B}`** (order 3), and `prob: mcub` reports the minimal-cut-set upper bound — tighter than the rare-event default. `EXT` is an **undeveloped event** (diamond) that is declared but referenced by no gate, so it is noted as unconnected in the diagram description. Switching the heater to `state: 0` would prune the over-pressure branch entirely and make the top event unsatisfiable.\"\n },\n {\n \"slug\": \"faulttree-water-overheating\",\n \"diagram\": \"faulttree\",\n \"title\": \"Water overheating (classic textbook tree)\",\n \"description\": \"The canonical introductory fault tree — an OR top over an AND sub-fault and an OR no-voltage branch, with a probability on every basic event. A faithful, quantified reproduction of the standard worked example.\",\n \"standard\": \"NUREG-0492 / IEC 61025\",\n \"tags\": [\n \"faulttree\",\n \"fta\",\n \"and-or\",\n \"cut-sets\",\n \"probability\",\n \"textbook\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"faulttree \\\"Water overheating\\\"\\n analysis: cutsets, probability\\n top T \\\"Water overheating\\\" = OR(F, E, G)\\n gate F \\\"Circuit failure and no warning lamp\\\" = AND(A, B)\\n gate G \\\"No voltage at input\\\" = OR(C, D)\\n basic E \\\"Booster failure\\\" p: 0.02\\n basic A \\\"Chip failure\\\" p: 0.05\\n basic B \\\"Warning lamp burned\\\" p: 0.03\\n basic C \\\"No burn in network\\\" p: 0.12\\n basic D \\\"Fuse blown\\\" p: 0.23\",\n \"notes\": \"## What this shows\\n\\nThe fault tree every reliability course opens with, rendered with computed cut sets. The top event **OR**s three branches: an **AND** sub-fault `F` (a circuit failure *and* a dead warning lamp must coincide), a direct booster failure `E`, and an **OR** no-voltage branch `G`.\\n\\nThe minimal cut sets mix orders: `{E}`, `{C}`, `{D}` are order-1 **single points of failure** (any one trips the top event), while `{A, B}` is order-2 (both the chip and the lamp must fail together). Each is boxed in red, single points of failure in the strongest red, and the top-event probability is computed from the per-event values — the deductive, quantified reading a fault tree exists to give.\"\n },\n {\n \"slug\": \"fbd-bottle-counter\",\n \"diagram\": \"fbd\",\n \"title\": \"Bottle counter — debounce → edge → count (FBD)\",\n \"description\": \"Three-network FBD pipeline that debounces a bottle sensor with a 50ms TON, takes the rising edge with R_TRIG, counts up to 24 bottles per case with CTU, and self-resets when the case is full. A real production-line pattern that exercises timer + edge-detector + counter + named-instance references in sequence.\",\n \"standard\": \"IEC 61131-3:2013 §6.4 + §2.5\",\n \"tags\": [\n \"fbd\",\n \"plc\",\n \"ton\",\n \"ctu\",\n \"r-trig\",\n \"debounce\",\n \"sensor\",\n \"packaging\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"fbd \\\"Bottle Counter\\\"\\n\\nvar BottleSensor: bool\\nvar BatchDone: bool\\nvar BatchSize: counter\\nvar DwellTimer: timer\\n\\nnetwork 0 \\\"Debounce sensor with 50ms dwell\\\":\\n Dwell = TON(IN: BottleSensor, PT: T#50ms)\\n\\nnetwork 1 \\\"Count one bottle on rising edge of debounced signal\\\":\\n Pulse = R_TRIG(CLK: Dwell.Q)\\n BatchSize = CTU(CU: Pulse.Q, R: BatchDone, PV: 24)\\n\\nnetwork 2 \\\"Latch batch done\\\":\\n BatchDone = MOVE(BatchSize.Q)\",\n \"notes\": \"Counting bottles on a conveyor sounds trivial — the photoelectric sensor goes high when a bottle interrupts the beam, increment the counter, done. In practice it's where most beginner PLC code first goes wrong, because real sensors *bounce*: the beam is broken, then briefly restored as light reflects off the bottle's edge, then broken again. Without debounce, a single bottle can register as three or four counts. This FBD captures the canonical fix in three short networks, and shows how named-instance references chain timers, edge-detectors, and counters into a pipeline.\\n\\n**Network 0 — debounce.** A TON (on-delay timer) ignores the sensor unless it stays high for at least 50ms continuously. `PT: T#50ms` is the IEC duration literal for the preset; it renders as a small yellow constant box at the PT input port. The Q output goes true 50ms after the IN goes true and resets immediately when IN drops — exactly the \\\"is this signal *really* asserted, or just noise?\\\" semantic the line needs.\\n\\n**Network 1 — edge → count.** Two named instances chain together. `Pulse = R_TRIG(CLK: Dwell.Q)` references the debounced output from network 0 by its instance.port name. R_TRIG emits a one-scan pulse on the rising edge — without it, the counter would increment continuously while the sensor is held high (e.g. if the conveyor jammed with a bottle in the beam). `BatchSize = CTU(CU: Pulse.Q, R: BatchDone, PV: 24)` then increments on each pulse, and resets when `BatchDone` goes true. The PV=24 is the case size for a six-pack of four-packs.\\n\\n**Network 2 — feedback latch.** The counter's Q output (true when CV ≥ PV) is moved into the `BatchDone` variable, which feeds back to network 1's reset input. This is one full case cycle: count to 24 → done → reset → start over. As with the motor latch, Schematex doesn't simulate the scan order; it renders the graph. The \\\"feedback\\\" appears in the wire from network 2 back to network 1's CTU.R.\\n\\n**What the data-type colors are telling you.** The TON.IN wire is BOOL (black). The TON.PT wire is TIME (magenta — but it's an inline constant here, so no wire). R_TRIG.CLK is BOOL (black). CTU.CV would be INT (blue) if it were wired anywhere — it's left dangling here because we only need Q. Different wire colors per data type are the TIA Portal de-facto convention, ported over to Schematex for at-a-glance validation: if a REAL wire (orange) lands on a BOOL port, you have a type error in your DSL.\"\n },\n {\n \"slug\": \"fbd-motor-latch\",\n \"diagram\": \"fbd\",\n \"title\": \"Motor start/stop latch (FBD)\",\n \"description\": \"Two-network FBD of the canonical PLC seal-in circuit — start-button rising edge sets a latch, stop and emergency-stop break it. Exercises declared variables, multi-network programs, inline expression notation, and negation bubbles.\",\n \"standard\": \"IEC 61131-3:2013 §6.4 + §2.5\",\n \"tags\": [\n \"fbd\",\n \"plc\",\n \"iec-61131-3\",\n \"latch\",\n \"motor-control\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"fbd \\\"Motor Control\\\"\\n\\nvar Start: bool\\nvar Stop: bool\\nvar EmergencyStop: bool\\nvar MotorOut: bool\\nvar Latch: bool\\n\\nnetwork 0 \\\"Start latch\\\":\\n Latch = OR(Start, AND(Latch, ~Stop, ~EmergencyStop))\\n\\nnetwork 1 \\\"Drive output\\\":\\n MotorOut = MOVE(Latch)\",\n \"notes\": \"The seal-in circuit — also called a start/stop latch — is the most common pattern in PLC code. Once the operator presses Start, the motor stays running even after they release the button, until either Stop or an emergency-stop input goes high. Every controls engineer writes this on day one, and every PLC textbook opens with the ladder version. The FBD form is just as concise but reads like data flow rather than like a relay schematic.\\n\\n**Network 0 — the latch.** `Latch = OR(Start, AND(Latch, ~Stop, ~EmergencyStop))` is the entire seal-in expressed as one nested call. The OR fires when *either* the start button is pressed *or* the latch is already set AND neither stop button is held. The `~` prefix on Stop and EmergencyStop adds a **negation bubble** at each input port — equivalent to inserting a NOT block on that wire, but rendered inline. The variadic AND expands automatically to three inputs because three positional arguments were passed.\\n\\n**The `Latch` feedback edge.** Notice that `Latch` appears on both the left side (as an input to the AND) and the right side (as the output of the OR). This is the *seal-in* feedback that gives the circuit its name. In a real PLC, the previous scan's `Latch` value is what feeds back — the current scan reads it, evaluates the boolean expression, and writes the new value. Schematex doesn't simulate the scan cycle; it just renders the data-flow graph faithfully, which is exactly what an engineer reviewing the program needs to see.\\n\\n**Network 2 — drive output.** `MotorOut = MOVE(Latch)` is a separate concern: take the latch state and assign it to the physical output that energises the motor contactor. Splitting it into its own network is a real engineering practice — it keeps the \\\"logic\\\" (when should the motor be on?) separate from the \\\"actuation\\\" (what physical output gets driven?), so swapping in test harnesses or fault-injection logic only requires modifying network 1, not network 0.\\n\\n**Why this is FBD and not ladder.** Both languages can express this circuit, and many PLC projects mix them. FBD wins when the engineer is thinking in terms of \\\"this signal flows into that operator\\\"; ladder wins when thinking in terms of \\\"this contact closes the path to that coil.\\\" For the seal-in pattern specifically, FBD's three-input AND collapses what ladder requires drawing as three series contacts on one rung — a small win, but a representative one.\"\n },\n {\n \"slug\": \"fbd-tank-setpoint-limiter\",\n \"diagram\": \"fbd\",\n \"title\": \"Tank setpoint limiter + alarm (FBD)\",\n \"description\": \"Two-network FBD that clamps an operator-entered tank-level setpoint to the safe range [0, 95]% via LIMIT, and raises an alarm if the operator types an out-of-range value. Uses LT and GT comparison blocks, the LIMIT selection block, and demonstrates REAL (orange) and BOOL (black) wires carrying different data types in one diagram.\",\n \"standard\": \"IEC 61131-3:2013 §6.4 + §2.5\",\n \"tags\": [\n \"fbd\",\n \"plc\",\n \"comparison\",\n \"limit\",\n \"real\",\n \"hmi\",\n \"operator-input\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"fbd \\\"Tank Level Setpoint Limiter\\\"\\n\\nvar DesiredSetpoint: real\\nvar SafeSetpoint: real\\nvar Alarm: bool\\n\\nnetwork 0 \\\"Clamp setpoint to safe range\\\":\\n SafeSetpoint = LIMIT(MN: 0.0, IN: DesiredSetpoint, MX: 95.0)\\n\\nnetwork 1 \\\"Alarm on out-of-range request\\\":\\n OutOfRange = OR(LT(DesiredSetpoint, 0.0), GT(DesiredSetpoint, 95.0))\\n Alarm = MOVE(OutOfRange.OUT)\",\n \"notes\": \"When an operator types a tank-level setpoint into the HMI, you can't just trust the number. Maybe they meant to type 75 and hit 750. Maybe they typed -5 because they were copying from a spec sheet that used a different reference. Maybe the HMI's input field doesn't have validation and the value is whatever bit-pattern the OPC UA bridge happened to land on. The PLC always validates, and the canonical pattern is: clamp to a safe range, then raise an alarm if the requested value was out of range so a human knows to check.\\n\\n**Network 0 — LIMIT.** `SafeSetpoint = LIMIT(MN: 0.0, IN: DesiredSetpoint, MX: 95.0)` is the clamp. LIMIT takes three REAL inputs and returns a REAL: the value of `IN` if it's in [MN, MX], otherwise MN or MX. Both bounds are inline constants — they render as yellow boxed text at their ports, no wire needed. The downstream control loop reads `SafeSetpoint`, never `DesiredSetpoint` directly. Even if the operator's input is corrupted, the tank can never be commanded outside the physically safe range.\\n\\n**Network 1 — out-of-range alarm.** `OutOfRange = OR(LT(DesiredSetpoint, 0.0), GT(DesiredSetpoint, 95.0))` is an inline expression that nests two comparison blocks inside an OR. LT (less-than) returns BOOL when its first input is less than the second; GT (greater-than) is the opposite. The OR fires when *either* fires — the operator's value was either too low or too high. The `Alarm = MOVE(OutOfRange.OUT)` then drives whatever HMI alarm channel — a red banner, a Slack notification, a SCADA event log entry.\\n\\n**Two data types in one diagram.** Look at the wire colors in the rendered SVG: the wire from `DesiredSetpoint` into LIMIT.IN is REAL (orange — IEEE 754 floating-point); the wires from LT.OUT and GT.OUT into OR are BOOL (black). The LIMIT.OUT is also REAL (orange). One of the FBD engine's small but pleasant features: the renderer infers each wire's type from the source port and colors it accordingly, following the TIA Portal convention. If you accidentally wired an INT to a REAL port the colors would mismatch at the junction and you'd notice immediately.\\n\\n**Why not ladder?** Ladder logic excels at boolean signal routing — contacts in series and parallel feeding into output coils. It has zero affordance for REAL arithmetic and comparison; you'd write the LIMIT expression as a structured-text \\\"function block\\\" call inside a ladder rung, which kills the visual semantic. FBD makes the math first-class. For per-scan combinational logic involving any non-BOOL signal, FBD is what the IEC 61131-3 standard expects you to use.\"\n },\n {\n \"slug\": \"fishbone-manufacturing-defect-6m\",\n \"diagram\": \"fishbone\",\n \"title\": \"Manufacturing defect 6M fishbone\",\n \"description\": \"Ishikawa 6M root-cause analysis for a solder joint defect spike on an electronics assembly line.\",\n \"standard\": \"Ishikawa 1968 / ISO 9001 CAPA\",\n \"tags\": [\n \"fishbone\",\n \"6m\",\n \"manufacturing\",\n \"defect\",\n \"capa\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"Solder Joint Defect Spike\\\"\\nconfig density = spacious\\neffect \\\"3.2% solder joint rejects\\\"\\n\\ncategory man \\\"Man\\\"\\ncategory machine \\\"Machine\\\"\\ncategory material \\\"Material\\\"\\ncategory method \\\"Method\\\"\\ncategory measurement \\\"Measurement\\\"\\ncategory environment \\\"Environment\\\"\\n\\nman : \\\"New operators on night shift\\\"\\n - \\\"Training checklist not signed\\\"\\nman : \\\"Handover notes incomplete\\\"\\n\\nmachine : \\\"Reflow oven zone 4 drift\\\"\\n - \\\"Thermocouple calibration overdue\\\"\\nmachine : \\\"Stencil printer squeegee worn\\\"\\n\\nmaterial : \\\"Solder paste past floor life\\\"\\nmaterial : \\\"PCB pads oxidized after storage\\\"\\n\\nmethod : \\\"Stencil aperture undersized\\\"\\nmethod : \\\"Pick-and-place speed raised\\\"\\n\\nmeasurement : \\\"AOI false accept rate rising\\\"\\nmeasurement : \\\"X-ray sampling reduced\\\"\\n\\nenvironment : \\\"Humidity above process window\\\"\\nenvironment : \\\"ESD straps failing audit\\\"\",\n \"notes\": \"## Scenario\\n\\nAn electronics manufacturer opens a CAPA after solder rejects spike above the control limit. The 6M fishbone forces the team to inspect people, machines, material, method, measurement, and environment before committing to corrective action.\\n\\n## Annotation key\\n\\n- `config density = spacious` gives the dense six-category diagram breathing room.\\n- Indented `-` lines are sub-causes under the preceding cause.\\n- The 6M category names match the manufacturing convention quality teams expect.\"\n },\n {\n \"slug\": \"fishbone-website-traffic\",\n \"diagram\": \"fishbone\",\n \"title\": \"Website traffic drop root-cause analysis\",\n \"description\": \"Ishikawa fishbone for a website traffic drop — six causal categories covering content, technical SEO, backlinks, UX, competition, and algorithm changes.\",\n \"standard\": \"Ishikawa 1968\",\n \"tags\": [\n \"root-cause\",\n \"Ishikawa\",\n \"six-categories\",\n \"growth\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"fishbone \\\"Fishbone diagram — Website traffic drop\\\"\\n\\neffect \\\"Traffic decline\\\"\\n\\ncategory content \\\"Content\\\"\\ncategory tech \\\"Technical\\\"\\ncategory links \\\"Backlinks\\\"\\ncategory ux \\\"UX\\\"\\ncategory competition \\\"Competition\\\"\\ncategory algo \\\"Algorithm\\\"\\n\\ncontent : \\\"Publishing frequency down\\\"\\ncontent : \\\"Content too generic\\\"\\ncontent : \\\"Keyword gaps\\\"\\ncontent : \\\"Low-quality AI content\\\"\\n\\ntech : \\\"Core Web Vitals failing\\\"\\ntech : \\\"Crawl coverage drop\\\"\\ntech : \\\"Crawler blocked by WAF\\\"\\ntech : \\\"Missing structured data\\\"\\n\\nlinks : \\\"High-quality backlinks lost\\\"\\nlinks : \\\"High ratio of low-quality links\\\"\\nlinks : \\\"Referring domain growth stalled\\\"\\nlinks : \\\"Low anchor text diversity\\\"\\n\\nux : \\\"Bounce rate rising\\\"\\nux : \\\"Poor mobile experience\\\"\\nux : \\\"Slow above-fold load\\\"\\nux : \\\"Excessive popup ads\\\"\\n\\ncompetition : \\\"New competitors entering\\\"\\ncompetition : \\\"AI tools replacing search\\\"\\ncompetition : \\\"Weakening brand recall\\\"\\ncompetition : \\\"Competitors publishing faster\\\"\\n\\nalgo : \\\"Core Update penalty\\\"\\nalgo : \\\"Weak E-E-A-T signals\\\"\\nalgo : \\\"AI Overviews / SGE cutoff\\\"\\nalgo : \\\"Search intent drift\\\"\",\n \"notes\": \"## Scenario\\n\\nAn ops lead runs a growth post-mortem after a 30% organic traffic drop. The Ishikawa (fishbone) diagram structures the team's brainstorm into six standard causal categories, preventing the meeting from fixating on the most vocal hypothesis while ignoring systemic causes. The completed diagram becomes the project brief for the remediation sprint.\\n\\n## Annotation key\\n\\n- `effect \\\"...\\\"` — the problem statement, placed at the fish's head (right side)\\n- `category id \\\"Label\\\"` — defines a major causal branch (a \\\"bone\\\"); use a short `id` to assign causes\\n- `id : \\\"cause text\\\"` — assigns a cause string to the named category branch\\n- Each category renders as a diagonal rib pointing toward the effect\\n- Sub-causes (second-order) can be added by nesting if the DSL supports it\\n\\n## How to read\\n\\nThe effect (traffic decline) sits at the right. Six causal ribs branch from the spine: Content, Technical, Backlinks, UX, Competition, and Algorithm. Each rib lists four specific hypotheses. In a workshop, the team votes on each cause, color-codes high-confidence ones, and converts the highest-priority items into action items. The diagram serves as both a brainstorming artifact and a living post-mortem document.\"\n },\n {\n \"slug\": \"flowchart-cicd-pipeline\",\n \"diagram\": \"flowchart\",\n \"title\": \"CI/CD pipeline with gated deploy\",\n \"description\": \"Flowchart of a trunk-based CI/CD pipeline — build, test, security scan, staging gate, and production deploy with automatic rollback on failed smoke tests.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"cicd\",\n \"devops\",\n \"pipeline\",\n \"deployment\",\n \"rollback\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"flowchart TD\\n commit([Push to main]) --> build[Build artifact]\\n build --> unit{Unit tests pass?}\\n unit -->|No| fail([Fail build])\\n unit -->|Yes| scan[Security scan]\\n scan --> vuln{High-severity CVEs?}\\n vuln -->|Yes| fail\\n vuln -->|No| stage[Deploy to staging]\\n stage --> smoke{Smoke tests green?}\\n smoke -->|No| fail\\n smoke -->|Yes| approve{Manual approval?}\\n approve -->|No| wait([Await approver])\\n approve -->|Yes| prod[Deploy to production]\\n prod --> health{Post-deploy health check?}\\n health -->|Yes| done([Release complete])\\n health -->|No| rollback[Automatic rollback]\\n rollback --> done\",\n \"notes\": \"## Scenario\\n\\nA platform engineer is documenting the team's trunk-based pipeline for a new-hire runbook. The diagram makes the four automated gates (tests → scan → smoke → post-deploy health) and the single human gate (manual approval) obvious at a glance, and shows that every failure path terminates the pipeline rather than silently continuing.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; start and terminal nodes\\n- `{…}` — diamond; automated or manual gate\\n- `[…]` — rectangle; build / deploy / scan step\\n- `-->|Yes/No|` — branch labels on each gate\\n\\n## How to read\\n\\nStart at *Push to main*. Every diamond is a gate — a *No* on any of unit tests, CVE scan, or smoke tests terminates at *Fail build*. Manual approval is the only human gate; it can park the pipeline at *Await approver* without failing. The post-deploy health check guards production: a failure triggers automatic rollback, which still completes at *Release complete* because the rollback itself is a successful outcome.\"\n },\n {\n \"slug\": \"flowchart-insurance-claim-adjudication\",\n \"diagram\": \"flowchart\",\n \"title\": \"Insurance claim adjudication\",\n \"description\": \"ISO-style flowchart for a claims team triaging coverage, fraud risk, document completeness, manual review, and payment or denial outcomes.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"flowchart\",\n \"insurance\",\n \"claims\",\n \"adjudication\",\n \"manual-review\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"flowchart LR\\n start([Claim submitted])\\n intake[/Capture FNOL data/]\\n docs{Documents complete?}\\n request[Request missing documents]\\n coverage{Policy active on loss date?}\\n deny1[Issue coverage denial]\\n fraud{Fraud score high?}\\n review[[Manual SIU review]]\\n liability{Liability accepted?}\\n estimate[Calculate covered amount]\\n approve{Adjuster approval?}\\n pay[(Payment ledger)]\\n denial[Send denial letter]\\n close([Close claim])\\n\\n start --> intake\\n intake --> docs\\n docs -->|No| request\\n request -.->|Resubmitted| docs\\n docs -->|Yes| coverage\\n coverage -->|No| deny1\\n deny1 --> close\\n coverage -->|Yes| fraud\\n fraud -->|Yes| review\\n review --> liability\\n fraud -->|No| liability\\n liability -->|No| denial\\n denial --> close\\n liability -->|Yes| estimate\\n estimate --> approve\\n approve -->|Needs changes| estimate\\n approve -->|Approved| pay\\n pay --> close\",\n \"notes\": \"## Scenario\\n\\nClaim adjudication is not a straight line. The same claim can bounce for missing documents, route to special investigation, return for estimate changes, or close through denial. A flowchart is appropriate here because the core question is operational routing, not ownership lanes or event semantics.\\n\\n## Annotation key\\n\\n- Parallelogram `[/.../]` marks intake data capture.\\n- `[[...]]` marks a predefined manual review subprocess.\\n- Dotted retry edge shows a resubmission loop without making it the main path.\"\n },\n {\n \"slug\": \"flowchart-order-fulfillment\",\n \"diagram\": \"flowchart\",\n \"title\": \"E-commerce order fulfillment\",\n \"description\": \"Flowchart mapping the full order-to-delivery path with inventory and payment decision gates, exception handling, and a single End terminal.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"process\",\n \"decision\",\n \"e-commerce\",\n \"operations\",\n \"exception-handling\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"flowchart LR\\n start([New order received])\\n start --> validate{Inventory available?}\\n validate -->|Yes| reserve[Reserve items]\\n validate -->|No| notify[Notify customer]\\n notify --> done([End])\\n reserve --> payment{Payment authorized?}\\n payment -->|Yes| ship[Ship order]\\n payment -->|No| cancel[Cancel & release]\\n ship --> confirm[Send confirmation email]\\n confirm --> done\\n cancel --> done\",\n \"notes\": \"## Scenario\\n\\nA product ops lead circulates this flowchart during an ops-review meeting to align engineering, customer support, and fulfillment on the single source of truth for what happens when a new order comes in. It surfaces the two decision gates (inventory, payment) and the three exception paths (out-of-stock notification, payment failure with released hold, successful ship with confirmation).\\n\\n## Annotation key\\n\\n- `([…])` — stadium / terminal; used for Start and End\\n- `{…}` — diamond; decision node\\n- `[…]` — rectangle; process step\\n- `-->|label|` — edge with a branch label (`Yes` / `No`)\\n\\n## How to read\\n\\nStart at the top-left terminal. Inventory check gates the first branch — a \\\"No\\\" routes straight to the End after notification. A \\\"Yes\\\" reserves stock then hits the payment gate. Payment failure releases the reservation and goes to End; success ships and emails the customer. Every path terminates at the same End node, so nothing dangles.\"\n },\n {\n \"slug\": \"fmea-ev-battery-dfmea\",\n \"diagram\": \"fmea\",\n \"title\": \"EV battery pack DFMEA\",\n \"description\": \"A design FMEA for an electric-vehicle battery pack. The engine flattens the failure chain, computes RPN = S × O × D, and derives the AIAG-VDA Action Priority — keeping a S10 safety failure High even when its RPN looks low.\",\n \"standard\": \"AIAG-VDA FMEA Handbook (2019) / IEC 60812\",\n \"tags\": [\n \"fmea\",\n \"dfmea\",\n \"rpn\",\n \"action-priority\",\n \"severity\",\n \"automotive\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"fmea \\\"EV battery pack DFMEA\\\"\\n type: design\\n rank: ap\\n flag: ap >= High\\n number: DFMEA-2026-014\\n item \\\"Cell module\\\" fn \\\"Store and deliver energy\\\"\\n mode \\\"Thermal runaway\\\"\\n effect \\\"Pack fire / occupant injury\\\" sev: 10\\n cause \\\"Internal short from dendrite growth\\\" occ: 3\\n controls prevention: \\\"Cell qualification\\\", detection: \\\"In-line CT scan\\\" det: 4\\n cause \\\"Overcharge past cutoff\\\" occ: 2\\n controls prevention: \\\"BMS voltage clamp\\\", detection: \\\"Redundant voltage sense\\\" det: 3\\n mode \\\"Capacity fade\\\"\\n effect \\\"Reduced range\\\" sev: 6\\n cause \\\"Electrolyte depletion\\\" occ: 5\\n controls detection: \\\"Periodic SOH estimate\\\" det: 6\\n item \\\"Busbar joint\\\" fn \\\"Conduct current between modules\\\"\\n mode \\\"High-resistance connection\\\"\\n effect \\\"Local overheating\\\" sev: 8\\n cause \\\"Loose torque on weld\\\" occ: 4\\n controls detection: \\\"End-of-line resistance test\\\" det: 4\",\n \"notes\": \"## What this shows\\n\\nA design FMEA (DFMEA) on the highest-stakes subsystem in an electric vehicle. The nested chain reads item → mode → effect/cause/controls: a cell module that can suffer thermal runaway or capacity fade, and a busbar joint that can go high-resistance. Each effect carries a Severity, each cause an Occurrence, each control the Detection it earns — the three AIAG-VDA 1–10 scales.\\n\\nThe engine computes the priority rather than just tabling it. It flattens to one worksheet row per (item, mode, cause), multiplies RPN = S × O × D, and — the part that matters — derives the AIAG-VDA Action Priority, which is severity-primary. The thermal-runaway row sits at S10·O3·D4 with an RPN of 120; a naive RPN sort would rank it below a noisier low-severity defect, but Action Priority keeps every safety failure (S = 9–10) at **High** regardless. The `flag: ap >= High` directive highlights exactly those rows so the safety-critical work rises to the top.\"\n },\n {\n \"slug\": \"fmea-injection-molding-pfmea\",\n \"diagram\": \"fmea\",\n \"title\": \"Injection-moulding PFMEA\",\n \"description\": \"A process FMEA for an injection-moulding line, ranked the legacy way by RPN. The engine computes RPN = S × O × D for every (step, mode, cause) row and flags the ones that breach the 100 threshold.\",\n \"standard\": \"AIAG-VDA FMEA Handbook (2019) / IEC 60812\",\n \"tags\": [\n \"fmea\",\n \"pfmea\",\n \"rpn\",\n \"process\",\n \"manufacturing\",\n \"scrap\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"fmea \\\"Injection moulding PFMEA\\\"\\n type: process\\n rank: rpn\\n flag: rpn > 100\\n item \\\"Mould fill step\\\" fn \\\"Fill cavity with melt\\\"\\n mode \\\"Short shot\\\"\\n effect \\\"Incomplete part scrapped\\\" sev: 7\\n cause \\\"Injection pressure too low\\\" occ: 5\\n controls prevention: \\\"Pressure setpoint lock\\\", detection: \\\"Vision check\\\" det: 4\\n cause \\\"Blocked gate\\\" occ: 3\\n controls detection: \\\"Cycle-time monitor\\\" det: 6\\n item \\\"Cooling step\\\" fn \\\"Solidify part to spec\\\"\\n mode \\\"Warpage\\\"\\n effect \\\"Out-of-tolerance dimension\\\" sev: 6\\n cause \\\"Uneven cooling channel flow\\\" occ: 6\\n controls detection: \\\"CMM sampling\\\" det: 7\",\n \"notes\": \"## What this shows\\n\\nA process FMEA (PFMEA) following the steps of an injection-moulding line — the fill step and the cooling step — rather than the parts of a product. Each process step gets its failure modes (short shot, warpage), the effect each has on the part, the process causes behind it, and the in-line controls that prevent or detect it.\\n\\nThis worksheet is ranked the legacy way with `rank: rpn`, so the engine sorts purely on RPN = S × O × D and the `flag: rpn > 100` directive lights up every row above 100 — here the uneven-cooling warpage row at S6·O6·D7 (RPN 252) and the short-shot pressure row at S7·O5·D4 (RPN 140). Each rendered row carries `data-rpn` and `data-ap`, so even on a legacy RPN worksheet the AIAG-VDA Action Priority is still computed and inspectable underneath.\"\n },\n {\n \"slug\": \"genogram-brca-cancer\",\n \"diagram\": \"genogram\",\n \"title\": \"Hereditary cancer (BRCA1) family\",\n \"description\": \"Three-generation BRCA1 family genogram with hereditary breast/ovarian cancer conditions — captured at intake before formal clinical pedigree analysis.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"hereditary-cancer\",\n \"four-generation\",\n \"deceased\",\n \"BRCA\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"genogram \\\"BRCA1 Family\\\"\\n I_1 [male, 1930, 1995, deceased]\\n I_2 [female, 1932, 1990, deceased, conditions: ovarian_cancer(full, #B388FF)]\\n I_1 -- I_2\\n II_1 [female, 1955, conditions: breast_cancer(full, #EC407A)]\\n II_2 [male, 1958]\\n II_3 [female, 1960]\\n II_1 -- II_4 [male, 1954]\\n III_1 [female, 1985, index, conditions: breast_cancer(full, #EC407A)]\\n III_2 [male, 1988]\",\n \"notes\": \"## Scenario\\n\\nA family history genogram for hereditary breast/ovarian cancer, documented at the initial genetic counseling intake before formal pedigree analysis. For standardized clinical pedigree notation (NSGC), use the Pedigree diagram type instead.\\n\\n## Annotation key\\n\\n- `conditions: ovarian_cancer(full)` / `conditions: breast_cancer(full)` — medical conditions filling the symbol; color is optional hex\\n- `deceased` with birth and death years — marks individuals with a slash and date range\\n- `index` — marks the proband who triggered the clinical referral\\n\\n## How to read\\n\\nThe maternal grandmother (I_2) had ovarian cancer and is deceased. Her daughter (II_1) developed breast cancer. The proband (III_1, index) is a third-generation female with breast cancer — the inheritance pattern spanning three generations justifies BRCA genetic testing.\"\n },\n {\n \"slug\": \"genogram-foster-care\",\n \"diagram\": \"genogram\",\n \"title\": \"Foster care / child protection\",\n \"description\": \"Foster-care genogram for a real LATAM child-protection case — biological parents (cohabitation ended), abuse, current foster placement (dotted secondary link), unknown-count siblings, and a maternal uncle as known-relative-with-unknown-ancestry.\",\n \"standard\": \"McGoldrick 2020 + Bennett 2022 (adopted-out / dual-parent convention)\",\n \"tags\": [\n \"foster-care\",\n \"dual-parent\",\n \"abuse\",\n \"sibling-of\",\n \"unknown-siblings\",\n \"latam\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"genogram \\\"Familia Isaías\\\"\\n victor [male, label: \\\"Víctor Seguel\\\"]\\n monica [female, label: \\\"Mónica Barrientos\\\"]\\n victor ~/~ monica\\n ?\\n isaias [male, 2020, age: 6, label: \\\"Isaías\\\", index]\\n pablo_sr [male, label: \\\"Don Pablo\\\"]\\n priscila [female, label: \\\"Doña Priscila\\\"]\\n pablo_sr -- priscila\\n pablo_jr [male, label: \\\"Pablo (jr)\\\"]\\n alanis [female, label: \\\"Alanis\\\"]\\n isaias [foster]\\n tio_materno [male, label: \\\"Tío materno\\\", sibling-of: monica]\\n victor -physical-abuse-> isaias\\n monica -physical-abuse-> isaias\\n tio_materno -nevermet- isaias\",\n \"notes\": \"## Scenario\\n\\nA foster-care social worker in Chile is preparing the case file for Isaías, a 6-year-old boy removed from his biological parents (Víctor and Mónica) due to physical abuse from both. He currently lives with foster parents Don Pablo and Doña Priscila, who have two biological children of their own. The case file mentions Isaías has siblings whose names and ages are unknown, and a maternal uncle who is a potential reunification resource but currently has no contact.\\n\\nA judge or psychologist receiving this diagram must, at a glance, correctly conclude:\\n\\n1. Isaías is the **biological son** of Víctor and Mónica — solid parent-child line down from the bio couple.\\n2. He **currently lives** with Don Pablo and Doña Priscila as a foster child — *secondary dotted link* from the foster couple, drawn without pulling Isaías away from his bio-parent position.\\n3. He was **removed due to physical abuse** from both bio parents — directional red zigzag arrows.\\n4. The **maternal uncle** is Mónica's brother (`sibling-of: monica`) with **no current relationship** to Isaías — dashed bracket between Mónica and Tío + `nevermet` line.\\n5. Isaías has **unknown-count siblings** still with the bio parents — single `?` diamond placeholder.\\n6. **Isaías is the index person** — concentric outer border highlight.\\n\\n## Annotation key\\n\\n- `~/~` — cohabitation ended (never-married); standard for LATAM caseloads where bio parents lived together unmarried and the relationship has broken. Distinct from `-x-` divorce (no marriage) and `-/-` separation (still married).\\n- Re-declaring `isaias [foster]` under the foster couple after declaring him under the bio couple → engine treats the second declaration as a **secondary \\\"current caregiver\\\" link** (dotted), preserving all attributes from the first declaration.\\n- `?` on a child line → a single diamond with `?` glyph meaning \\\"≥1 siblings, count and identities unknown\\\" (standard pedigree convention).\\n- `[sibling-of: monica]` → places Tío materno on Mónica's generation with a dashed bracket between them, **without** synthesizing phantom maternal grandparents.\\n- `-physical-abuse->` → directional red arrow; the `>` indicates the perpetrator (left side) and victim (right side).\\n\\n## Why this matters\\n\\nA genogram engine that quietly rendered Isaías as a third biological child of Don Pablo + Doña Priscila — or dropped his sex and label when the `[foster]` redeclaration overwrote the original — would invert the case story. This example exercises every fix from the 2026-04 foster-care brief: dual-parent rendering, same-id merge, sibling-of, cohabiting-ended, and the unknown-siblings placeholder.\"\n },\n {\n \"slug\": \"genogram-medical-history\",\n \"diagram\": \"genogram\",\n \"title\": \"Multi-generation medical history\",\n \"description\": \"Three-generation family medical history genogram with multi-condition color annotations using fill zones — heart disease, diabetes, cancer, hypertension.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"conditions\",\n \"multicolor\",\n \"three-generation\",\n \"inheritance\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"genogram \\\"Medical History\\\"\\n grandfather [male, 1930, 1990, deceased, conditions: heart-disease(full, #e74c3c) + diabetes(half-left, #ff9800)]\\n grandmother [female, 1935, conditions: cancer(half-right, #9c27b0)]\\n grandfather -- grandmother\\n father [male, 1960, conditions: heart-disease(quad-tl, #e74c3c) + hypertension(quad-tr, #2196f3)]\\n uncle [male, 1963, conditions: diabetes(full, #ff9800)]\\n mother [female, 1962]\\n father -- mother\\n patient [male, 1988, index, conditions: hypertension(half-left, #2196f3)]\\n sister [female, 1991]\",\n \"notes\": \"## Scenario\\n\\nA clinical social worker or genetic counselor captures three generations of family medical history at intake. The `conditions()` annotation lets each person carry multiple diagnoses simultaneously — and the fill geometry (full, half, quadrant) encodes severity or inheritance proportion at a glance, without cluttering the diagram with text labels.\\n\\n## Annotation key\\n\\n- `conditions: X(fill, color)` — paints a shape inside the genogram symbol using the named fill zone and hex color\\n- `full` — entire symbol filled; indicates fully affected\\n- `half-left` / `half-right` — left or right half filled; often used for one of two conditions side-by-side\\n- `quad-tl` / `quad-tr` — top-left or top-right quadrant; allows up to four distinct conditions per person\\n- `+ diabetes(...)` — chain multiple conditions on the same person with `+`\\n- `deceased` — draws a diagonal slash through the symbol\\n- `index` — marks the proband with an arrow\\n\\n## How to read\\n\\nThe grandfather's full red fill (heart disease) and half-orange fill (diabetes) are visually inherited by the father, who carries both — encoded as top-left and top-right quadrant fills. The patient (index) shows only hypertension in the left half, indicating partial inheritance. Tracing any color across generations immediately reveals the inheritance chain.\"\n },\n {\n \"slug\": \"genogram-nuclear-family\",\n \"diagram\": \"genogram\",\n \"title\": \"Nuclear family (minimal template)\",\n \"description\": \"Minimal nuclear family genogram — married couple, one child, marriage date — the clinical intake starting template per McGoldrick 2020 notation.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"starter\",\n \"minimal\",\n \"marriage-date\",\n \"index\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"genogram \\\"Smith Family\\\"\\n john [male, 1975]\\n mary [female, 1977]\\n john -- mary \\\"m. 2002\\\"\\n alice [female, 2005, index]\",\n \"notes\": \"## Scenario\\n\\nThe simplest genogram that is clinically useful — a married couple with one child. Used as a session intake template and as the starting point when teaching genogram notation to new practitioners.\\n\\n## Annotation key\\n\\n- `--` — standard marriage/union line\\n- `\\\"m. 2002\\\"` — marriage year label\\n- `index` — marks Alice as the identified patient\\n\\n## How to read\\n\\nTwo parents connected by a union line with a marriage date; their child Alice (marked as the index person) hangs below. Extend this template by adding siblings, grandparents, or emotional relationship lines.\"\n },\n {\n \"slug\": \"genogram-potter-family\",\n \"diagram\": \"genogram\",\n \"title\": \"The Potter family\",\n \"description\": \"Three-generation Potter family genogram with emotional relationship lines — cutoff, hostile, and close — illustrating McGoldrick relational notation.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"emotional-relationships\",\n \"three-generation\",\n \"deceased\",\n \"cutoff\",\n \"hostile\",\n \"close\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"genogram \\\"The Potter Family\\\"\\n fleamont [male, 1909, 1979, deceased]\\n euphemia [female, 1920, 1979, deceased]\\n fleamont -- euphemia\\n james [male, 1960, 1981, deceased]\\n mr_evans [male, 1925, deceased]\\n mrs_evans [female, 1928, deceased]\\n mr_evans -- mrs_evans\\n lily [female, 1960, 1981, deceased]\\n petunia [female, 1958]\\n james -- lily \\\"m. 1978\\\"\\n harry [male, 1980, index]\\n petunia -- vernon [male, 1951]\\n dudley [male, 1980]\\n harry -cutoff- petunia\\n harry -hostile- dudley\\n harry -close- lily\",\n \"notes\": \"## Scenario\\n\\nA teaching example for social work students learning genogram notation. The Potter family is fictional but emotionally rich — death years, a marriage date, cross-family emotional relationships, and three distinct relational patterns (cutoff, hostile, close) all in one diagram.\\n\\n## Annotation key\\n\\n- `[male/female, birth_year, death_year, deceased]` — person with death marker\\n- `\\\"m. 1978\\\"` — marriage date label on the union line\\n- `index` — marks Harry as the identified patient (proband)\\n- `-cutoff-` — estrangement; drawn as two parallel bars across the relationship line\\n- `-hostile-` — conflict; drawn as zigzag line\\n- `-close-` — enmeshment/closeness; drawn as double parallel line\\n\\n## How to read\\n\\nRead each indented block as a family unit. James and Lily (index generation) both died in 1981. Harry's emotional world is defined by three relational lines: cutoff from Aunt Petunia, hostility toward cousin Dudley, and closeness to his deceased mother.\"\n },\n {\n \"slug\": \"gitgraph-release-flow\",\n \"diagram\": \"gitgraph\",\n \"title\": \"Git Flow release history\",\n \"description\": \"A realistic Git Flow branch/merge/tag history — develop, a feature branch, a tagged release, and a hotfix merged back to both lines. Mermaid gitGraph syntax, rendered through Schematex's zero-dependency engine.\",\n \"standard\": \"Mermaid gitGraph dialect\",\n \"tags\": [\n \"gitgraph\",\n \"git-flow\",\n \"branch\",\n \"merge\",\n \"tag\",\n \"hotfix\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"gitGraph\\n commit id: \\\"init\\\"\\n commit id: \\\"scaffold\\\"\\n branch develop\\n checkout develop\\n commit id: \\\"feature scaffold\\\"\\n branch feature/login\\n checkout feature/login\\n commit id: \\\"login UI\\\"\\n commit id: \\\"login API\\\"\\n checkout develop\\n merge feature/login\\n commit id: \\\"polish\\\"\\n checkout main\\n merge develop tag: \\\"v1.0\\\"\\n branch hotfix\\n checkout hotfix\\n commit id: \\\"patch CVE\\\" type: HIGHLIGHT\\n checkout main\\n merge hotfix tag: \\\"v1.0.1\\\"\\n checkout develop\\n merge main\",\n \"notes\": \"## What this shows\\n\\nA full Git Flow release cycle, the branching strategy teams adopt to keep a clean trunk. Work forks off `main` into a long-lived `develop`, then into a short-lived `feature/login` branch; the feature merges back to develop, develop merges to `main` as the tagged `v1.0` release. Then a security `hotfix` branches straight off `main`, lands a HIGHLIGHT commit, ships as `v1.0.1`, and is merged back down into develop so the fix isn't lost — the discipline that keeps the two lines from diverging.\\n\\nThe DSL is the Mermaid `gitGraph` dialect verbatim, so existing Mermaid sources port directly. The engine replays the operation list in order to assign each commit to a lane, routes the merge connectors from each branch tip without crossings, renders the patch commit emphasised as a HIGHLIGHT, and draws the version tags as flags — all from a KB-scale, dependency-free bundle.\"\n },\n {\n \"slug\": \"idef0-order-fulfilment\",\n \"diagram\": \"idef0\",\n \"title\": \"IDEF0 A0 — fulfil customer order\",\n \"description\": \"An IDEF0 A0 function decomposition with all four ICOM arrow types. Inputs, controls, mechanisms and outputs each pin to a fixed box edge, so the model is correct by construction per FIPS PUB 183.\",\n \"standard\": \"FIPS PUB 183 (IDEF0)\",\n \"tags\": [\n \"idef0\",\n \"icom\",\n \"function-model\",\n \"decomposition\",\n \"fips-183\",\n \"structured-analysis\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"idef0 \\\"Fulfil customer order\\\"\\nnode A0\\nfunction A1 \\\"Validate order\\\"\\nfunction A2 \\\"Pick and pack\\\"\\nfunction A3 \\\"Ship and invoice\\\"\\ninput A1 \\\"Customer order\\\"\\ncontrol A1 \\\"Credit policy\\\"\\nmechanism A1 \\\"Order management system\\\"\\nA1 -> A2 \\\"Validated order\\\"\\ninput A2 \\\"Inventory\\\"\\ncontrol A2 \\\"Picking rules\\\"\\nmechanism A2 \\\"Warehouse staff\\\"\\nA2 -> A3 \\\"Packed shipment\\\"\\ncontrol A3 \\\"Carrier contract\\\"\\nmechanism A3 \\\"Shipping carrier\\\"\\noutput A3 \\\"Delivered order\\\"\\noutput A3 \\\"Invoice\\\"\",\n \"notes\": \"## What this shows\\n\\nAn IDEF0 A0 diagram — the top-level functional decomposition of an order-fulfilment system — showing all four ICOM arrow roles. Reading the box edges by convention: **I**nputs enter on the left (the customer order, inventory), **C**ontrols govern from the top (credit policy, picking rules, carrier contract), **M**echanisms supply resources from the bottom (the order system, warehouse staff, carrier), and **O**utputs leave on the right (delivered order, invoice). The box-to-box flows (`A1 -> A2 \\\"Validated order\\\"`) chain the three activities.\\n\\nThe differentiator is that the model is correct by construction, not just drawn. Because the arrow keyword *is* the box edge it attaches to, the engine enforces ICOM placement — you cannot accidentally draw a control as an input. It resolves every box reference, assigns decomposition numbers (A0 → A1..A3), codes the boundary arrows down each edge (I1/C1/O1/M1…), and applies the FIPS 3-to-6-box guideline. A flow that tried to *enter* a box via its `.output` edge would be rejected, because an output leaves a box — the standard is enforced, not suggested.\"\n },\n {\n \"slug\": \"ladder-conveyor-interlock\",\n \"diagram\": \"ladder\",\n \"title\": \"Conveyor interlock chain\",\n \"description\": \"Three-rung ladder logic for a downstream-first conveyor start sequence with jam permissives and an alarm latch.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"conveyor\",\n \"interlock\",\n \"permissive\",\n \"alarm\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Conveyor Interlock Chain\\\"\\n\\nrung 1 \\\"Run downstream conveyor first\\\":\\n XIC(AUTO_MODE, \\\"BIT 1.0\\\", name=\\\"Auto mode\\\")\\n XIO(ESTOP_OK, \\\"BIT 1.1\\\", name=\\\"E-stop not tripped\\\")\\n XIO(CV2_JAM, \\\"IN 2.2\\\", name=\\\"Downstream jam clear\\\")\\n OTE(CV2_RUN, \\\"OUT 4.1\\\", name=\\\"Conveyor 2 run\\\")\\n\\nrung 2 \\\"Start upstream only when downstream is running\\\":\\n XIC(AUTO_MODE, \\\"BIT 1.0\\\", name=\\\"Auto mode\\\")\\n XIC(CV2_RUN, \\\"OUT 4.1\\\", name=\\\"CV2 running\\\")\\n XIO(CV1_JAM, \\\"IN 2.1\\\", name=\\\"Upstream jam clear\\\")\\n OTE(CV1_RUN, \\\"OUT 4.0\\\", name=\\\"Conveyor 1 run\\\")\\n\\nrung 3 \\\"Latch jam alarm\\\":\\n parallel:\\n branch:\\n XIC(CV1_JAM, \\\"IN 2.1\\\", name=\\\"CV1 jam\\\")\\n branch:\\n XIC(CV2_JAM, \\\"IN 2.2\\\", name=\\\"CV2 jam\\\")\\n OTL(JAM_ALARM, \\\"BIT 3.0\\\", name=\\\"Jam alarm\\\")\",\n \"notes\": \"## Scenario\\n\\nConveyors are started downstream-first so a running upstream belt never feeds material into a stopped downstream belt. This example shows the interlock directly in the rungs: conveyor 1 cannot run until conveyor 2 is already commanded on.\\n\\n## Annotation key\\n\\n- `XIC(CV2_RUN)` is the downstream permissive on the upstream conveyor rung.\\n- `XIO(CV1_JAM)` and `XIO(CV2_JAM)` block the run command when a jam bit is true.\\n- `OTL(JAM_ALARM)` latches the alarm so it remains visible after the jam sensor clears.\"\n },\n {\n \"slug\": \"ladder-mode-selection\",\n \"diagram\": \"ladder\",\n \"title\": \"System mode selection (Set/Reset)\",\n \"description\": \"IEC 61131-3 ladder logic for HMI-driven Auto/Manual mode selection using Set/Reset (OTL/OTU) coils with system fault interlocks.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"OTL\",\n \"OTU\",\n \"Set-Reset\",\n \"parallel-outputs\",\n \"interlocks\",\n \"Allen-Bradley\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"ladder \\\"System Mode Selection\\\"\\n\\nrung 1 \\\"Set system Auto mode, reset Manual\\\":\\n XIC(AUTO_HMIPB, \\\"BIT 5.10\\\", name=\\\"Auto Mode HMI Pushbutton\\\")\\n XIO(MANL_HMIPB, \\\"BIT 5.11\\\", name=\\\"Manual Mode HMI Pushbutton\\\")\\n XIO(SYS_FAULT, \\\"BIT 3.0\\\", name=\\\"System Fault\\\")\\n parallel:\\n branch:\\n OTL(SYS_AUTO, \\\"BIT 3.1\\\", name=\\\"System Auto Mode\\\")\\n branch:\\n OTU(SYS_MANUAL, \\\"BIT 3.2\\\", name=\\\"System Manual Mode\\\")\\n\\nrung 2 \\\"Set Manual, reset Auto (with Home seal-in)\\\":\\n parallel:\\n branch:\\n XIC(MANL_HMIPB, \\\"BIT 5.11\\\", name=\\\"Manual Mode HMI Pushbutton\\\")\\n branch:\\n XIC(SYS_HOMECMD, \\\"BIT 3.5\\\", name=\\\"System Home Command\\\")\\n XIO(AUTO_HMIPB, \\\"BIT 5.10\\\", name=\\\"Auto Mode HMI Pushbutton\\\")\\n XIO(SYS_FAULT, \\\"BIT 3.0\\\", name=\\\"System Fault\\\")\\n parallel:\\n branch:\\n OTL(SYS_MANUAL, \\\"BIT 3.2\\\", name=\\\"System Manual Mode\\\")\\n branch:\\n OTU(SYS_AUTO, \\\"BIT 3.1\\\", name=\\\"System Auto Mode\\\")\",\n \"notes\": \"## Scenario\\n\\nAn Allen-Bradley PLC program for a machine that requires mutually exclusive Auto and Manual operating modes, with a Home command that can trigger a manual mode entry as a safety fallback. The latched Set/Reset coil pattern is standard for retained-state mode selection that survives a power cycle.\\n\\n## Annotation key\\n\\n- `OTL(tag, addr, name=...)` — Output Latch (Set): energizes and *latches* the bit high; bit stays high even when the rung loses power\\n- `OTU(tag, addr, name=...)` — Output Unlatch (Reset): clears a latched bit back to 0\\n- `parallel: branch:` — output-side parallel branches execute simultaneously when the rung is true\\n- Rung 1 sets Auto and simultaneously resets Manual; Rung 2 does the inverse\\n- The `SYS_FAULT` XIO contact appears in both rungs as a master interlock — no mode change is allowed during a fault\\n\\n## How to read\\n\\nRung 1 fires when the operator presses the Auto HMI button AND Manual is not pressed AND no fault exists. It simultaneously latches `SYS_AUTO` ON and unlatches `SYS_MANUAL`. Rung 2 is the mirror: Manual button OR Home command, guarded by Auto-not-pressed and no-fault, sets Manual and resets Auto. The latched coils mean the last-pressed mode persists through PLC power cycles.\"\n },\n {\n \"slug\": \"ladder-motor-start-stop\",\n \"diagram\": \"ladder\",\n \"title\": \"Motor start/stop seal-in circuit\",\n \"description\": \"Classic three-wire motor start/stop seal-in circuit in IEC 61131-3 ladder logic — the foundational pattern taught in every PLC certification course.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"seal-in\",\n \"motor\",\n \"XIC\",\n \"XIO\",\n \"OTE\",\n \"parallel\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"ladder \\\"Motor Start/Stop\\\"\\nrung 1 \\\"Seal-in circuit\\\":\\n parallel:\\n branch:\\n XIC(START_PB, \\\"IN 1.0\\\", name=\\\"Start Button\\\")\\n branch:\\n XIC(MOTOR_AUX, \\\"BIT 3.0\\\", name=\\\"Aux Contact\\\")\\n XIO(STOP_PB, \\\"IN 1.1\\\", name=\\\"Stop Button\\\")\\n OTE(MOTOR_CMD, \\\"OUT 2.0\\\", name=\\\"Motor Command\\\")\",\n \"notes\": \"## Scenario\\n\\nEvery controls engineer learns the three-wire motor start/stop circuit before writing their first PLC program. It appears verbatim in IEC 61131-3 training materials, Allen-Bradley certification exams, and factory acceptance tests worldwide. The seal-in contact latches the motor ON after the momentary start pushbutton is released — the fundamental pattern for any maintained-output logic.\\n\\n## Annotation key\\n\\n- `XIC(tag, address, name=...)` — Examine If Closed: contact passes power when the referenced bit is `1` (true)\\n- `XIO(tag, address, name=...)` — Examine If Open: contact passes power when the referenced bit is `0` (false); normal for stop buttons wired N.C.\\n- `OTE(tag, address, name=...)` — Output Energize: coil energizes the referenced bit when rung has power\\n- `parallel: branch:` — models a parallel contact branch (logical OR)\\n- The `MOTOR_AUX` contact in the parallel branch is the seal-in: once the motor output energizes, the aux contact closes and holds the rung true even after the START_PB releases\\n\\n## How to read\\n\\nThe rung reads left to right. Power flows if *either* the start button (XIC START_PB) *or* the aux contact (XIC MOTOR_AUX) is closed, *and* the stop button (XIO STOP_PB) is not pressed. When the output coil (OTE MOTOR_CMD) energizes the motor, it also drives the aux contact bit — latching the rung high. Pressing STOP breaks the series path and de-energizes the rung, dropping the motor and the seal-in simultaneously.\"\n },\n {\n \"slug\": \"ladder-tank-level-pump-control\",\n \"diagram\": \"ladder\",\n \"title\": \"Tank level pump control\",\n \"description\": \"Pump control ladder with low-level start, high-level stop, seal-in logic, and a run-delay timer.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"pump\",\n \"tank\",\n \"timer\",\n \"seal-in\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Tank Level Pump Control\\\"\\n\\nrung 1 \\\"Fill pump seal-in\\\":\\n parallel:\\n branch:\\n XIC(LOW_LEVEL, \\\"IN 1.0\\\", name=\\\"Low level\\\")\\n branch:\\n XIC(PUMP_RUN, \\\"OUT 2.0\\\", name=\\\"Pump running\\\")\\n XIO(HIGH_LEVEL, \\\"IN 1.1\\\", name=\\\"High level\\\")\\n XIO(FAULT, \\\"BIT 3.0\\\", name=\\\"Fault clear\\\")\\n OTE(PUMP_RUN, \\\"OUT 2.0\\\", name=\\\"Fill pump\\\")\\n\\nrung 2 \\\"Run delay proves flow\\\":\\n XIC(PUMP_RUN, \\\"OUT 2.0\\\", name=\\\"Pump running\\\")\\n TON(FLOW_DELAY, IN=PUMP_RUN, PT=5000, name=\\\"Flow prove delay\\\")\\n\\nrung 3 \\\"No-flow alarm after delay\\\":\\n XIC(FLOW_DELAY, \\\"TMR 1.0\\\", name=\\\"Delay done\\\")\\n XIO(FLOW_OK, \\\"IN 1.2\\\", name=\\\"Flow switch\\\")\\n OTL(FLOW_ALARM, \\\"BIT 3.1\\\", name=\\\"No flow alarm\\\")\",\n \"notes\": \"## Scenario\\n\\nA fill pump starts when the tank reaches low level, stays on through a seal-in path, and stops at the high-level switch. A timer allows a few seconds for the flow switch to prove flow before latching an alarm.\\n\\n## Annotation key\\n\\n- The `parallel:` block is the seal-in path.\\n- `TON` is the on-delay timer used as a permissive before declaring no-flow.\\n- `OTL` latches the alarm so an operator must acknowledge the failure.\"\n },\n {\n \"slug\": \"logic-ansi-vs-iec-gate-gallery\",\n \"diagram\": \"logic\",\n \"title\": \"IEC logic gate gallery\",\n \"description\": \"Logic gate gallery using IEC 60617 rectangular symbols for AND, OR, XOR, NAND, NOR, NOT, and special-output buffers.\",\n \"standard\": \"IEC 60617-12\",\n \"tags\": [\n \"logic\",\n \"iec\",\n \"gate-gallery\",\n \"ansi-alternative\",\n \"symbols\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"logic \\\"IEC Gate Gallery\\\" style: iec\\ninput A, B, C, EN\\noutput Y_and, Y_or, Y_xor, Y_nand, Y_nor, Y_not, Y_tri\\nY_and = AND(A, B)\\nY_or = OR(A, B)\\nY_xor = XOR(A, B)\\nY_nand = NAND(A, B)\\nY_nor = NOR(A, B)\\nY_not = NOT(C)\\nY_tri = TRISTATE_BUF(A, EN)\",\n \"notes\": \"## Scenario\\n\\nANSI curved gates are common in US education, but IEC rectangular logic symbols are standard in many international and industrial documents. This example shows the same functional DSL rendered with the IEC style.\\n\\n## Annotation key\\n\\n- `style: iec` switches the symbol family for the whole diagram.\\n- Gate definitions remain ordinary functional assignments.\\n- The gallery includes both basic gates and a special-output buffer.\"\n },\n {\n \"slug\": \"logic-full-adder\",\n \"diagram\": \"logic\",\n \"title\": \"1-bit full adder\",\n \"description\": \"1-bit full adder built from XOR, AND, and OR gates — the foundational building block of every arithmetic logic unit, from a functional description.\",\n \"standard\": \"IEEE 91\",\n \"tags\": [\n \"XOR\",\n \"AND\",\n \"OR\",\n \"combinational\",\n \"ALU\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"logic \\\"1-bit Full Adder\\\"\\ninput A, B, Cin\\noutput Sum, Cout\\ns1 = XOR(A, B)\\nSum = XOR(s1, Cin)\\nc1 = AND(A, B)\\nc2 = AND(s1, Cin)\\nCout = OR(c1, c2)\",\n \"notes\": \"## Scenario\\n\\nThe 1-bit full adder is the foundational building block of every arithmetic logic unit. Digital logic students derive it in lecture; FPGA engineers instantiate it in RTL. Schematex renders it from a purely functional description — no manual gate placement, no wire routing — making it easy to embed in textbooks, datasheets, or AI-generated hardware documentation.\\n\\n## Annotation key\\n\\n- `input A, B, Cin` — declare named input ports\\n- `output Sum, Cout` — declare named output ports\\n- `s1 = XOR(A, B)` — intermediate signal `s1` is the XOR of inputs A and B\\n- `Sum = XOR(s1, Cin)` — the sum bit is the XOR of the partial sum and carry-in\\n- `c1 = AND(A, B)` — carry generated when both A and B are 1\\n- `c2 = AND(s1, Cin)` — carry propagated when partial sum is 1 and Cin is 1\\n- `Cout = OR(c1, c2)` — carry-out is 1 if either generate or propagate carry is active\\n\\n## How to read\\n\\nThe diagram renders two XOR gates for the sum path (A⊕B, then ⊕Cin) and two AND gates feeding an OR for the carry-out (the standard generate/propagate structure). The layout is automatically ranked so data flows left to right, inputs on the left edge, outputs on the right. Every 4-bit or 8-bit ripple-carry adder in textbooks is just this circuit chained together.\"\n },\n {\n \"slug\": \"markov-customer-lifecycle\",\n \"diagram\": \"markov\",\n \"title\": \"Customer lifecycle (ergodic chain, stationary π)\",\n \"description\": \"A SaaS trial → active → churned chain. The engine validates the row-stochastic matrix, confirms the chain is ergodic, and computes the long-run stationary distribution π — the steady-state share of customers in each state.\",\n \"standard\": \"Kemeny & Snell, Finite Markov Chains\",\n \"tags\": [\n \"markov\",\n \"stationary\",\n \"ergodic\",\n \"lifecycle\",\n \"churn\",\n \"steady-state\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"markov \\\"Customer lifecycle\\\"\\n analysis: classify, stationary\\n Trial -> Trial : 0.4\\n Trial -> Active : 0.5\\n Trial -> Churned : 0.1\\n Active -> Active : 0.8\\n Active -> Trial : 0.05\\n Active -> Churned : 0.15\\n Churned -> Churned : 0.7\\n Churned -> Trial : 0.3\",\n \"notes\": \"## What this shows\\n\\nA SaaS customer modelled as a memoryless hop between three states — Trial, Active, Churned — each month. Every row of probabilities leaving a state sums to 1 (the row-stochastic rule), and because churned customers can re-enter via Trial (`Churned -> Trial : 0.3`), no state is a dead end: the chain is **ergodic**, every state reachable from every other.\\n\\nThe engine does the linear algebra. It validates the matrix, runs SCC analysis to confirm a single recurrent class with no absorbing sink, then computes the **stationary distribution π** — the long-run share of your customer base sitting in each state once the system settles, independent of where it started. That steady-state answer (and the per-state classification) is carried in `data-*`, and it is the number a churn model exists to produce, not the circles-and-arrows.\"\n },\n {\n \"slug\": \"markov-gamblers-ruin\",\n \"diagram\": \"markov\",\n \"title\": \"Gambler's ruin (absorbing chain)\",\n \"description\": \"The classic absorbing Markov chain with two sinks. The engine classifies the transient and absorbing states and computes the fundamental matrix — the probability of ending broke vs rich and the expected number of steps to absorption.\",\n \"standard\": \"Kemeny & Snell, Finite Markov Chains\",\n \"tags\": [\n \"markov\",\n \"absorbing\",\n \"fundamental-matrix\",\n \"gamblers-ruin\",\n \"transient\",\n \"expected-steps\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"markov \\\"Gambler's ruin\\\"\\n analysis: classify, absorbing\\n state Broke \\\"$0\\\" absorbing\\n state Rich \\\"$4\\\" absorbing\\n state S1\\n state S2\\n state S3\\n Broke -> Broke : 1\\n Rich -> Rich : 1\\n S1 -> Broke : 0.5\\n S1 -> S2 : 0.5\\n S2 -> S1 : 0.5\\n S2 -> S3 : 0.5\\n S3 -> S2 : 0.5\\n S3 -> Rich : 0.5\",\n \"notes\": \"## What this shows\\n\\nThe canonical absorbing Markov chain. A gambler with \\\\$1, \\\\$2, or \\\\$3 (states S1–S3) bets on a fair coin, moving up or down \\\\$1 each round, and stops only at ruin (\\\\$0) or the target (\\\\$4). The two endpoints are declared `absorbing` — once entered, never left (a self-loop of probability 1) — and the engine cross-checks that assertion against the matrix.\\n\\nThis is where the engine's linear algebra pays off. It classifies S1–S3 as **transient** and Broke/Rich as **absorbing**, then forms the fundamental matrix N = (I − Q)⁻¹ to compute the two answers an absorbing chain is built for: the **absorption probabilities** (starting from each state, the chance of ending broke vs rich — for a fair game, proportional to the distance to each barrier) and the **expected number of steps to absorption**. Those computed values, carried in `data-*`, are the result no drawing tool can give.\"\n },\n {\n \"slug\": \"matrix-9-box-talent\",\n \"diagram\": \"matrix\",\n \"title\": \"9-box talent grid\",\n \"description\": \"3×3 performance × potential talent grid — the GE/McKinsey HR review tool used to plan promotions, succession, and performance management.\",\n \"standard\": \"9-Box Talent Grid (GE / McKinsey)\",\n \"tags\": [\n \"matrix\",\n \"9-box\",\n \"talent\",\n \"hr\",\n \"succession\",\n \"performance\",\n \"table\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"matrix 9-box \\\"Engineering — H1 Talent Review\\\"\\nstyle: table\\ncell (0,2) label: \\\"Enigma\\\"\\ncell (0,2) label: \\\"Samir K. (sr. eng)\\\"\\ncell (1,2) label: \\\"Growth Employee\\\"\\ncell (1,2) label: \\\"Priya R. (eng II)\\\"\\ncell (1,2) label: \\\"Tomás L. (eng II)\\\"\\ncell (2,2) label: \\\"Future Leader\\\"\\ncell (2,2) label: \\\"Maya O. (sr. eng)\\\"\\ncell (0,1) label: \\\"Dilemma\\\"\\ncell (0,1) label: \\\"David C. (eng II)\\\"\\ncell (1,1) label: \\\"Core Player\\\"\\ncell (1,1) label: \\\"Lin H. (sr. eng)\\\"\\ncell (1,1) label: \\\"Kofi A. (eng II)\\\"\\ncell (2,1) label: \\\"High Impact\\\"\\ncell (2,1) label: \\\"Reina S. (staff)\\\"\\ncell (0,0) label: \\\"Under-performer\\\"\\ncell (0,0) label: \\\"— PIP candidate —\\\"\\ncell (1,0) label: \\\"Effective\\\"\\ncell (1,0) label: \\\"Jordan P. (eng I)\\\"\\ncell (2,0) label: \\\"Trusted Pro\\\"\\ncell (2,0) label: \\\"Elena V. (staff)\\\"\",\n \"notes\": \"## Scenario\\n\\nA VP of People runs the half-year talent review with eng managers. Each direct report lands in one of nine cells based on **performance** (the x-axis: how they're doing today) and **potential** (the y-axis: how much room they have to grow). The three top-row cells are the succession bench. The three bottom-row cells are the performance-management agenda. The middle row is the steady-state core that holds the org together.\\n\\n## Annotation key\\n\\n- `matrix 9-box` — preset 3×3 grid (the canonical nine cell names ship with the template)\\n- `style: table` — top-aligned bullet-list rendering inside each cell\\n- `cell (col, row) label: \\\"...\\\"` — each line adds one bullet to that cell. First line per cell is the canonical role name (Enigma / Future Leader / Core Player / …); subsequent lines list the people in that cell\\n- Coordinates: `(0, 0)` is bottom-left (low performance, low potential); `(2, 2)` is top-right (high performance, high potential)\\n\\n## How to read\\n\\n**Future Leader** (top-right) is the natural-successor cell — the person you'd promote if a senior role opens tomorrow. **Dilemma** (top-left) and **Enigma** (top-middle-left) are the high-potential / low-performance cells: stuck in the wrong role, or under-coached, or in a bad team-fit — usually a managerial action item, not a performance issue. **Under-performer** (bottom-left) is the only cell that should ever be empty; if it has names, plan the next conversation now.\\n\\nThe canonical 9-box discipline is to **anchor each calibration discussion on observable evidence** — a recent shipped project, a missed deadline, a mentee promotion. Without that anchor, the grid drifts into bias. The table format is what the calibration committee literally prints and marks up in the room.\"\n },\n {\n \"slug\": \"matrix-bcg-portfolio\",\n \"diagram\": \"matrix\",\n \"title\": \"BCG product portfolio\",\n \"description\": \"BCG matrix plotting five product lines by market share and growth rate — stars, cash cows, question marks, and one dog — for annual investment planning.\",\n \"standard\": \"BCG Growth-Share (1970)\",\n \"tags\": [\n \"matrix\",\n \"bcg\",\n \"portfolio\",\n \"strategy\",\n \"investment\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"matrix bcg \\\"Product Portfolio — FY26\\\"\\n\\\"Platform SDK\\\" at (0.8, 0.8) size: 5 highlight: true category: star\\n\\\"Legacy API\\\" at (0.85, 0.15) size: 4 category: cashcow\\n\\\"Mobile SDK\\\" at (0.25, 0.85) size: 3 category: question\\n\\\"Self-serve billing\\\" at (0.35, 0.75) size: 2 category: question\\n\\\"On-prem installer\\\" at (0.2, 0.15) size: 1 category: dog\",\n \"notes\": \"## Scenario\\n\\nA VP of product strategy presents this at the annual planning offsite. The Platform SDK is the clear star — keep investing. The Legacy API is a cash cow that funds new bets. Two question marks (Mobile SDK, Self-serve billing) get the hard conversation: which one earns the next round of engineering spend? The on-prem installer is a dog — sunset candidate.\\n\\n## Annotation key\\n\\n- `matrix bcg` — preset axes (market share ← → low; low → high growth)\\n- `\\\"Label\\\" at (x, y)` — share (0–1) × growth (0–1)\\n- `size:` — relative revenue contribution\\n- `category:` — BCG quadrant tag; drives colour\\n\\n## How to read\\n\\nBCG uses a *reversed* x-axis: high market share is on the left, low on the right. That quirk puts cash cows in the bottom-left (high share, low growth) and stars in the top-left (high share, high growth). The right half holds low-share products: top-right = question marks (decide: invest or kill), bottom-right = dogs (usually kill). Bubble size shows current revenue — don't prematurely kill a cow that funds a star.\"\n },\n {\n \"slug\": \"matrix-eisenhower-week\",\n \"diagram\": \"matrix\",\n \"title\": \"Eisenhower week prioritization\",\n \"description\": \"2×2 Eisenhower table grouping a week's tasks into Do First / Schedule / Delegate / Delete — the canonical text-in-cell layout, not a scatter chart.\",\n \"standard\": \"Eisenhower (1954)\",\n \"tags\": [\n \"matrix\",\n \"eisenhower\",\n \"prioritization\",\n \"productivity\",\n \"planning\",\n \"table\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"matrix eisenhower \\\"This Week\\\"\\nstyle: table\\nQ2: \\\"Ship hotfix\\\"\\nQ2: \\\"Customer demo prep\\\"\\nQ1: \\\"Write Q3 OKRs\\\"\\nQ1: \\\"Refactor auth layer\\\"\\nQ4: \\\"LinkedIn updates\\\"\\nQ4: \\\"Inbox zero\\\"\\nQ3: \\\"Reorganize Slack channels\\\"\",\n \"notes\": \"## Scenario\\n\\nAn engineering manager triages her week at Monday planning. The point of an Eisenhower matrix in real use isn't a scatter plot — it's a **four-cell list**: tasks dropped into the quadrant that matches their urgency × importance. The table tells her at a glance where her attention should go this week (Do First + Schedule), what to push down (Delegate), and what to drop (Delete).\\n\\n## Annotation key\\n\\n- `matrix eisenhower` — preset axes (urgency × importance) and four quadrant titles\\n- `style: table` — text-in-cell layout: hides axes/arrows/grid, renders quadrant titles as cell headers, lists each item as a bullet\\n- `Q1:` … `Q4:` — shorthand for `cell (col, row) label: …`. Q1=top-right (Schedule), Q2=top-left (Do First), Q3=bottom-left (Delete), Q4=bottom-right (Delegate)\\n- Repeating `Q2:` stacks multiple tasks in the same cell as a bullet list\\n\\n## How to read\\n\\nThe \\\"Do First\\\" cell (top-left in eisenhower's convention with urgent on the left axis) is the urgent + important pile — work the morning sprint. \\\"Schedule\\\" is the trap quadrant: important but not yet urgent (Q3 OKRs, refactor) — it silently slips until it becomes urgent and badly done. \\\"Delegate\\\" is the busy-work the AI generates — urgent on someone's calendar but not actually load-bearing for the org. \\\"Delete\\\" is the candidate for \\\"no\\\": neither urgent nor important.\\n\\n## Why a table, not a chart\\n\\nThe classic Eisenhower output is a 2×2 grid with task lists, not a scatter of dots. If you want to encode a third dimension (time cost, owner) on top of the cell layout, drop `style: table` and use `\\\"Label\\\" at (x, y) size: N` instead — that switches to bubble mode.\"\n },\n {\n \"slug\": \"matrix-impact-effort\",\n \"diagram\": \"matrix\",\n \"title\": \"Impact-effort feature prioritization\",\n \"description\": \"2×2 impact × effort table sorting a backlog into Quick Wins / Major Projects / Fill-ins / Thankless — the classic PM prioritization grid.\",\n \"standard\": \"Impact–Effort (Sondhi 1999)\",\n \"tags\": [\n \"matrix\",\n \"impact\",\n \"effort\",\n \"prioritization\",\n \"product\",\n \"table\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"matrix impact-effort \\\"Sprint Planning — Q2 Backlog\\\"\\nstyle: table\\nQ2: \\\"Add bulk-delete to inbox\\\"\\nQ2: \\\"Surface error message inline\\\"\\nQ2: \\\"Fix mobile menu z-index bug\\\"\\nQ1: \\\"Rebuild billing on new stripe API\\\"\\nQ1: \\\"Multi-tenant workspace support\\\"\\nQ3: \\\"Brand color audit\\\"\\nQ3: \\\"Update tooltip copy\\\"\\nQ4: \\\"Animated empty-state illustrations\\\"\\nQ4: \\\"Internal admin dashboard polish\\\"\",\n \"notes\": \"## Scenario\\n\\nA solo PM running quarterly planning ranks the backlog. The table form is what stakeholders actually want to see in the planning doc — a sortable list per quadrant, not a scatter plot. Quick Wins go in the top-left (high impact, low effort) — ship them this sprint. Major Projects are the bets (high impact, high effort) — pick at most one per quarter. Thankless work (low impact, high effort) is where teams accidentally burn quarters.\\n\\n## Annotation key\\n\\n- `matrix impact-effort` — preset axes (effort × impact) with the four PM-canonical quadrant names\\n- `style: table` — render as a 4-cell text grid, no axis arrows, no chart\\n- `Q1` … `Q4` — Q1=high impact + high effort (Major Projects), Q2=high impact + low effort (Quick Wins), Q3=low impact + low effort (Fill-ins), Q4=low impact + high effort (Thankless)\\n\\n## How to read\\n\\nIf your Quick Wins cell is empty, that's a smell — it usually means the PM hasn't broken down work small enough. If your Major Projects cell has more than one item per engineer-quarter, you're overcommitting. The Thankless cell is where you have the conversation about cutting scope or pushing to next quarter.\"\n },\n {\n \"slug\": \"matrix-johari-window\",\n \"diagram\": \"matrix\",\n \"title\": \"Johari window — manager self-assessment\",\n \"description\": \"2×2 Johari window placing self-traits across Open / Blind / Hidden / Unknown — the classic coaching exercise rendered as a four-cell table.\",\n \"standard\": \"Johari window (Luft & Ingham 1955)\",\n \"tags\": [\n \"matrix\",\n \"johari\",\n \"coaching\",\n \"self-awareness\",\n \"hr\",\n \"table\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"matrix johari \\\"Self vs. Team — Q2 Reflection\\\"\\nstyle: table\\nQ2: \\\"Strong technical instincts\\\"\\nQ2: \\\"Direct in code review\\\"\\nQ2: \\\"Patient with juniors\\\"\\nQ1: \\\"Interrupts in meetings\\\"\\nQ1: \\\"Hard to read when stressed\\\"\\nQ3: \\\"Imposter syndrome about leadership\\\"\\nQ3: \\\"Anxiety about cross-team politics\\\"\\nQ4: \\\"Capacity for difficult conversations under pressure\\\"\",\n \"notes\": \"## Scenario\\n\\nA newly-promoted engineering manager runs a Johari exercise with her team during a 1:1 retro. She populates the **Open** cell (things both she and the team see); the team adds to **Blind** (things they see that she doesn't); she fills **Hidden** privately; **Unknown** is the open hypothesis space — capabilities and limitations that haven't surfaced yet.\\n\\nThe table form is the canonical Johari output. Coaches print it on a single page and walk through it with the coachee — a scatter plot of dots would defeat the entire purpose.\\n\\n## Annotation key\\n\\n- `matrix johari` — preset axes (Known to Self × Known to Others) with the four window panes\\n- `style: table` — flips off axes/grid, places each pane title as a cell header, lists items as bullets\\n- `Q1` = Blind (top-right: not known to self, known to others)\\n- `Q2` = Open / Arena (top-left: known to self + others)\\n- `Q3` = Hidden / Façade (bottom-left: known to self, not to others)\\n- `Q4` = Unknown (bottom-right: not known to either — the growth hypothesis space)\\n\\n## How to read\\n\\nThe classic Johari coaching prompt: **how do you move items from Hidden → Open** (vulnerability work) **and from Blind → Open** (feedback-acceptance work)? An overstuffed Hidden pane signals psychological-safety debt; an empty Blind pane usually means the team hasn't been asked.\"\n },\n {\n \"slug\": \"matrix-qfd-coffee-maker\",\n \"diagram\": \"matrix\",\n \"title\": \"Coffee maker House of Quality\",\n \"description\": \"A QFD House of Quality where the engine computes the technical-importance row (45 / 39 / 51) — the ranked answer to which engineering characteristic moves the most customer value — plus the diamond-cell roof that flags trade-offs between characteristics.\",\n \"standard\": \"Akao Quality Function Deployment\",\n \"tags\": [\n \"matrix\",\n \"qfd\",\n \"house-of-quality\",\n \"akao\",\n \"voice-of-customer\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"matrix qfd \\\"Coffee maker\\\"\\nwhat: \\\"Quiet operation\\\" weight: 5\\nwhat: \\\"Brews fast\\\" weight: 3\\nwhat: \\\"Energy efficient\\\" weight: 4\\nhow: \\\"Fan RPM\\\" dir: down\\nhow: \\\"Heater watts\\\" dir: up\\nhow: \\\"Insulation\\\" dir: up\\nrel (0,0): 9\\nrel (0,2): 3\\nrel (1,1): 9\\nrel (2,1): 3\\nrel (2,2): 9\\nroof (0,1): --\\nroof (1,2): +\",\n \"notes\": \"## What this shows\\n\\nThe **House of Quality** — the core matrix of Akao's Quality Function Deployment — translates what customers want into the engineering characteristics that deliver it. Customer requirements (**WHATs**) are the rows, each with an importance weight; engineering characteristics (**HOWs**) are the columns; the body cells record how strongly each HOW serves each WHAT on the 9 / 3 / 1 strong-medium-weak scale.\\n\\nThe differentiator is the computed row at the foot of the house: each column's **technical importance** is the sum of `weight × strength` down that column, here **45 / 39 / 51** — so Insulation (51) is the highest-leverage characteristic to invest in and Heater watts (39) the lowest. (Add `normalize: true` to read these as 33% / 29% / 38% instead.) Above the columns, the **roof** is a half-matrix of diamond cells recording HOW-to-HOW correlations: `roof (0,1): --` flags that lowering Fan RPM while raising Heater watts is a trade-off, while `roof (1,2): +` flags that Heater watts and Insulation reinforce each other.\"\n },\n {\n \"slug\": \"matrix-sipoc-order-fulfilment\",\n \"diagram\": \"matrix\",\n \"title\": \"Order fulfilment SIPOC\",\n \"description\": \"The one-page scoping table that opens a Six Sigma DMAIC project — Suppliers, Inputs, Process, Outputs, Customers in five fixed columns, pinning down exactly where the process starts and ends before anyone improves it.\",\n \"standard\": \"Six Sigma DMAIC\",\n \"tags\": [\n \"matrix\",\n \"sipoc\",\n \"six-sigma\",\n \"dmaic\",\n \"process-scoping\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"matrix sipoc \\\"Order fulfilment\\\"\\nsuppliers: \\\"Vendor\\\", \\\"Warehouse\\\"\\ninputs: \\\"PO\\\", \\\"Stock levels\\\"\\nprocess: \\\"Receive order\\\", \\\"Pick\\\", \\\"Pack\\\", \\\"Ship\\\"\\noutputs: \\\"Shipped package\\\", \\\"Invoice\\\"\\ncustomers: \\\"End customer\\\", \\\"Finance\\\"\",\n \"notes\": \"## What this shows\\n\\nA **SIPOC** is the first artifact a Six Sigma team builds in the *Define* phase of DMAIC. It names — in five columns read left to right — everyone and everything the process touches: **S**uppliers hand in **I**nputs, the **P**rocess turns them into **O**utputs, and **C**ustomers receive them. Here the order-fulfilment process runs `Receive order → Pick → Pack → Ship`, fed by purchase orders and stock levels from the vendor and warehouse, and producing a shipped package for the end customer and an invoice for finance.\\n\\nThe point of a SIPOC is boundary-setting before measurement: it forces the team to agree where the process starts, where it ends, and who hands work in and out of it. The five columns always render in canonical S-I-P-O-C order, so the diagram reads correctly even when the blocks are authored out of sequence.\"\n },\n {\n \"slug\": \"mindmap-driver-readmissions\",\n \"diagram\": \"mindmap\",\n \"title\": \"Driver diagram — reduce 30-day readmissions\",\n \"description\": \"An IHI driver diagram that traces a quality-improvement aim left to right through its primary drivers and the concrete change ideas meant to move them.\",\n \"standard\": \"Driver Diagram: IHI improvement model\",\n \"tags\": [\n \"mindmap\",\n \"driver\",\n \"quality-improvement\",\n \"healthcare\",\n \"aim-driver-change\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"%% style: driver\\n# Reduce 30-day readmissions\\n## Reliable discharge process\\n- Teach-back at bedside\\n- Med reconciliation\\n## Timely follow-up\\n- Appointment within 7 days\\n- Post-discharge phone call\",\n \"notes\": \"## What this shows\\n\\nA **driver diagram** — the planning artifact from the IHI (Institute for Healthcare Improvement) model for improvement. It reads left to right as a tidy tree: the **aim** (\\\"reduce 30-day readmissions\\\") on the far left, the **primary drivers** that move it (\\\"reliable discharge process\\\", \\\"timely follow-up\\\") in the next column, and the concrete **change ideas** — teach-back at the bedside, medication reconciliation, an appointment within 7 days — branching out to the right.\\n\\nThe value is the line of sight it forces. Every change idea on the right traces back through a driver to the aim, so a team can defend *why* each intervention is on the board and spot which drivers still have no ideas attached. It is the ordinary `#` / `##` / `-` mindmap input, rendered as an aim → drivers → change-ideas tree by adding `%% style: driver`.\"\n },\n {\n \"slug\": \"mindmap-futureswheel-remote-work\",\n \"diagram\": \"mindmap\",\n \"title\": \"Futures wheel — remote work becomes default\",\n \"description\": \"A structured-brainstorming futures wheel that ripples a single trend outward into first- and second-order consequences across concentric, color-coded rings.\",\n \"standard\": \"Futures Wheel: Glenn (1972)\",\n \"tags\": [\n \"mindmap\",\n \"futureswheel\",\n \"foresight\",\n \"consequence-mapping\",\n \"scenario-planning\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"%% style: futureswheel\\n# Remote work becomes default\\n## Less commuting\\n- Lower carbon emissions\\n- Cheaper city living\\n## Distributed teams\\n- Async communication norms\\n- Global hiring pools\\n## Empty offices\\n- Commercial real estate slump\\n- Repurposed to housing\",\n \"notes\": \"## What this shows\\n\\nA **futures wheel** — Jerome Glenn's 1971/72 technique for thinking past a trend's obvious effects. A single event sits at the hub (\\\"remote work becomes default\\\"), its first-order consequences land on the inner ring, and each of those fans out to its own second-order consequences on the next ring. Reading outward is reading forward in causal time: less commuting *leads to* lower emissions and cheaper city living; empty offices *lead to* a commercial-real-estate slump and housing conversions.\\n\\nThe layout does the discipline for you. Every child is kept inside its parent's angular sector, so a branch never tangles with its neighbors, and each ring is color-coded by order — the visual cue that tells a workshop room how many steps removed a given consequence is from the original trend. It is the same `#` / `##` / `-` mindmap input you already write, switched on with `%% style: futureswheel`.\"\n },\n {\n \"slug\": \"mindmap-product-launch\",\n \"diagram\": \"mindmap\",\n \"title\": \"Product launch plan mindmap\",\n \"description\": \"Radial mind map for a product launch — market readiness, engineering, go-to-market, and success metrics — used as a kickoff whiteboard.\",\n \"standard\": \"Buzan (1970s)\",\n \"tags\": [\n \"mindmap\",\n \"product-launch\",\n \"planning\",\n \"gtm\",\n \"brainstorming\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"mindmap\\n\\n# Product Launch Plan\\n\\n## Market readiness\\n### Competitive analysis\\n- Direct competitors\\n- Pricing benchmarks\\n### Target segments\\n- SMB customers\\n- Enterprise pilot\\n\\n## Engineering\\n### Feature freeze\\n- Core API complete\\n- Edge cases resolved\\n### Infrastructure\\n- Load testing\\n- CDN configuration\\n - Cache rules\\n - Geo routing\\n\\n## Go-to-market\\n- Landing page live\\n- Email campaign\\n- Press outreach\\n - TechCrunch pitch\\n - Newsletter sponsors\\n\\n## Success metrics\\n- Week 1 signups\\n- Activation rate\\n- NPS at day 30\",\n \"notes\": \"## Scenario\\n\\nThe launch lead opens the kickoff meeting with this mindmap on a shared whiteboard. Four branches name the four owners (product, engineering, marketing, analytics) and every leaf is a checkable deliverable. The radial layout gives each owner roughly equal visual real estate — no function's work feels like an afterthought.\\n\\n## Annotation key\\n\\n- `#` — root (exactly one)\\n- `##`, `###` — branch depth; each extra `#` nests one level deeper\\n- `-` bullets — leaf items; 2-space indent adds another level\\n\\n## How to read\\n\\nStart at the centre. Each `##` heading is a top-level workstream with its own owner. `###` headings group sub-areas; bullet lists capture concrete deliverables. Indented bullets (e.g. *Cache rules* under *CDN configuration*) are sub-tasks owned by the same person who owns the parent. Anything without a bullet-or-heading is not tracked — the mindmap is the source of truth.\"\n },\n {\n \"slug\": \"mindmap-quarterly-okrs\",\n \"diagram\": \"mindmap\",\n \"title\": \"Quarterly OKRs mindmap\",\n \"description\": \"Company OKRs organized as a mindmap — three objectives, each with measurable key results — suited for the all-hands kickoff of a new quarter.\",\n \"standard\": \"Buzan (1970s)\",\n \"tags\": [\n \"mindmap\",\n \"okrs\",\n \"planning\",\n \"company\",\n \"quarterly\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"mindmap\\n\\n# Q4 Company OKRs\\n\\n## Grow ARR 30%\\n### Expand enterprise pipeline\\n- 10 new qualified logos\\n- Win rate ≥ 25%\\n### Increase expansion\\n- Net revenue retention ≥ 120%\\n- Seat adoption +40%\\n\\n## Ship Platform v2\\n### Core migration\\n- 100% API coverage\\n- Zero-downtime cutover\\n### Developer experience\\n- Sub-5-min quickstart\\n- 95% doc satisfaction\\n\\n## Strengthen team\\n### Hiring\\n- 8 senior engineers\\n- 2 staff PMs\\n### Retention\\n- Voluntary attrition < 5%\\n- eNPS ≥ 40\",\n \"notes\": \"## Scenario\\n\\nThe chief of staff projects this during the Q4 all-hands. Three objectives radiate from the centre; every key result is a leaf with a specific number. The mindmap format reads fast — every person in the company can find their team's objective within three seconds — and it tolerates mid-quarter edits without disturbing other branches.\\n\\n## Annotation key\\n\\n- `#` — root; company-level frame\\n- `##` — objective (qualitative direction)\\n- `###` — key-result cluster\\n- `-` bullets — specific measurable KRs\\n\\n## How to read\\n\\nThe root names the quarter. The three `##` branches are the objectives — the things that will be judged at the end of the quarter. Each `###` groups key results by theme; the bullets are the actual measurable targets. If a KR can't be reduced to a number, it probably belongs in a planning doc rather than on this mindmap.\"\n },\n {\n \"slug\": \"network-boundaries\",\n \"diagram\": \"network\",\n \"title\": \"Physical and logical boundaries in one diagram\",\n \"description\": \"A branch-office topology nesting physical containers (a site holding an MDF rack) and logical overlays (a DMZ security zone and a CIDR subnet) — solid borders for physical, dashed tinted borders for logical — so the same devices read correctly in both the cabling and the addressing views.\",\n \"standard\": \"Cisco-convention topology icons + hierarchical campus model\",\n \"tags\": [\n \"network\",\n \"boundaries\",\n \"subnet\",\n \"vlan\",\n \"dmz\",\n \"rack\",\n \"security-zone\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"network \\\"Branch Office\\\"\\n layout: tiered\\n internet net\\n site hq \\\"HQ Building\\\" {\\n rack mdf \\\"MDF Rack\\\" {\\n firewall fw1 tier: edge\\n l3switch core1 tier: core\\n }\\n }\\n zone dmz \\\"DMZ\\\" {\\n server web \\\"Web Server\\\"\\n }\\n subnet lan \\\"10.0.10.0/24\\\" {\\n switch a1 tier: access\\n pc u1 \\\"User PC\\\" ip: 10.0.10.50\\n }\\n net -- fw1 : wan\\n fw1 -- web\\n fw1 -- core1 : 10G\\n core1 -- a1 : trunk vlan: 10\\n a1 -- u1\",\n \"notes\": \"Real network documentation has to answer two different questions at once: *where is this box physically* (which building, which rack) and *what address space / security zone is it in*. Schematex draws both kinds of grouping and distinguishes them visually.\\n\\n**Physical containers are solid.** `site` and `rack` blocks get solid borders — the HQ building holds an MDF rack holding the firewall and core switch.\\n\\n**Logical overlays are dashed and tinted.** `zone` (the DMZ) and `subnet` (the `10.0.10.0/24` LAN) get dashed, tinted borders — they group by policy and addressing, not by location. The engine validates that `u1`'s `ip: 10.0.10.50` actually falls inside the subnet's CIDR.\\n\\n**Tiers still band the layout.** `tier: edge|core|access` keeps the hierarchical top-to-bottom ordering even inside the boundaries, so the diagram reads as a proper three-tier design.\"\n },\n {\n \"slug\": \"network-cctv-camera-system\",\n \"diagram\": \"network\",\n \"title\": \"CCTV camera network topology\",\n \"description\": \"IP-video surveillance topology — Internet → perimeter firewall → core switch → PoE switches → dome/PTZ/bullet cameras, with the cameras isolated on their own 192.168.20.0/24 subnet and an NVR for recording.\",\n \"standard\": \"Cisco topology icons + IP/CCTV (ONVIF) conventions\",\n \"tags\": [\n \"cctv\",\n \"surveillance\",\n \"ip-camera\",\n \"nvr\",\n \"poe\",\n \"vlan\",\n \"subnet\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"network \\\"Acme HQ — CCTV\\\"\\n layout: tiered\\n internet net \\\"Internet\\\"\\n firewall fw1 \\\"Perimeter FW\\\" tier: edge\\n l3switch core1 \\\"Core SW\\\" tier: core\\n poeswitch poe1 \\\"PoE Switch A\\\" tier: access\\n poeswitch poe2 \\\"PoE Switch B\\\" tier: access\\n nvr nvr1 \\\"Video Recorder\\\"\\n monitor wall1 \\\"Guard Station\\\"\\n subnet cams \\\"192.168.20.0/24\\\" {\\n camera cam1 \\\"Lobby Dome\\\" type: dome ip: 192.168.20.11\\n camera cam2 \\\"Gate PTZ\\\" type: ptz ip: 192.168.20.12\\n camera cam3 \\\"Dock Bullet\\\" type: bullet ip: 192.168.20.13\\n poe1\\n poe2\\n }\\n net -- fw1 : wan \\\"ISP 1Gbps\\\"\\n fw1 -- core1 : fiber 10G\\n core1 -- poe1 : trunk vlan: 20 1G\\n core1 -- poe2 : trunk vlan: 20 1G\\n core1 -- nvr1 : 1G\\n core1 -- wall1\\n poe1 -- cam1 : poe\\n poe1 -- cam2 : poe\\n poe2 -- cam3 : poe\",\n \"notes\": \"## Scenario\\n\\nA security integrator is documenting an IP-CCTV install for hand-off. The cameras need their own isolated subnet (so they can't route to the corporate LAN), Power-over-Ethernet from the access switches, and a single NVR recording everything. The diagram has to be **editable and printable** so it can be reused for the next building.\\n\\n## What the diagram shows\\n\\n- **The camera subnet** `192.168.20.0/24` is drawn as a dashed boundary enclosing the three cameras and both PoE switches — the cameras' IPs are validated against the CIDR, so a typo'd address is caught, not silently rendered.\\n- **Camera body styles** are real silhouettes: `type: dome`, `type: ptz`, and `type: bullet` each render differently, the way an integrator's drawings distinguish them.\\n- **PoE links** (`poe`) are drawn in green with a power tag — these carry both data and power to the cameras.\\n- **The uplinks** are a trunk carrying VLAN 20 at 1G; the fiber backbone to the core is orange at 10G; the ISP hand-off is a serial/WAN circuit.\\n\\n## Annotation key\\n\\n| Element | Meaning |\\n|---|---|\\n| Dashed blue box | Logical subnet (label = CIDR) |\\n| Green link + PoE | Power-over-Ethernet to a camera |\\n| Orange link | Fiber uplink |\\n| `Trunk · VLAN 20 · 1G` | 802.1Q trunk carrying VLAN 20 at 1 Gbps |\\n\\nSwap `layout: tiered` for `layout: tree` to get a pure hierarchy, or add more `subnet` / `vlan` boundaries as the install grows.\"\n },\n {\n \"slug\": \"network-enterprise-campus\",\n \"diagram\": \"network\",\n \"title\": \"Three-tier enterprise campus network\",\n \"description\": \"Classic Cisco hierarchical campus — Internet/WAN edge, redundant core switches with a LAG uplink, a distribution layer, and an access layer feeding a server farm. The canonical core/distribution/access model.\",\n \"standard\": \"Cisco hierarchical internetworking model (core/distribution/access)\",\n \"tags\": [\n \"campus\",\n \"three-tier\",\n \"core\",\n \"distribution\",\n \"access\",\n \"lag\",\n \"enterprise\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"network \\\"Driscoll Campus\\\"\\n layout: tiered\\n internet inet\\n cloud wan \\\"WAN\\\"\\n firewall fw1 \\\"Core Firewall\\\" tier: edge\\n router er1 \\\"Edge Rtr 1\\\" tier: edge\\n l3switch cs1 \\\"Core SW 1\\\" tier: core\\n l3switch cs2 \\\"Core SW 2\\\" tier: core\\n switch d1 \\\"Dist A\\\" tier: distribution\\n switch d2 \\\"Dist B\\\" tier: distribution\\n serverfarm farm \\\"Server Farm\\\" count: 4\\n a1 a2 a3 : switch tier: access\\n inet -- fw1\\n wan -- er1 : serial\\n fw1 -- cs1 : 10G\\n er1 -- cs2\\n cs1 == cs2 : lag 40G\\n cs1 -- d1\\n cs2 -- d2\\n cs1 -- farm : trunk vlan: 100\\n d1 -- a1\\n d2 -- a2\\n d2 -- a3\",\n \"notes\": \"## Scenario\\n\\nA network engineer is drawing the as-built for a campus that follows Cisco's three-tier hierarchical model. The `tier:` attribute on each device drives the banding, so the diagram lands in the canonical **edge → core → distribution → access** rows automatically — no manual placement.\\n\\n## What the diagram shows\\n\\n- **`tier:` banding** — `edge`, `core`, `distribution`, `access` place devices in fixed rows top-to-bottom. Endpoints (the server farm) hang below their switch.\\n- **The redundant core** — `cs1 == cs2 : lag 40G` is the EtherChannel uplink, drawn as a double line with a 40G label (`==` is shorthand for a LAG link).\\n- **Shorthand** — `a1 a2 a3 : switch tier: access` declares three identical access switches on one line.\\n- **The server farm** — `serverfarm ... count: 4` draws a stacked icon labelled ×4.\\n\\n## Annotation key\\n\\n| Element | Meaning |\\n|---|---|\\n| Double line + `40G` | Aggregated link (LAG / EtherChannel) |\\n| `tier: core` etc. | Hierarchical band assignment |\\n| `Trunk · VLAN 100` | Server-farm uplink trunk |\\n\\nFor a two-tier \\\"collapsed core\\\" just drop the distribution devices; for a data-center fabric use `layout: spine-leaf` instead.\"\n },\n {\n \"slug\": \"network-layout-modes-star-ring-bus-mesh\",\n \"diagram\": \"network\",\n \"title\": \"Network layout modes\",\n \"description\": \"Four small network topology sketches showing star, ring, bus, and mesh layouts as separate diagrams in the gallery corpus.\",\n \"standard\": \"Cisco topology conventions\",\n \"tags\": [\n \"network\",\n \"layout\",\n \"star\",\n \"ring\",\n \"bus\",\n \"mesh\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"network \\\"Branch LAN - Star Layout\\\"\\n layout: star\\n router gw \\\"Gateway\\\"\\n switch sw1 \\\"Access Switch\\\"\\n pc pc1 \\\"Admin PC\\\"\\n laptop lt1 \\\"Laptop\\\"\\n printer prn \\\"Printer\\\"\\n ap ap1 \\\"Wi-Fi AP\\\"\\n gw -- sw1 : 1G\\n sw1 -- pc1 : access vlan: 10 1G\\n sw1 -- lt1 : access vlan: 10 1G\\n sw1 -- prn : access vlan: 20 1G\\n sw1 -- ap1 : poe vlan: 30 1G\",\n \"notes\": \"## Scenario\\n\\nNetwork examples should prove that layout is semantic, not incidental. This one uses `layout: star`, where the gateway and access switch form the center and endpoints fan around them.\\n\\n## Annotation key\\n\\n- `layout: star` selects the hub-and-spoke placer.\\n- Link annotations carry VLANs, speed, and PoE.\\n- The same device/link model can be rendered with other layouts in companion examples.\"\n },\n {\n \"slug\": \"network-link-types\",\n \"diagram\": \"network\",\n \"title\": \"Every link type on one fabric\",\n \"description\": \"A compact topology that exercises the full link vocabulary — fiber with speed and port tags, a LAG bundle, a wireless association, an 802.1Q trunk carrying VLANs, a PoE drop to a camera, and a site-to-site VPN tunnel — each rendered with its own line style.\",\n \"standard\": \"Cisco-convention topology icons + ANSI/TIA-606 labelling\",\n \"tags\": [\n \"network\",\n \"links\",\n \"fiber\",\n \"lag\",\n \"vlan\",\n \"poe\",\n \"vpn\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"network \\\"Link types\\\"\\n layout: tree\\n router core \\\"Core\\\"\\n switch a \\\"Sw A\\\"\\n switch b \\\"Sw B\\\"\\n ap ap1 \\\"AP\\\"\\n server s1\\n camera c1 type: turret\\n vpngw vpn1 \\\"VPN GW\\\"\\n core -- a : fiber 10G port: Gi0/1>Gi1/0/1\\n core -- b : lag 20G\\n a -- ap1 : wireless\\n a -- s1 : trunk vlan: 10,20 1G\\n b -- c1 : poe\\n core -- vpn1 : vpn \\\"site-to-site\\\"\",\n \"notes\": \"A network diagram is only as useful as the *link* annotations — \\\"are these two switches on fiber or copper, trunk or access, what VLANs, what speed.\\\" Schematex encodes all of it after the `:` on a connection, and renders each link type distinctly.\\n\\n**One line, many semantics.** `fiber 10G port: Gi0/1>Gi1/0/1` draws the orange ticked fiber style and prints both the speed and the two interface names. `lag 20G` thickens the line for a bundled uplink. `wireless` and `vpn` go dashed; `poe` carries power to the camera; `trunk vlan: 10,20` tags the 802.1Q VLAN list.\\n\\n**Validation comes free.** VLAN ids are range-checked (1–4094) and the engine never silently drops a port, link, or device — if you wrote it, it's on the diagram or it's a reported error.\"\n },\n {\n \"slug\": \"network-spine-leaf-fabric\",\n \"diagram\": \"network\",\n \"title\": \"Spine-leaf data-center fabric\",\n \"description\": \"A folded-Clos data-center fabric — two spine switches, four leaf switches fully meshed to the spines automatically, and servers attached to their leaves at 25G.\",\n \"standard\": \"Clos (1953) folded-Clos / spine-leaf fabric\",\n \"tags\": [\n \"spine-leaf\",\n \"clos\",\n \"fabric\",\n \"datacenter\",\n \"leaf\",\n \"spine\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"network \\\"DC Fabric\\\"\\n layout: spine-leaf\\n spines: sp1 sp2\\n leaves: lf1 lf2 lf3 lf4\\n server h1\\n server h2\\n server h3\\n lf1 -- h1 : 25G\\n lf2 -- h2 : 25G\\n lf4 -- h3 : 25G\",\n \"notes\": \"## Scenario\\n\\nA data-center architect wants the fabric drawn without hand-typing every spine-to-leaf cable. In `layout: spine-leaf` mode you declare the spines and leaves, and the engine **auto-meshes every leaf to every spine** — here that's 2 × 4 = 8 generated links — leaving you to add only the host attachments.\\n\\n## What the diagram shows\\n\\n- **`spines:` / `leaves:`** declare the two fabric rows. The devices don't need a separate `kind` line — spines become L3 switches, leaves become switches.\\n- **Auto-mesh** — every spine↔leaf link is generated; you never type them. Add or remove a leaf and the mesh updates.\\n- **Host attachments** — `lf1 -- h1 : 25G` hangs a server below its leaf at 25 Gbps.\\n\\n## Annotation key\\n\\n| Element | Meaning |\\n|---|---|\\n| Top row | Spine switches |\\n| Middle row | Leaf switches (fully meshed to spines) |\\n| Bottom row | Hosts, under their leaf |\\n\\nThis is the modern east-west fabric; for a traditional north-south campus use `layout: tiered` with `tier:` bands instead.\"\n },\n {\n \"slug\": \"network-zero-trust-cloud-vpc\",\n \"diagram\": \"network\",\n \"title\": \"Zero-trust cloud VPC topology\",\n \"description\": \"Network topology for a zero-trust SaaS VPC with VPN entry, DMZ, private application subnet, database subnet, firewall segmentation, and annotated VPN/fiber/trunk links.\",\n \"standard\": \"Cisco-convention topology icons + security-zone topology\",\n \"tags\": [\n \"network\",\n \"zero-trust\",\n \"vpc\",\n \"dmz\",\n \"vpn\",\n \"firewall\",\n \"cloud\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"network \\\"Zero-trust SaaS VPC\\\"\\n layout: tiered\\n internet inet \\\"Internet\\\"\\n cloud idp \\\"Identity Provider\\\"\\n vpngw vpn \\\"Client VPN\\\" tier: edge\\n firewall fw \\\"Segmentation FW\\\" tier: edge\\n loadbalancer alb \\\"Public ALB\\\" tier: distribution\\n\\n zone dmz \\\"DMZ\\\" {\\n proxy edgeproxy \\\"Reverse Proxy\\\" tier: distribution\\n }\\n subnet appnet \\\"10.20.10.0/24\\\" {\\n server api1 \\\"API 1\\\" ip: 10.20.10.11\\n server api2 \\\"API 2\\\" ip: 10.20.10.12\\n }\\n subnet dbnet \\\"10.20.30.0/24\\\" {\\n storage db \\\"Postgres HA\\\" ip: 10.20.30.20\\n }\\n zone admin \\\"Admin Zone\\\" {\\n laptop admin1 \\\"Admin Laptop\\\"\\n }\\n\\n inet -- alb : fiber 10G\\n inet -- vpn : vpn\\n idp -- vpn : vpn \\\"OIDC\\\"\\n vpn -- fw : vpn \\\"device posture\\\"\\n alb -- edgeproxy : 1G\\n edgeproxy -- fw : trunk vlan: 110\\n fw -- api1 : access vlan: 210 1G\\n fw -- api2 : access vlan: 210 1G\\n fw -- db : access vlan: 230 1G\\n admin1 -- vpn : wireless vpn\",\n \"notes\": \"## Scenario\\n\\nZero-trust diagrams need to show both the physical/logical topology and the policy boundary: public traffic reaches only the DMZ, administrators enter through VPN and identity checks, and application servers reach the database through a segmented firewall path.\\n\\n## Annotation key\\n\\n- `zone` and `subnet` groups distinguish security policy from IP address space.\\n- VPN links are dashed and annotated, making identity/device-posture paths visible.\\n- VLAN labels document segmentation at the firewall boundary.\"\n },\n {\n \"slug\": \"orgchart-matrix-reporting\",\n \"diagram\": \"orgchart\",\n \"title\": \"Scale-up with matrix reporting\",\n \"description\": \"Org chart for a 60-person scale-up with two product lines — solid-line functional reporting plus dotted-line product-manager reporting into each engineering lead.\",\n \"standard\": \"HR convention\",\n \"tags\": [\n \"orgchart\",\n \"matrix-reporting\",\n \"scale-up\",\n \"engineering\",\n \"organization\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"Scaleup — Matrixed Product Lines\\\"\\nceo: \\\"Jamie Torres\\\" | CEO [role: ceo]\\n cto: \\\"Raj Patel\\\" | CTO [role: cto]\\n lead_core: \\\"Priya Nair\\\" | Eng Lead | Core [role: engineer]\\n eng1: \\\"Alex Kim\\\" | Senior Engineer [role: engineer]\\n eng2: \\\"Jordan Lee\\\" | Engineer [role: engineer]\\n lead_growth: \\\"Omar Hassan\\\" | Eng Lead | Growth [role: engineer]\\n eng3: \\\"Yuki Tanaka\\\" | Staff Engineer [role: engineer]\\n eng4: \\\"Maya Patel\\\" | Engineer [role: engineer]\\n cpo: \\\"Ellen Wu\\\" | CPO [role: cpo]\\n pm_core: \\\"Tyler Brooks\\\" | PM | Core [role: product]\\n pm_growth: \\\"Suki Ito\\\" | PM | Growth [role: product]\\n cdo: \\\"Liu Wei\\\" | CDO [role: design]\\n des_core: \\\"Ana Rossi\\\" | Designer | Core [role: design]\\n des_growth: \\\"Kai Park\\\" | Designer | Growth [role: design]\\npm_core -.-> lead_core\\npm_growth -.-> lead_growth\\ndes_core -.-> lead_core\\ndes_growth -.-> lead_growth\",\n \"notes\": \"## Scenario\\n\\nThe head of engineering is explaining the matrix structure to a new eng lead. Functional managers (CTO, CPO, CDO) own career growth; product-line leads coordinate day-to-day work. The dotted lines from PMs and designers into the two eng leads make this split visible without implying a change in reporting chain.\\n\\n## Annotation key\\n\\n- Solid line (indentation) — functional / HR reporting\\n- `A -.-> B` — dotted line; secondary / product reporting\\n- `[role: …]` — colour-coded by function\\n\\n## How to read\\n\\nSolid lines (from indentation) answer \\\"who owns my performance review and career.\\\" Dotted lines answer \\\"whose roadmap am I aligned to this quarter.\\\" PMs and designers both report functionally into their chiefs but are dotted-lined into the engineering lead whose product line they're embedded in — a typical scale-up pattern that balances functional excellence with product-team velocity.\"\n },\n {\n \"slug\": \"orgchart-tech-startup\",\n \"diagram\": \"orgchart\",\n \"title\": \"Series-A tech startup org\",\n \"description\": \"Three-level org chart for a ~30-person Series-A startup — CEO with engineering, product, and ops directs, showing open roles and a board advisor.\",\n \"standard\": \"HR convention\",\n \"tags\": [\n \"orgchart\",\n \"startup\",\n \"hiring\",\n \"headcount\",\n \"series-a\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"orgchart \\\"Acme — Series A Team\\\"\\nceo: \\\"Jamie Torres\\\" | CEO [role: ceo]\\n cto: \\\"Raj Patel\\\" | CTO [role: cto]\\n lead_fe: \\\"Priya Nair\\\" | Eng Lead | Frontend [role: engineer]\\n eng1: \\\"Alex Kim\\\" | Senior Engineer [role: engineer]\\n eng2: \\\"Jordan Lee\\\" | Engineer [role: engineer, status: new]\\n open1: open \\\"TBH\\\" | Frontend Engineer [role: engineer]\\n lead_be: \\\"Omar Hassan\\\" | Eng Lead | Backend [role: engineer]\\n eng3: \\\"Yuki Tanaka\\\" | Staff Engineer [role: engineer]\\n draft1: draft \\\"TBH\\\" | Senior Engineer [role: engineer]\\n cpo: \\\"Ellen Wu\\\" | CPO [role: cpo]\\n pm1: \\\"Tyler Brooks\\\" | Product Lead | Core [role: product]\\n pm2: \\\"Suki Ito\\\" | Product Lead | Growth [role: product]\\n coo: \\\"Maria Santos\\\" | COO [role: ops]\\n fin1: \\\"Nour Ahmed\\\" | Finance Manager [role: ops]\\nadvisor adv1: \\\"Dr. Alan Ford\\\" | Board Advisor [role: advisor]\",\n \"notes\": \"## Scenario\\n\\nThe founder is preparing a hiring plan for the next two quarters and uses this chart in a board update. It shows the current team, the one confirmed open req (Frontend Engineer), one planned-but-not-recruiting slot (Staff Engineer backend), and the board advisor relationship. Indentation communicates reporting lines without drawing edges.\\n\\n## Annotation key\\n\\n- `id: \\\"Name\\\" | \\\"Title\\\" | \\\"Department\\\"` — a person node\\n- Indentation (2 spaces) — reporting hierarchy\\n- `open …` / `draft …` — unfilled / planned roles\\n- `advisor …` — external board or advisor relationship\\n- `[role: …]` — colour-coded by function\\n\\n## How to read\\n\\nThe single root is the CEO. Each two-space indent step moves one level down the reporting tree. Two kinds of \\\"ghost\\\" slots appear: `open` nodes (Frontend Engineer) are reqs you are actively hiring for; `draft` nodes (Staff Backend) are next-quarter plans. The advisor sits outside the tree — not in the reporting chain but formally associated with the org.\"\n },\n {\n \"slug\": \"pedigree-assisted-reproduction-ivf-donor-surrogate\",\n \"diagram\": \"pedigree\",\n \"title\": \"Assisted reproduction pedigree\",\n \"description\": \"Clinical pedigree showing IVF donor and surrogate context with a proband child and clearly separated biological and gestational participants.\",\n \"standard\": \"Bennett 2022\",\n \"tags\": [\n \"pedigree\",\n \"assisted-reproduction\",\n \"ivf\",\n \"donor\",\n \"surrogate\",\n \"proband\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"Assisted Reproduction Family\\\"\\n intended_father [male, unaffected]\\n intended_mother [female, unaffected]\\n egg_donor [female, evaluated]\\n surrogate [female, evaluated]\\n\\n intended_father -- egg_donor\\n embryo [unknown, pregnancy]\\n\\n intended_father -- intended_mother\\n child [female, unaffected, proband]\\n\\n surrogate -- intended_father\\n child [female, unaffected, proband]\",\n \"notes\": \"## Scenario\\n\\nAssisted reproduction cases need more than a simple parent-child line. This example keeps the clinical pedigree compact while labeling the relevant participants: intended parents, donor, surrogate, embryo, and proband.\\n\\n## Annotation key\\n\\n- `pregnancy` marks the embryo node.\\n- `evaluated` indicates participants evaluated in the genetics intake.\\n- Re-declaring `child` preserves the proband while documenting alternate family context.\"\n },\n {\n \"slug\": \"pedigree-brca1\",\n \"diagram\": \"pedigree\",\n \"title\": \"BRCA1 hereditary cancer (four-generation)\",\n \"description\": \"Four-generation BRCA1 pedigree distinguishing affected, carrier, and presymptomatic individuals — per NSGC standard for cascade testing and insurance pre-authorization.\",\n \"standard\": \"NSGC\",\n \"tags\": [\n \"BRCA\",\n \"four-generation\",\n \"carrier\",\n \"presymptomatic\",\n \"proband\",\n \"NSGC\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"BRCA1 Family — Hereditary Breast/Ovarian Cancer\\\"\\n I-1 [male, unaffected]\\n I-2 [female, affected, deceased]\\n I-1 -- I-2\\n II-1 [female, affected]\\n II-2 [male, unaffected]\\n II-3 [female, carrier]\\n II-1 -- II-4 [male, unaffected]\\n III-1 [female, affected, proband]\\n III-2 [male, unaffected]\\n III-3 [female, presymptomatic]\\n II-3 -- II-6 [male, unaffected]\\n III-6 [female, carrier]\\n III-7 [male, unaffected]\",\n \"notes\": \"## Scenario\\n\\nA genetic counselor documents a four-generation BRCA1 pedigree for a patient referred after a personal diagnosis of breast cancer at age 35. The NSGC-standard pedigree distinguishes affected, carrier, and presymptomatic individuals — critical for insurance pre-authorization and cascade testing recommendations for at-risk relatives.\\n\\n## Annotation key\\n\\n- `affected` — full fill; individual has been diagnosed with the condition\\n- `carrier` — half fill; individual carries the mutation but is currently asymptomatic\\n- `presymptomatic` — quarter fill or dot; positive genetic test but no clinical diagnosis yet\\n- `proband` — triangle marker; the individual who triggered clinical investigation\\n- `deceased` — diagonal slash through the symbol\\n\\n## How to read\\n\\nThe pattern of affected females across three generations (I-2, II-1, III-1) is the red flag for hereditary BRCA1. The proband (III-1) is the entry point. Her aunt (II-3) is a carrier who has already passed the mutation to III-6. The presymptomatic sibling (III-3) has tested positive but is not yet diagnosed — she receives enhanced surveillance recommendations.\"\n },\n {\n \"slug\": \"pedigree-cystic-fibrosis\",\n \"diagram\": \"pedigree\",\n \"title\": \"Cystic fibrosis (autosomal recessive)\",\n \"description\": \"Classic autosomal recessive cystic fibrosis pedigree with two carrier parents — illustrates the 25% recurrence risk for genetic counseling and patient education.\",\n \"standard\": \"NSGC\",\n \"tags\": [\n \"autosomal-recessive\",\n \"carrier\",\n \"Mendelian\",\n \"proband\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"CF family — autosomal recessive\\\"\\n I-1 [male, carrier]\\n I-2 [female, carrier]\\n I-1 -- I-2\\n II-1 [male, affected, proband]\\n II-2 [female, carrier]\\n II-3 [male, unaffected]\\n II-2 -- II-4 [male, carrier]\\n III-1 [female, affected]\\n III-2 [male, unaffected]\",\n \"notes\": \"## Scenario\\n\\nThe classic textbook pedigree for autosomal recessive inheritance — used in genetics courses, patient education, and clinical counseling to illustrate the 25% recurrence risk when both parents are carriers.\\n\\n## Annotation key\\n\\n- `carrier` — half-filled symbol; one normal allele and one mutant allele (Aa)\\n- `affected` — fully filled symbol; two mutant alleles (aa)\\n- `unaffected` — open symbol; either homozygous normal (AA) or carrier (Aa) — cannot distinguish clinically without testing\\n- `proband` — triangle arrow; the first affected individual identified in the family\\n\\n## How to read\\n\\nBoth Generation I parents are carriers. Their Generation II children follow the expected 1:2:1 Mendelian ratio: one affected son (proband), one carrier daughter, one unaffected son. In Generation III, carrier daughter II-2 married a carrier II-4 — producing another affected granddaughter (III-1), reinforcing the recessive inheritance pattern.\"\n },\n {\n \"slug\": \"pedigree-hemophilia\",\n \"diagram\": \"pedigree\",\n \"title\": \"Hemophilia A (X-linked recessive)\",\n \"description\": \"Three-generation hemophilia A pedigree showing X-linked recessive inheritance with carrier females and affected males per NSGC clinical notation.\",\n \"standard\": \"NSGC\",\n \"tags\": [\n \"x-linked\",\n \"carrier\",\n \"three-generation\",\n \"NSGC\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"pedigree \\\"Hemophilia A\\\"\\n I-1 [male, unaffected]\\n I-2 [female, carrier-x]\\n I-1 -- I-2\\n II-1 [male, affected]\\n II-2 [female, carrier-x]\\n II-3 [male, unaffected]\\n II-4 [female, unaffected]\\n II-2 -- II-5 [male, unaffected]\\n III-1 [male, affected]\\n III-2 [female, carrier-x]\\n III-3 [male, unaffected]\",\n \"notes\": \"## Scenario\\n\\nA genetic counselor documents a three-generation hemophilia A pedigree during a prenatal consultation. The X-linked recessive pattern — carrier females who show no symptoms but pass the mutated allele — must be clearly distinguished from affected males. NSGC standard notation is required for clinical records and insurance pre-authorization.\\n\\n## Annotation key\\n\\n- `carrier-x` — female carrier of an X-linked recessive allele; rendered as a circle with a centre dot per NSGC convention\\n- `affected` — fully filled symbol; individual expresses the condition\\n- `unaffected` — open (unfilled) symbol; no clinical presentation\\n- `proband` — the index case who prompted clinical referral (not used here, but add `proband` to any individual)\\n- `I-1 -- I-2` followed by indented children — defines a mating pair and their offspring\\n\\n## How to read\\n\\nGeneration I: unaffected father, carrier mother. Generation II: one affected son (II-1), one carrier daughter (II-2), two unaffected children. Generation III: carrier daughter II-2 married an unaffected man; they produced another affected son (III-1) and another carrier daughter (III-2) — demonstrating the classic X-linked skip-generation pattern where the trait disappears in daughters only to re-emerge in grandsons.\"\n },\n {\n \"slug\": \"pert-aoa-software-project\",\n \"diagram\": \"pert\",\n \"title\": \"Activity-on-arrow (AOA) network\",\n \"description\": \"The classic textbook PERT notation — numbered event circles, activities as labelled arrows, and dotted dummy activities auto-inserted at multi-predecessor merges. Written in the same activity-on-node DSL; Schematex builds and numbers the event graph.\",\n \"standard\": \"PMI PMBOK 7 + Moder 1983 — Activity-on-Arrow (ADM, legacy)\",\n \"tags\": [\n \"pert\",\n \"aoa\",\n \"activity-on-arrow\",\n \"critical-path\",\n \"education\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"pert\\ntitle: \\\"Software project (AOA)\\\"\\nlayout: aoa\\nunit: days\\n\\ntask A \\\"create schedule\\\" duration: 10\\ntask B \\\"buy hardware\\\" duration: 5\\ntask C \\\"programming\\\" duration: 20 after: A\\ntask D \\\"installation\\\" duration: 5 after: B\\ntask E \\\"conversion\\\" duration: 15 after: D\\ntask F \\\"test code\\\" duration: 20 after: C, E\\ntask G \\\"write manual\\\" duration: 15 after: E\\ntask H \\\"test system\\\" duration: 10 after: F\\ntask I \\\"training\\\" duration: 5 after: G\\ntask J \\\"user test\\\" duration: 10 after: H, I\",\n \"notes\": \"Before activity-on-node won, project networks were drawn **activity-on-arrow** (AOA / ADM): the *arrows* are the work and the *nodes* are events — the instants when activities start and finish. It's the form on Investopedia and in older textbooks, and it's what `layout: aoa` produces.\\n\\n**You still write activity-on-node.** The DSL is identical to every other PERT example — tasks, durations, `after:` dependencies. Schematex converts it: each activity gets a head event, and the events are numbered so every arrow runs from a lower id to a higher one (the classic *i-j* rule).\\n\\n**Dummy activities.** AOA can't show two activities merging into one without help, so wherever an activity has multiple predecessors a **dummy** (dotted, zero-duration arrow) is inserted. Here `test code` depends on both `programming` and `conversion`, and `user test` on both `test system` and `training` — each merge gets dummies that carry the dependency without representing real work.\\n\\n**The critical path is still computed.** The forward/backward pass runs on the event graph and the critical activities are drawn as bold red arrows: `create schedule → programming → test code → test system → user test` (70 days).\\n\\n**One caveat.** AOA can only express finish-to-start logic — there's no way to draw a start-to-start or finish-to-finish relationship as an arrow-between-events. If your network uses SS/FF/SF or lag, those are flattened to FS with a warning. For real scheduling, prefer the default `network` (AON) layout; reach for `aoa` when you need to match a textbook figure.\"\n },\n {\n \"slug\": \"pert-migration-timescaled\",\n \"diagram\": \"pert\",\n \"title\": \"Time-scaled migration plan (network-Gantt)\",\n \"description\": \"A data-centre migration in the time-scaled layout — x-position proportional to Early Start, width proportional to duration, with a unit time axis. Exercises start-to-start and finish-to-finish dependencies, lag/lead, a milestone, and lane packing.\",\n \"standard\": \"PMI PMBOK 7 + Moder 1983 (AON/PDM)\",\n \"tags\": [\n \"pert\",\n \"cpm\",\n \"timescaled\",\n \"gantt\",\n \"dependencies\",\n \"milestone\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pert\\ntitle: \\\"Data-centre migration\\\"\\nunit: days\\nlayout: timescaled\\n\\ntask A \\\"Inventory systems\\\" duration: 5\\ntask B \\\"Stakeholder review\\\" duration: 6 after: A SS+1\\ntask C \\\"Vendor selection\\\" duration: 8 after: A, B\\ntask D \\\"Architecture\\\" duration: 10 after: C\\ntask E \\\"Procurement\\\" duration: 12 after: C+2\\ntask F \\\"Code refactor\\\" duration: 15 after: D\\ntask G \\\"Pilot env\\\" duration: 5 after: E, F FF\\ntask H \\\"Pilot run\\\" duration: 7 after: G\\ntask I \\\"Cutover\\\" milestone after: H\\ntask J \\\"Hypercare\\\" duration: 5 after: I\",\n \"notes\": \"`layout: timescaled` is the bridge between the network view and a Gantt chart. Each activity's **x-position is proportional to its Early Start** and its **width is proportional to its duration**, with a unit time axis along the bottom — so distance reads as time.\\n\\n**Full PDM dependencies.** This network uses every relationship type beyond the default finish-to-start. `B after: A SS+1` is start-to-start with a 1-day lag (stakeholder review begins a day into the inventory). `E after: C+2` is FS with a 2-day lag (procurement waits two days after vendor selection finishes). `G after: ... F FF` is finish-to-finish (the pilot environment must be ready *when* the code refactor finishes, not after it). Each non-FS edge is labelled on the connector (`SS+1d`, `FS+2d`, `FF`).\\n\\n**Milestones and lane packing.** `Cutover` is declared with the `milestone` flag — a zero-duration checkpoint drawn as a diamond at its scheduled date. To avoid overlaps, activities are greedily packed into horizontal lanes by start time, and task names sit above their bars (Gantt convention) so long labels never overflow a short bar.\\n\\n**Still computed, still critical-aware.** Even in the time-scaled view the critical path is highlighted in red and slack is shown on each bar. `Procurement` (E) carries 6 days of slack and renders in blue, visibly off the critical chain `A → C → D → F → G → H → I → J`.\"\n },\n {\n \"slug\": \"pert-product-launch\",\n \"diagram\": \"pert\",\n \"title\": \"Q3 product launch PERT/CPM network\",\n \"description\": \"A seven-task product-launch schedule where the engine computes every Early/Late Start & Finish, total slack, and the critical path (A → C → D → E → G) automatically — the canonical activity-on-node network with the six-field box.\",\n \"standard\": \"PMI PMBOK 7 + Moder 1983 (AON/PDM)\",\n \"tags\": [\n \"pert\",\n \"cpm\",\n \"critical-path\",\n \"schedule\",\n \"project-management\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"pert\\ntitle: \\\"Q3 Product Launch\\\"\\nunit: days\\n\\ntask A \\\"Market research\\\" duration: 5\\ntask B \\\"Design mockups\\\" duration: 8 after: A\\ntask C \\\"Backend API\\\" duration: 15 after: A\\ntask D \\\"Frontend build\\\" duration: 10 after: B, C\\ntask E \\\"QA / testing\\\" duration: 5 after: D\\ntask F \\\"Marketing collateral\\\" duration: 7 after: B\\ntask G \\\"Launch event\\\" duration: 2 after: E, F\",\n \"notes\": \"This is what separates Schematex's `pert` engine from a drag-and-drop \\\"PERT chart maker\\\": you write only the tasks, durations, and dependencies — the schedule is *computed*.\\n\\n**The six-field box.** Each activity renders as the canonical 3×2 PERT/CPM rectangle: Early Start / Duration / Early Finish on top, the task name and id in the middle, and Late Start / Slack / Late Finish on the bottom. Those four schedule fields are never typed by hand — a forward pass walks the network to find ES/EF, a backward pass finds LS/LF, and total slack is `LS − ES`.\\n\\n**The critical path falls out of the math.** Any activity with zero slack is on the critical path and is drawn in red: `A → C → D → E → G`. Here `C` (Backend API, 15 days) is the long pole — it dominates `B` (Design mockups, 8 days) at the `D` merge, so the schedule pivots on the backend, not the design. Change `C` to 6 days and the critical path shifts to run through `B` instead; the render updates because the computation does.\\n\\n**Parallel work, one merge.** `B` and `C` both start once research finishes, run concurrently, and re-converge at `D` (Frontend build). `F` (Marketing collateral) branches off `B` and carries slack — it can slip several days without moving the launch. The project duration, 37 days, is the maximum Early Finish over the terminal tasks, not simply the last task you declared.\"\n },\n {\n \"slug\": \"pert-swimlane-online-shop\",\n \"diagram\": \"pert\",\n \"title\": \"PERT swimlanes grouped by team\",\n \"description\": \"The same computed activity-on-node schedule, re-grouped into horizontal swimlanes by responsible team (Customer Account, Shopping Site, Shopping Cart, Testing) — the way Visual Paradigm and PMO templates present a project network.\",\n \"standard\": \"PMI PMBOK 7 + Moder 1983 (AON/PDM)\",\n \"tags\": [\n \"pert\",\n \"cpm\",\n \"swimlane\",\n \"critical-path\",\n \"project-management\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"pert\\ntitle: \\\"Online Shop Project\\\"\\nunit: days\\n\\ntask T1 \\\"Support Account Deletion\\\" duration: 3 lane: \\\"Customer Account\\\"\\ntask T2 \\\"Design a New Theme\\\" duration: 8 lane: \\\"Shopping Site\\\"\\ntask T3 \\\"Apply New Theme to the Site\\\" duration: 15 after: T2 lane: \\\"Shopping Site\\\"\\ntask T4 \\\"Improve Searching\\\" duration: 7 after: T3 lane: \\\"Shopping Site\\\"\\ntask T5 \\\"Enhance Shopping Cart Functionality\\\" duration: 8 after: T2 lane: \\\"Shopping Cart\\\"\\ntask T6 \\\"Enhance Shopping Cart Checkout\\\" duration: 6 after: T5 lane: \\\"Shopping Cart\\\"\\ntask T7 \\\"Ready Testing Environment\\\" duration: 2 after: T1, T4, T6 lane: \\\"Testing\\\"\\ntask T8 \\\"Test Online Shop\\\" duration: 8 after: T7 lane: \\\"Testing\\\"\",\n \"notes\": \"A flat network answers \\\"what's the critical path?\\\"; a swimlane network also answers \\\"who owns what?\\\". Add `lane: \\\"…\\\"` to any task and the diagram re-groups into horizontal bands — by team, phase, or owner — without changing a single number in the schedule.\\n\\n**Same engine, different presentation.** This is still pure activity-on-node: the forward/backward pass runs exactly as it would without lanes, so the critical path `T2 → T3 → T4 → T7 → T8` and every slack value are identical to the ungrouped layout. Lanes are a *view*, not a computation — they activate automatically the moment any task declares one.\\n\\n**Reading the bands.** Lanes appear in first-declared order, each as a banded row with a label gutter on the left. A task sits in the column for its dependency depth but the row for its team, so you can trace both the time order (left to right) and the ownership (top to bottom) at a glance. Dependencies that cross teams — `T1` (Customer Account) and `T4` (Shopping Site) and `T6` (Shopping Cart) all feeding `T7` (Testing) — render as orthogonal connectors hopping between bands, making hand-off points obvious.\\n\\n**Where this helps.** This is the format PMO templates and tools like Visual Paradigm use for status reviews, because a stakeholder can find their team's row instantly and see what it's waiting on and what's waiting on it.\"\n },\n {\n \"slug\": \"pert-three-point-estimation\",\n \"diagram\": \"pert\",\n \"title\": \"Three-point (PERT) estimation with variance\",\n \"description\": \"Durations written as optimistic/most-likely/pessimistic (O/M/P). The engine computes the beta-distribution expected duration te = (O+4M+P)/6 per activity, the per-task variance, and the project-level standard deviation along the critical path.\",\n \"standard\": \"PMI PMBOK 7 — three-point (beta-PERT) estimation\",\n \"tags\": [\n \"pert\",\n \"three-point\",\n \"estimation\",\n \"variance\",\n \"critical-path\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"pert\\ntitle: \\\"Three-point project\\\"\\nunit: days\\ncritical-tolerance: 0.01\\n\\ntask A \\\"Spec\\\" duration: 2/3/5\\ntask B \\\"Build\\\" duration: 5/8/14 after: A\\ntask C \\\"Test\\\" duration: 3/4/6 after: B\\ntask D \\\"Deploy\\\" duration: 1/2/3 after: C\",\n \"notes\": \"PERT's original 1959 contribution wasn't the box — it was handling *uncertainty* in durations. Write a duration as `O/M/P` (optimistic / most-likely / pessimistic) and the engine treats it as a beta-PERT estimate.\\n\\n**Expected duration.** Each three-point activity collapses to its beta-distribution mean **te = (O + 4M + P) / 6**, which is what the Duration field shows. `Build` at `5/8/14` becomes `te = 8.5` — pulled above the most-likely 8 because the pessimistic tail (14) is fatter than the optimistic one (5). The whole forward/backward pass then runs on these `te` values, so the project duration here is ≈ 17.83 days, not an integer.\\n\\n**Variance and project risk.** Each activity also carries `σ² = ((P − O) / 6)²`, surfaced as a small `σ=…` annotation under the name and on a `data-pert-variance` attribute. Summed over the critical-path activities (under the classical independence assumption), the project standard deviation is ≈ 1.69 days — a one-line risk figure you can quote: \\\"≈68% chance of finishing within ±1.69 days of 17.83.\\\"\\n\\n**Why `critical-tolerance: 0.01`.** Once durations are fractional, accumulated floating-point error can give a truly-critical activity a slack of `0.0000001`. The tolerance treats anything within 0.01 of zero as critical, so the red path stays stable across runs. For all-integer projects you can leave it at the default of `0`.\"\n },\n {\n \"slug\": \"petri-arc-types-inhibitor-read-reset\",\n \"diagram\": \"petri\",\n \"title\": \"Petri net arc types\",\n \"description\": \"Petri net showing standard, inhibitor, read, reset, weighted arcs, capacity, and enabled-transition highlighting in one compact control example.\",\n \"standard\": \"Murata 1989 / ISO-IEC 15909\",\n \"tags\": [\n \"petri\",\n \"inhibitor\",\n \"read-arc\",\n \"reset-arc\",\n \"capacity\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"petri \\\"Arc Types\\\"\\nlayout: lr\\ntokens: auto\\nplace Idle *1\\nplace Busy\\nplace Fault\\nplace Permit *1\\nplace Buffer capacity: 3 tokens: 2\\ntransition Start\\ntransition Complete\\ntransition Reset\\nIdle -> Start\\nPermit -- Start\\nFault -o Start\\nBuffer -> Start weight: 2\\nStart -> Busy\\nBusy -> Complete\\nComplete -> Idle\\nFault => Reset\\nBusy -> Reset\\nReset -> Idle\",\n \"notes\": \"## Scenario\\n\\nPetri nets become much more expressive once arc types carry semantics. This example shows a start transition that requires permission, is inhibited by a fault, consumes two buffer tokens, and can be reset from a fault state.\\n\\n## Annotation key\\n\\n- `--` is a read arc: test without consuming.\\n- `-o` is an inhibitor arc: enabled only when the place is empty.\\n- `=>` is a reset arc: clear the source place when the transition fires.\"\n },\n {\n \"slug\": \"petri-classic-net\",\n \"diagram\": \"petri\",\n \"title\": \"The classic Petri net — concurrency with feedback\",\n \"description\": \"Murata's canonical place/transition net — one transition forks a token into two concurrent branches that a second transition joins, with a feedback place closing the loop. The engine marks which transitions are enabled in the current marking.\",\n \"standard\": \"Murata 1989 + ISO/IEC 15909-1 (place/transition net)\",\n \"tags\": [\n \"petri\",\n \"concurrency\",\n \"fork-join\",\n \"feedback\",\n \"enabled-transitions\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"petri \\\"Classic\\\"\\n place P1 *1\\n place P2\\n place P3 *2\\n place P4 *1\\n transition T1\\n transition T2\\n P1 -> T1\\n T1 -> P2\\n T1 -> P3\\n P2 -> T2\\n P3 -> T2\\n T2 -> P4\\n P4 -> T1\",\n \"notes\": \"This is the net you find on the first page of every Petri-net text (Murata's 1989 survey, Wikipedia's figure 1): the smallest diagram that shows concurrency, synchronisation, and feedback at once.\\n\\n**One fork, one join.** Firing `T1` puts a token into both `P2` and `P3` — two branches now run concurrently. `T2` cannot fire until *both* branches deposit their tokens, so it is a synchronisation point (an AND-join).\\n\\n**The feedback place closes the loop.** `P4 -> T1` routes the result back as a back-edge, drawn around the layout so the cycle reads cleanly. In the current marking only `T1` is *enabled* (highlighted) — `T2` is dead because `P2` is empty until `T1` fires.\\n\\n**The render is downstream of the semantics.** Schematex isn't drawing shapes you positioned; it validated the bipartite structure, checked each transition's input places against the marking, and coloured the enabled one.\"\n },\n {\n \"slug\": \"petri-fire-sequence\",\n \"diagram\": \"petri\",\n \"title\": \"Firing a transition advances the marking\",\n \"description\": \"The same three-place net before and after firing — the `fire:` directive replays a transition, so the rendered marking is the state *after* the token moved from P1 to P2, and the engine now highlights T2 as the newly enabled transition.\",\n \"standard\": \"Murata 1989 (place/transition net firing rule)\",\n \"tags\": [\n \"petri\",\n \"firing-rule\",\n \"marking\",\n \"dynamics\",\n \"enabled-transitions\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"petri \\\"After fire: T1\\\"\\n place P1 *1\\n transition T1\\n place P2\\n transition T2\\n place P3\\n P1 -> T1\\n T1 -> P2\\n P2 -> T2\\n T2 -> P3\\n fire: T1\",\n \"notes\": \"Most text-to-diagram tools draw a Petri net as static shapes. Schematex *runs* it.\\n\\n**The firing rule, applied.** The net is declared with one token in `P1`. The `fire: T1` directive tells the engine to apply T1's firing — consume one token from each input place (`P1`), produce one in each output place (`P2`). What you see rendered is the marking **after** that step: the token now sits in `P2`.\\n\\n**Enablement is recomputed.** With the token in `P2`, `T1` is now dead (its input `P1` is empty) and `T2` is the *enabled* transition (highlighted). Chain more steps — `fire: T1, T2` — to walk the net forward and watch the token travel P1 → P2 → P3.\\n\\nThis is the difference between a drawing and a model: the diagram is a *function of* the computed marking, not something you hand-positioned.\"\n },\n {\n \"slug\": \"petri-mutual-exclusion\",\n \"diagram\": \"petri\",\n \"title\": \"Mutual exclusion with a shared resource\",\n \"description\": \"The canonical concurrency pattern as a Petri net — two processes competing for a single Mutex token. Either process may enter its critical section, but the shared token guarantees they never do so at the same time. Both entry transitions show as enabled until one fires and consumes the resource.\",\n \"standard\": \"Murata 1989 / ISO-IEC 15909-1 (place/transition net)\",\n \"tags\": [\n \"petri\",\n \"concurrency\",\n \"mutual-exclusion\",\n \"synchronization\",\n \"formal-methods\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"petri \\\"Mutual Exclusion — two processes, one resource\\\"\\n place idleA *1 \\\"A idle\\\"\\n place idleB *1 \\\"B idle\\\"\\n place mutex *1 \\\"resource\\\"\\n place critA \\\"A critical\\\"\\n place critB \\\"B critical\\\"\\n transition enterA\\n transition exitA\\n transition enterB\\n transition exitB\\n idleA -> enterA\\n mutex -> enterA\\n enterA -> critA\\n critA -> exitA\\n exitA -> idleA\\n exitA -> mutex\\n idleB -> enterB\\n mutex -> enterB\\n enterB -> critB\\n critB -> exitB\\n exitB -> idleB\\n exitB -> mutex\",\n \"notes\": \"Mutual exclusion is the \\\"hello world\\\" of concurrency theory, and a Petri net states it more honestly than a flowchart can: the safety property is a structural fact about a single token, not a comment in the margin.\\n\\n**One token, two claimants.** The `mutex` place holds exactly one token. Both `enterA` and `enterB` are enabled — each has its process idle *and* the resource available — so the engine rings both green. The moment one fires, it consumes the mutex token, and the other entry transition is no longer enabled. There is no marking in which both `critA` and `critB` hold a token; that invariant is what \\\"mutual exclusion\\\" means.\\n\\n**Exit returns the resource.** `exitA` / `exitB` put the token back into `mutex` and the process back to idle, so the net cycles forever without ever violating the invariant — a *live* and *safe* net in Petri terminology.\\n\\n**Why the formalism earns its keep.** Drawn as two side-by-side flowcharts, the shared-resource constraint is invisible. Drawn as a Petri net, it is the single most important node in the diagram. That is the whole pitch: the model carries the property, and the renderer shows you which moves are currently legal.\"\n },\n {\n \"slug\": \"petri-producer-consumer\",\n \"diagram\": \"petri\",\n \"title\": \"Producer / consumer with a bounded buffer\",\n \"description\": \"The bounded-buffer producer/consumer pattern as a Petri net — complementary free/used slot places enforce the buffer size, a timed withdraw transition models the consumer's rate, and place capacity caps the buffer at three slots. Tokens flowing through free→used→free show backpressure as a structural property.\",\n \"standard\": \"Murata 1989 + Marsan 1995 (GSPN timed transitions)\",\n \"tags\": [\n \"petri\",\n \"concurrency\",\n \"producer-consumer\",\n \"bounded-buffer\",\n \"queueing\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"petri \\\"Producer / Consumer (bounded buffer)\\\"\\n place pReady *1 \\\"producer ready\\\"\\n place free *3 \\\"free slots\\\"\\n place used capacity: 3 \\\"used slots\\\"\\n place cReady *1 \\\"consumer ready\\\"\\n transition produce \\\"deposit\\\"\\n transition consume timed rate: 0.8 \\\"withdraw\\\"\\n pReady -> produce\\n free -> produce\\n produce -> used\\n produce -> pReady\\n used -> consume\\n cReady -> consume\\n consume -> free\\n consume -> cReady\",\n \"notes\": \"A bounded buffer is where queueing theory meets concurrency, and the Petri net version makes the backpressure mechanism explicit instead of hiding it in a counter variable.\\n\\n**Free and used slots are complementary places.** The `free` place starts with three tokens (three empty slots); `used` starts empty and is capped at `capacity: 3` (the dashed border). Every `produce` firing moves one token free→used; every `consume` firing moves one back used→free. Their sum is invariant — the buffer can never hold more than three items, and that bound is a structural property of the net, not a runtime check.\\n\\n**A timed consumer.** `consume` is a `timed` transition with a rate (λ = 0.8), rendered as a hollow box — the [GSPN](https://en.wikipedia.org/wiki/Stochastic_Petri_net) convention for a transition that fires after a stochastic delay. That is how you model a consumer that drains the buffer at a finite rate, the seed of any performance analysis.\\n\\n**Backpressure for free.** When `free` is empty (buffer full), `produce` loses its input token and is no longer enabled — the producer blocks until the consumer frees a slot. No `if buffer.full` branch; the net's enabling rule *is* the backpressure.\"\n },\n {\n \"slug\": \"petri-workflow-net\",\n \"diagram\": \"petri\",\n \"title\": \"Order-fulfilment workflow net (WF-net)\",\n \"description\": \"A van der Aalst workflow net — a single source place and single sink place bracket an AND-split/join that runs picking and invoicing concurrently before shipping. The engine detects the WF-net structure and reports it in the SVG description.\",\n \"standard\": \"van der Aalst 1998 workflow nets (a Murata place/transition net)\",\n \"tags\": [\n \"petri\",\n \"workflow\",\n \"wf-net\",\n \"and-split\",\n \"business-process\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"petri \\\"Order workflow\\\"\\n place in *1 \\\"received\\\"\\n transition split\\n place pick\\n place invoice\\n transition pack\\n transition bill\\n place packed\\n place billed\\n transition ship\\n place out \\\"shipped\\\"\\n in -> split\\n split -> pick\\n split -> invoice\\n pick -> pack\\n invoice -> bill\\n pack -> packed\\n bill -> billed\\n packed -> ship\\n billed -> ship\\n ship -> out\",\n \"notes\": \"A *workflow net* is the Petri-net dialect business-process people actually use: exactly one **source** place (no incoming arcs — where a case enters) and one **sink** place (no outgoing arcs — where it leaves). Schematex detects this structure and notes it in the diagram's `<desc>`.\\n\\n**Concurrency by construction.** `split` forks the order into a `pick` branch and an `invoice` branch — warehouse and finance work in parallel. `ship` is the AND-join: it needs both `packed` and `billed`, so an order can't ship before it's been both packed and billed. No status flags, no polling — the net enforces the ordering.\\n\\n**Why not a flowchart?** A flowchart would draw the same boxes but couldn't express \\\"these two run concurrently and rejoin\\\" without ambiguity. The Petri net's token flow makes the AND-split/join unambiguous and analysable. This is the same reduction BPMN uses internally.\"\n },\n {\n \"slug\": \"phylo-bacterial-diversity\",\n \"diagram\": \"phylo\",\n \"title\": \"Bacterial diversity (ten-taxon tree)\",\n \"description\": \"Ten-taxon bacterial phylogenetic tree from a Newick/NHX string with bootstrap support values, three colored clade arcs, and a branch-length scale bar.\",\n \"standard\": \"Newick/NHX\",\n \"tags\": [\n \"Newick\",\n \"NHX\",\n \"bootstrap\",\n \"clade\",\n \"color-coding\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"phylo \\\"Bacterial Diversity\\\"\\n newick: \\\"((((Ecoli:0.1,Salmonella:0.12):0.05[&&NHX:B=98],Vibrio:0.2):0.08[&&NHX:B=85],((Bacillus:0.15,Staph:0.18):0.06[&&NHX:B=92],Listeria:0.22):0.1):0.15,((Myco_tb:0.3,Myco_leprae:0.28):0.12[&&NHX:B=100],(Strepto:0.25,Lactobacillus:0.2):0.08[&&NHX:B=78]):0.2);\\\"\\n clade Gamma = (Ecoli, Salmonella, Vibrio) [color: \\\"#1E88E5\\\", label: \\\"γ-Proteobacteria\\\"]\\n clade Firmi = (Bacillus, Staph, Listeria, Strepto, Lactobacillus) [color: \\\"#E53935\\\", label: \\\"Firmicutes\\\"]\\n clade Actino = (Myco_tb, Myco_leprae) [color: \\\"#43A047\\\", label: \\\"Actinobacteria\\\"]\\n scale \\\"substitutions/site\\\"\",\n \"notes\": \"## Scenario\\n\\nA microbiologist or bioinformatician pastes a Newick tree string exported from RAxML, IQ-TREE, or MEGA and immediately gets a publication-ready SVG with clade highlights and a branch-length scale bar — no manual layout required.\\n\\n## Annotation key\\n\\n- `newick: \\\"...\\\"` — standard Newick format tree string; branch lengths follow `:` after each taxon name\\n- `[&&NHX:B=98]` — NHX annotation; `B=` is the bootstrap support value (0–100), rendered on internal nodes\\n- `clade id = (taxon, ...)` — defines a named clade by listing its leaf members\\n- `[color: \\\"#hex\\\", label: \\\"...\\\"]` — colors the clade's subtree and adds a labeled arc\\n- `scale \\\"...\\\"` — draws a calibrated scale bar with the given unit label\\n\\n## How to read\\n\\nThe tree shows three major bacterial clades. Blue (γ-Proteobacteria): *E. coli*, *Salmonella*, and *Vibrio* cluster with 98% bootstrap support. Red (Firmicutes): *Bacillus*, *Staph*, *Listeria*, *Streptococcus*, and *Lactobacillus*. Green (Actinobacteria): the two *Mycobacterium* species form a highly supported clade (bootstrap 100). Branch lengths represent substitutions per site — longer branches indicate faster evolutionary rates.\"\n },\n {\n \"slug\": \"phylo-dendrogram-gene-expression\",\n \"diagram\": \"phylo\",\n \"title\": \"Gene expression clusters (cut into flat groups)\",\n \"description\": \"A hierarchical-clustering dendrogram of gene-expression samples, sliced at a chosen height so the continuous tree collapses into distinctly colored flat clusters with a dashed threshold line.\",\n \"standard\": \"Hierarchical clustering (cophenetic height)\",\n \"tags\": [\n \"phylo\",\n \"dendrogram\",\n \"clustering\",\n \"cut\",\n \"cophenetic\",\n \"fcluster\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"phylo \\\"Gene expression clusters\\\" [mode: dendrogram]\\n newick: \\\"(((A:1,B:1):2,C:3):2,(D:2,E:2):3);\\\"\\n cut 4\\n scale \\\"cluster distance\\\"\",\n \"notes\": \"## What this shows\\n\\nThe same tree the `phylo` engine draws for evolution, read instead as the output of **hierarchical agglomerative clustering** (Sokal & Michener 1958 — the form `scipy.cluster.hierarchy.dendrogram` produces). Each internal node sits at its **merge height**: the cophenetic distance at which its two child clusters fuse. Leaves align on a common baseline, branches are rectangular elbows, and a height axis lets you read off exactly how far apart any two leaves are before they first share a cluster — `(A, B)` join low and tight, while `(D, E)` only merge with the rest near the top.\\n\\nThe `cut 4` line is what makes this actionable. It slices the tree at height 4: every subtree that fuses below that line becomes one **flat cluster**, each painted a distinct color, with a dashed threshold line drawn across the chart. This is the dendrogram counterpart of choosing `k` clusters in `fcluster` — turning a continuous similarity tree into the discrete groups you actually act on.\"\n },\n {\n \"slug\": \"phylo-dendrogram-sample-clustering\",\n \"diagram\": \"phylo\",\n \"title\": \"Sample clustering dendrogram (no cut)\",\n \"description\": \"A bare hierarchical-clustering dendrogram with internal nodes placed at their merge height and a cluster-distance axis — the plain similarity tree before any flat-cluster threshold is applied.\",\n \"standard\": \"Hierarchical clustering (cophenetic height)\",\n \"tags\": [\n \"phylo\",\n \"dendrogram\",\n \"clustering\",\n \"cophenetic\",\n \"similarity\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"phylo \\\"Sample clustering\\\" [mode: dendrogram]\\n newick: \\\"(((A:1,B:1):2,C:3):2,(D:2,E:2):3);\\\"\\n scale \\\"cluster distance\\\"\",\n \"notes\": \"## What this shows\\n\\nThe plainest reading of a **hierarchical-clustering dendrogram**: five samples joined bottom-up, with each internal node placed at its **merge height** — the cophenetic distance at which its two child clusters fuse. Leaves align on a shared baseline and a cluster-distance axis runs down the side, so the vertical position of every join tells you how similar the samples beneath it are.\\n\\nUnlike a cladogram (topology only) or a phylogram (branch length = evolutionary distance), here the height of the merge *is* the message: samples that fuse low are alike, samples that only fuse near the top are distant. This example omits the `cut` directive on purpose — it is the raw similarity tree, before you commit to a threshold that would carve it into flat clusters.\"\n },\n {\n \"slug\": \"phylo-sars-cov-2-chronogram\",\n \"diagram\": \"phylo\",\n \"title\": \"SARS-CoV-2 variant chronogram\",\n \"description\": \"Chronogram-style phylogenetic tree for major SARS-CoV-2 variants with clade highlights and a year scale.\",\n \"standard\": \"Newick / phylogram conventions\",\n \"tags\": [\n \"phylo\",\n \"chronogram\",\n \"newick\",\n \"variants\",\n \"clades\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"phylo \\\"SARS-CoV-2 Variants\\\" [mode: chronogram, layout: rectangular, mrsd: \\\"2023\\\"]\\n newick: \\\"((Alpha:0.45,(Beta:0.35,Gamma:0.38):0.12):0.25,(Delta:0.42,(BA1:0.28,(BA2:0.18,XBB:0.12):0.1):0.22):0.3);\\\"\\n clade VOC = (Alpha, Beta, Gamma, Delta) [color: \\\"#1E88E5\\\", label: \\\"Early VOCs\\\", highlight: branch]\\n clade Omicron = (BA1, BA2, XBB) [color: \\\"#E53935\\\", label: \\\"Omicron lineages\\\", highlight: both]\\n scale \\\"years before 2023\\\"\",\n \"notes\": \"## Scenario\\n\\nChronograms use branch lengths as time. For variant surveillance, that means the horizontal distance conveys approximate divergence time rather than only genetic distance.\\n\\n## Annotation key\\n\\n- `mode: chronogram` and `mrsd` tell the renderer how to interpret branch lengths.\\n- `clade` highlights named groups from the Newick leaves.\\n- `scale` labels the time axis.\"\n },\n {\n \"slug\": \"pid-distillation-column-reboiler-condenser\",\n \"diagram\": \"pid\",\n \"title\": \"Distillation column with reboiler and condenser\",\n \"description\": \"P&ID for a distillation overhead loop with condenser, reflux drum, reflux pump, reboiler, and ISA instrument bubbles.\",\n \"standard\": \"ANSI/ISA-5.1 + ISO 10628\",\n \"tags\": [\n \"pid\",\n \"distillation\",\n \"column\",\n \"condenser\",\n \"reboiler\",\n \"instrumentation\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pid \\\"Distillation Column T-201\\\"\\n\\nequip T-201 : column_tray [tag: \\\"T-201\\\"]\\nequip E-201 : condenser [tag: \\\"Overhead Condenser\\\"]\\nequip D-201 : vessel_h [tag: \\\"Reflux Drum\\\"]\\nequip P-201 : pump_centrifugal [tag: \\\"Reflux Pump\\\"]\\nequip E-202 : reboiler [tag: \\\"Reboiler\\\"]\\nequip PSV-201 : valve_psv [tag: \\\"PSV-201\\\", set_pressure: \\\"150 psig\\\"]\\n\\nline L1 from T-201.top to E-201.shell_in [size: \\\"8in\\\", service: \\\"overhead vapor\\\", type: \\\"process\\\"]\\nline L2 from E-201.shell_out to D-201.in [size: \\\"8in\\\", service: \\\"condensate\\\", type: \\\"process\\\"]\\nline L3 from D-201.bottom to P-201.in [size: \\\"3in\\\", service: \\\"reflux\\\", type: \\\"process\\\"]\\nline L4 from P-201.out to T-201.reflux [size: \\\"3in\\\", service: \\\"reflux\\\", type: \\\"process\\\"]\\nline L5 from T-201.bottom to E-202.in [size: \\\"6in\\\", service: \\\"bottoms\\\", type: \\\"process\\\"]\\nline L6 from T-201.top to PSV-201.in [size: \\\"2in\\\", service: \\\"relief\\\", type: \\\"process_minor\\\"]\\n\\ninst PT-201 : field_discrete\\n measures T-201\\ninst LIC-201 : cr_shared\\n measures D-201\\ninst TIC-201 : cr_shared\\n measures T-201\",\n \"notes\": \"## Scenario\\n\\nDistillation columns are a canonical P&ID use case because the physical process and the control loops must be legible together. This example shows the main process path and three instrument bubbles without pretending to be a full plant drawing.\\n\\n## Annotation key\\n\\n- `equip` lines select ISO process equipment symbols.\\n- `line ... from ... to ...` connects equipment ports and carries line tags.\\n- `inst` declarations create ISA-5.1 instrument bubbles tied to measured equipment.\"\n },\n {\n \"slug\": \"pid-pump-flow-control\",\n \"diagram\": \"pid\",\n \"title\": \"Pump with flow control loop (P&ID)\",\n \"description\": \"Classic centrifugal pump pulling from an atmospheric tank, with a flow transmitter (FT-101), flow indicating controller (FIC-101), and a fail-closed pneumatic control valve — the minimum viable P&ID that every process engineer recognises at a glance.\",\n \"standard\": \"ANSI/ISA-5.1-2009 + ISO 10628-1:2014\",\n \"tags\": [\n \"pid\",\n \"isa-5.1\",\n \"flow-control\",\n \"centrifugal-pump\",\n \"control-valve\",\n \"instrument-loop\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"pid \\\"Water Pump Flow Control\\\"\\n\\nequip T-101 : tank_atm [tag: \\\"Feed Tank\\\"]\\nequip P-101 : pump_centrifugal [tag: \\\"Feed Pump\\\"]\\nequip V-101 : valve_control [actuator: \\\"diaphragm\\\", fail: \\\"FC\\\"]\\nequip V-100 : valve_gate [tag: \\\"Isolation\\\"]\\n\\nline L1 from T-101.bottom to P-101.in [size: \\\"4\\\\\\\"\\\", service: \\\"water\\\", type: \\\"process\\\"]\\nline L2 from P-101.out to V-101.in [size: \\\"4\\\\\\\"\\\", service: \\\"water\\\", type: \\\"process\\\"]\\nline L3 from V-101.out to dest [size: \\\"4\\\\\\\"\\\", type: \\\"process\\\"]\\n\\ninst FT-101 : field_discrete\\n measures L2\\ninst FIC-101 : cr_shared\\n controls V-101\\n\\nline s1 from FT-101 to FIC-101 [type: \\\"electric\\\"]\\nline s2 from FIC-101 to V-101 [type: \\\"pneumatic\\\"]\",\n \"notes\": \"The pump-with-flow-control loop is to P&ID what the \\\"hello world\\\" program is to software: every process engineer has drawn one, every piping textbook uses it as chapter one, and once you understand it you understand the grammar of every more complex diagram.\\n\\n**What the diagram shows.** T-101 is an atmospheric tank (dome-roof symbol, open to atmosphere). The centrifugal pump P-101 pulls fluid from the bottom nozzle and pushes it downstream through a 4-inch water service line. The flow transmitter FT-101 — a field-mounted discrete instrument, drawn as a plain circle per ISA-5.1 §4.1 — sits on the discharge line L2 and measures the volumetric flow rate. Its 4–20 mA electric signal travels to FIC-101, the flow indicating controller in the main control room (drawn as a circle with a horizontal line through it, indicating it is panel-mounted and has a display). FIC-101 computes the error between the setpoint and the measured flow and drives V-101, a diaphragm-actuated control valve, open or closed via a pneumatic signal. V-100 is a manual gate valve upstream — the isolation valve you close when you need to pull the pump for maintenance.\\n\\n**ISA-5.1 signal line types.** The two non-process lines in this diagram are drawn differently from the main pipe: the electric signal between FT-101 and FIC-101 is a dashed line (`stroke-dasharray: 6 4`), and the pneumatic signal between FIC-101 and V-101 is a solid line with small perpendicular slash marks at regular intervals. These are not stylistic choices — they are ISA-5.1 §5.2 mandatory line type codes. An instrument technician reading the diagram needs to know, at a glance, whether a run of wire failed or an air supply pressure dropped. The line type tells them which.\\n\\n**Fail-safe position.** V-101 is marked `fail: \\\"FC\\\"` — fail-closed. When the air supply to the diaphragm actuator is lost (instrument air header trips, tubing rupture), the spring return pushes the valve shut. This is the correct failure mode for a pump discharge valve: loss of control should stop flow, not open it fully. If this were a cooling-water valve on a reactor, you'd want fail-open instead. The choice of fail position is one of the first decisions in a safety instrumented system review (HAZOP, SIL assessment) and it belongs on the P&ID from day one.\\n\\n**Why not draw.io.** Process engineers currently draw P&IDs in AutoCAD P&ID, SmartPlant P&ID, or draw.io with stencil libraries — all of which require manual symbol placement and wiring. The Schematex DSL lets you describe the topology and generate a standards-compliant SVG. This is particularly useful when a process is described in prose (from a process description document or a licensor's PFD) and needs to be turned into a P&ID for HAZOP review — the conversion becomes a text transformation task that LLMs can assist with, producing a reviewable first draft rather than a blank canvas.\"\n },\n {\n \"slug\": \"pid-reactor-feed-system\",\n \"diagram\": \"pid\",\n \"title\": \"Reactor feed with multi-loop control and pressure safety (P&ID)\",\n \"description\": \"CSTR reactor system with centrifugal pump, shell-and-tube pre-heater, flow control on the feed line, temperature control on the product outlet, and a PSHH pressure switch interlock — four instrument loops in one diagram, covering the core vocabulary of ISA-5.1 P&ID engineering.\",\n \"standard\": \"ANSI/ISA-5.1-2009 + ISO 10628-1:2014\",\n \"tags\": [\n \"pid\",\n \"isa-5.1\",\n \"reactor\",\n \"heat-exchanger\",\n \"multi-loop\",\n \"pshh\",\n \"interlock\",\n \"safety\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pid \\\"High-Pressure Reactor Feed\\\"\\n\\nequip T-201 : tank_atm [tag: \\\"Raw Material Tank\\\"]\\nequip P-201 : pump_centrifugal [tag: \\\"Feed Pump P-201A/B\\\"]\\nequip E-201 : hx_shell_tube [tag: \\\"Feed Pre-heater\\\"]\\nequip R-201 : reactor_cstr [tag: \\\"Reactor R-201\\\"]\\nequip V-201 : valve_control [actuator: \\\"diaphragm\\\", fail: \\\"FC\\\"]\\nequip V-202 : valve_control [actuator: \\\"diaphragm\\\", fail: \\\"FO\\\"]\\nequip V-203 : valve_psv [set_pressure: \\\"150 psig\\\"]\\n\\nline L1 from T-201.bottom to P-201.in [size: \\\"6\\\\\\\"\\\", service: \\\"feed\\\", type: \\\"process\\\"]\\nline L2 from P-201.out to E-201.shell_in [size: \\\"6\\\\\\\"\\\", service: \\\"feed\\\", type: \\\"process\\\"]\\nline L3 from E-201.shell_out to V-201.in [size: \\\"6\\\\\\\"\\\", service: \\\"feed\\\", type: \\\"process\\\"]\\nline L4 from V-201.out to R-201.in [size: \\\"6\\\\\\\"\\\", service: \\\"feed\\\", type: \\\"process\\\"]\\nline L5 from R-201.out to V-202.in [size: \\\"4\\\\\\\"\\\", service: \\\"product\\\", type: \\\"process\\\"]\\n\\ninst FT-201 : field_discrete\\n measures L2\\ninst FIC-201 : cr_shared\\n controls V-201\\n\\ninst TT-201 : field_discrete\\n measures R-201\\ninst TIC-201 : cr_shared\\n controls V-202\\n\\ninst PT-201 : field_discrete\\n measures R-201\\ninst PSHH-201 : field_discrete\\n measures R-201\\n\\nline s1 from FT-201 to FIC-201 [type: \\\"electric\\\"]\\nline s2 from FIC-201 to V-201 [type: \\\"pneumatic\\\"]\\nline s3 from TT-201 to TIC-201 [type: \\\"electric\\\"]\\nline s4 from TIC-201 to V-202 [type: \\\"pneumatic\\\"]\\nline s5 from PT-201 to PSHH-201 [type: \\\"electric\\\"]\",\n \"notes\": \"Real process plants don't have one control loop — they have a web of them. This diagram shows a CSTR reactor system with four instrument loops and a safety instrument, which is about the minimum complexity for a unit operation that would appear in a HAZOP study. Understanding how to read this diagram cold is a core skill for every process, instrumentation, and safety engineer on the project team.\\n\\n**The process path.** Raw material is stored in T-201 (atmospheric tank). The centrifugal pump P-201A/B (the A/B suffix is conventional for spared pumps — one online, one standby) pulls from the bottom nozzle and pushes through 6-inch feed line L2 to the shell-and-tube heat exchanger E-201, which pre-heats the feed before it enters the reactor. From E-201, the line continues through the feed control valve V-201 into the reactor R-201. The reactor product exits through L5 and the product control valve V-202.\\n\\n**Loop 201 — flow control.** FT-201 (flow transmitter, field-mounted) sits on the pump discharge line L2 and sends a 4–20 mA signal to FIC-201 (flow indicating controller, control-room mounted, DCS shared — note the horizontal line through the circle). FIC-201 closes or opens V-201 to maintain the feed flow setpoint. V-201 is fail-closed: if instrument air is lost, the feed to the reactor stops. Starving a reactor on air loss is usually safer than flooding it.\\n\\n**Loop 201T — temperature control.** TT-201 (temperature transmitter) measures the reactor body temperature and signals TIC-201, which throttles V-202 — the product outlet valve — to regulate residence time and therefore heat generation in the reactor. V-202 is fail-open: losing air means the product continues to drain out, preventing dangerous temperature accumulation inside the vessel. The fail-safe position is always chosen by answering the question: \\\"which state causes less harm if control is lost?\\\"\\n\\n**Loop 201P — pressure monitoring and safety.** PT-201 is a field-mounted pressure transmitter — it sends the continuous pressure reading to the DCS historian. PSHH-201 is a pressure switch, high-high: a discrete field-mounted device that trips at the maximum allowable working pressure (MAWP). It is wired to the safety interlock system (SIS), not the DCS. The distinction matters: DCS loops control the process; SIS loops protect equipment and people. OSHA PSM (29 CFR 1910.119) requires the two to be functionally independent. V-203 is the pressure safety valve — a spring-loaded valve that opens automatically at the set pressure of 150 psig regardless of any control signal, providing the last line of mechanical protection.\\n\\n**Why P&ID, not PFD.** A process flow diagram (PFD) shows the same equipment but only the major process streams, mass balances, and operating conditions. A P&ID adds every instrument, every valve, every signal line, and every utility connection — it is the engineering document used by instrument engineers to write I/O lists, by safety engineers to perform HAZOP, and by construction teams to verify field installation. The DSL lets you build this level of detail from text, making it tractable for AI-assisted first drafts and version-controlled review cycles.\"\n },\n {\n \"slug\": \"prisma-dual-pipeline\",\n \"diagram\": \"prisma\",\n \"title\": \"PRISMA 2020 dual pipeline (databases + other methods)\",\n \"description\": \"PRISMA 2020 flow diagram in dual-pipeline mode — identification via databases and registers plus a second column for other methods (citation searching, hand searches, expert recommendations), merged into screening via a Y-junction.\",\n \"standard\": \"PRISMA 2020 (Page et al., BMJ 2021;372:n71)\",\n \"tags\": [\n \"prisma\",\n \"systematic-review\",\n \"dual-pipeline\",\n \"citation-search\",\n \"evidence-synthesis\",\n \"meta-analysis\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"prisma\\nmode: 2020-dual\\ntitle: Effect of yoga on chronic back pain — SR\\n\\nidentification:\\n databases:\\n n: 1234\\n sources: PubMed=600, Embase=450, Cochrane=184\\n duplicates-removed: 254\\n other:\\n n: 56\\n sources: citation-search=30, hand-search=20, expert-recommendation=6\\n\\nscreening:\\n records-screened: 1036\\n excluded:\\n n: 810\\n reasons: duplicate=120, irrelevant title=560, non-English=130\\n reports-sought: 226\\n reports-not-retrieved: 12\\n\\neligibility:\\n full-text-assessed: 214\\n excluded:\\n n: 191\\n reasons: wrong population=80, wrong intervention=60, wrong outcome=51\\n\\nincluded:\\n studies: 23\\n reports: 25\",\n \"notes\": \"## Scenario\\n\\nThe 2020 update to PRISMA added a **second identification pathway** for studies found outside formal database searches — citation chasing, hand-searching reference lists, and expert recommendations. Reviewers must report these separately and show both streams merging into a single screening process. The `prisma` engine renders the two columns side by side with a Y-junction merge.\\n\\n## Annotation key\\n\\n- **`mode: 2020-dual`** — adds the right-hand \\\"Identification via other methods\\\" column. The engine auto-detects dual mode whenever an `other:` block is present, so the explicit `mode` line is optional here.\\n- **`identification.other`** — its own `n:` total and `sources:` breakdown (citation search, hand search, expert recommendation).\\n- **`reports-sought:` / `reports-not-retrieved:`** — optional Screening detail lines for the retrieval step.\\n- **Y-junction merge** — the databases stream is the trunk; the other-methods stream drops and runs left to join it just above Screening.\\n\\n## Standard reference\\n\\nPage MJ, McKenzie JE, Bossuyt PM, et al. *The PRISMA 2020 statement.* BMJ 2021;372:n71, Figure 2 (dual-source variant).\"\n },\n {\n \"slug\": \"prisma-systematic-review\",\n \"diagram\": \"prisma\",\n \"title\": \"PRISMA 2020 systematic review (single pipeline)\",\n \"description\": \"Canonical PRISMA 2020 flow diagram for a systematic review using the dedicated prisma engine — records identified across four databases, deduplicated, screened, assessed for eligibility, and included, with exclusion side-boxes and mandatory n = counts.\",\n \"standard\": \"PRISMA 2020 (Page et al., BMJ 2021;372:n71)\",\n \"tags\": [\n \"prisma\",\n \"systematic-review\",\n \"meta-analysis\",\n \"research\",\n \"evidence-synthesis\",\n \"cochrane\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"prisma\\nmode: 2020-single\\ntitle: Effect of exercise on chronic low-back pain — SR\\n\\nidentification:\\n databases:\\n n: 1418\\n sources: PubMed=600, Embase=450, Cochrane=184, Web of Science=184\\n duplicates-removed: 318\\n\\nscreening:\\n records-screened: 1100\\n excluded:\\n n: 870\\n reasons: irrelevant title=750, non-English=120\\n\\neligibility:\\n full-text-assessed: 230\\n excluded:\\n n: 195\\n reasons: wrong population=80, wrong intervention=60, wrong outcome=55\\n\\nincluded:\\n studies: 35\\n reports: 38\",\n \"notes\": \"## Scenario\\n\\nA research librarian produces the PRISMA 2020 flow diagram for a Cochrane review submission. The journal **requires** the diagram in the exact four-row structure — Identification → Screening → Eligibility → Included — with the count `(n = …)` shown in every box and the excluded boxes itemizing reasons. With the dedicated `prisma` engine the librarian writes only counts and reasons; the rigid layout, the \\\"Records removed before screening\\\" side-box, and the exclusion side-boxes are produced automatically and are correct by construction.\\n\\n## Annotation key\\n\\n- **`mode: 2020-single`** — one Identification column (databases & registers). Use `mode: 2020-dual` to add the \\\"other methods\\\" column.\\n- **`identification.databases`** — `n:` is the mandatory total; `sources:` renders the per-database breakdown; `duplicates-removed:` splits out into the right-column \\\"Records removed before screening\\\" box automatically.\\n- **`screening` / `eligibility` `excluded:` blocks** — each has its own `n:` total and an optional `reasons:` breakdown rendered in a side-box to the right, connected by a horizontal arrow.\\n- **`included.studies` / `reports`** — one study can yield several reports, so both counts render.\\n\\n## How to read\\n\\nTop to bottom mirrors the PRISMA 2020 template exactly. The left capsule bands label the three canonical stages; the orange bar spans the Identification column group. Counts reconcile across stages (1418 − 318 = 1100 screened; 1100 − 870 = 230 assessed; 230 − 195 = 35 included) — the engine warns if they don't.\\n\\n## Standard reference\\n\\nPage MJ, McKenzie JE, Bossuyt PM, et al. *The PRISMA 2020 statement: an updated guideline for reporting systematic reviews.* BMJ 2021;372:n71. Template: [prisma-statement.org/prisma-2020-flow-diagram](https://www.prisma-statement.org/prisma-2020-flow-diagram).\"\n },\n {\n \"slug\": \"sequence-combined-fragments-gallery\",\n \"diagram\": \"sequence\",\n \"title\": \"Combined fragments gallery\",\n \"description\": \"UML sequence diagram demonstrating alt, opt, loop, par, critical, and ref frames in one realistic API interaction.\",\n \"standard\": \"OMG UML 2.5.1\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"combined-fragments\",\n \"alt\",\n \"loop\",\n \"par\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sequence \\\"API request with combined fragments\\\"\\n autonumber 1 1\\n actor Client\\n boundary API as \\\"API Gateway\\\"\\n control Auth\\n control Orders\\n database DB\\n queue Events\\n\\n Client ->+ API : POST /orders\\n ref over API, Auth : Validate token\\n alt [token valid]\\n API -> Auth : checkScopes()\\n Auth --> API : scopes\\n opt [idempotency key present]\\n API -> DB : lookupRequest(key)\\n DB --> API : previous result?\\n end\\n loop (1,3)\\n API -> Orders : reserveInventory()\\n Orders --> API : reservation result\\n end\\n par\\n API ->> Events : OrderRequested\\n and\\n API -> DB : persistOrder()\\n end\\n critical\\n DB --> API : commit ok\\n API -->- Client : 201 Created\\n end\\n else [token invalid]\\n API -->- Client : 401 Unauthorized\\n end\",\n \"notes\": \"## Scenario\\n\\nThis is a compact tour of UML sequence constructs that matter in real service diagrams. The request validates auth, checks idempotency, retries a reservation, publishes asynchronously, persists state, and returns a response.\\n\\n## Annotation key\\n\\n- `alt`, `opt`, `loop`, `par`, and `critical` are first-class combined fragments.\\n- `ref over API, Auth` references a reusable interaction instead of inlining it.\\n- `->>` distinguishes asynchronous event publication from blocking calls.\"\n },\n {\n \"slug\": \"sequence-login-flow\",\n \"diagram\": \"sequence\",\n \"title\": \"Login flow with an alt fragment\",\n \"description\": \"An authentication handshake across an actor, a Jacobson control object, and a database lifeline — synchronous calls open activation bars, a dashed reply returns the row, and an alt combined fragment splits the valid/invalid branches. A note records the session-cookie side effect.\",\n \"standard\": \"OMG UML 2.5.1 §17 (Interactions)\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"authentication\",\n \"alt-fragment\",\n \"activation\",\n \"lifeline-kinds\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sequence \\\"Login flow\\\"\\n actor User\\n participant Web as \\\"Web App\\\"\\n control Auth\\n database DB\\n User -> Web : submit(credentials)\\n activate Web\\n Web ->+ Auth : verify(credentials)\\n Auth ->+ DB : SELECT user\\n DB --> Auth : row\\n deactivate DB\\n alt [credentials valid]\\n Auth --> Web : token\\n Web --> User : 200 OK\\n else [invalid]\\n Auth --> Web : 401\\n Web --> User : error\\n end\\n deactivate Auth\\n deactivate Web\\n note over User, Web : session cookie set\",\n \"notes\": \"The canonical \\\"who calls whom, in what order\\\" diagram — and a good tour of the features that separate a UML sequence diagram from a generic flow.\\n\\n**Lifeline kinds carry meaning.** `actor`, `control`, and `database` render their distinct UML/Jacobson heads (stick figure, circled arrow, cylinder), so the diagram tells you *what kind of thing* each participant is, not just its name.\\n\\n**Activation and replies.** `->+` opens an activation bar on the callee; `--` draws the dashed reply that returns control (and the `row`). Bars nest, so you can see `Auth` is active while it waits on `DB`.\\n\\n**Branching is a real fragment.** The `alt` block with its `[credentials valid]` / `[invalid]` guards is a UML *combined fragment*, drawn as a labelled box spanning the lifelines — not two separate arrows you have to mentally group.\"\n },\n {\n \"slug\": \"sequence-microservices-saga\",\n \"diagram\": \"sequence\",\n \"title\": \"Microservices order saga\",\n \"description\": \"A distributed order-processing saga showing the parts of UML sequence notation that generic tools omit — a ref interaction-use frame, a par fragment for concurrent service calls, asynchronous event-bus messages, and an alt fragment with a compensating rollback on payment failure.\",\n \"standard\": \"OMG UML 2.5.1 §17 (Interactions)\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"microservices\",\n \"saga\",\n \"async\",\n \"event-driven\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sequence \\\"Order processing (saga)\\\"\\n actor Customer\\n participant Gateway as \\\"API Gateway\\\"\\n control Orders as \\\"Order Service\\\"\\n participant Payment as \\\"Payment Service\\\"\\n participant Inventory as \\\"Inventory Service\\\"\\n queue Bus as \\\"Event Bus\\\"\\n\\n Customer -> Gateway : POST /orders\\n Gateway ->+ Orders : createOrder()\\n ref over Orders, Bus : Validate cart & price\\n\\n par\\n Orders ->> Payment : charge(card)\\n and\\n Orders ->> Inventory : reserve(items)\\n end\\n\\n alt [payment captured && stock reserved]\\n Payment --> Orders : paid\\n Inventory --> Orders : reserved\\n Orders ->> Bus : OrderConfirmed\\n Orders -->- Gateway : 201 Created\\n Gateway --> Customer : confirmation\\n else [payment failed]\\n Orders ->> Inventory : release(items)\\n Orders ->> Bus : OrderCancelled\\n Orders -->- Gateway : 402 Payment Required\\n Gateway --> Customer : declined\\n end\",\n \"notes\": \"This is the case that separates a real UML engine from a flowchart with stick figures. A saga is concurrent, asynchronous, and has a compensating path — and Schematex has dedicated notation for each.\\n\\n**`ref` keeps the diagram composable.** \\\"Validate cart & price\\\" is its own interaction; inlining it here would bury the saga in detail. The `ref over Orders, Bus : …` frame references it instead — notation most text-to-diagram tools simply don't have.\\n\\n**`par` shows true concurrency.** The order service charges the card and reserves stock *at the same time*. The `par` fragment's two operands say these run concurrently, not in sequence — a distinction a top-to-bottom message list cannot express.\\n\\n**Async vs. reply arrows are not cosmetic.** `->>` (open head) marks fire-and-forget calls and event-bus publishes; `-->` (dashed) marks the replies that come back. Reading the arrowheads tells you which steps block and which don't.\\n\\n**The compensation lives in the `alt`.** When payment fails, the second operand *releases* the previously reserved inventory and emits `OrderCancelled` — the saga's rollback, drawn right beside the happy path instead of in a separate diagram.\"\n },\n {\n \"slug\": \"sequence-oauth-login\",\n \"diagram\": \"sequence\",\n \"title\": \"OAuth 2.0 authorization-code login\",\n \"description\": \"The canonical browser-based sign-in handshake as a UML sequence diagram — redirect to the auth server, user consent, code-for-token exchange, and an alt fragment for the success vs. failure branch, with activation bars tracking who is busy at each step.\",\n \"standard\": \"OMG UML 2.5.1 §17 (Interactions)\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"oauth\",\n \"authentication\",\n \"api\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sequence \\\"OAuth 2.0 Authorization Code\\\"\\n actor User\\n boundary Browser\\n control App as \\\"Web App\\\"\\n participant Auth as \\\"Auth Server\\\"\\n database DB as \\\"User Store\\\"\\n\\n User -> Browser : click \\\"Sign in\\\"\\n Browser ->+ App : GET /login\\n App --> Browser : 302 → Auth Server\\n Browser ->+ Auth : GET /authorize\\n Auth --> User : consent screen\\n User -> Auth : approve\\n Auth -->- Browser : 302 + auth code\\n\\n Browser ->+ App : GET /callback?code\\n App ->+ Auth : POST /token (code)\\n Auth ->+ DB : load user\\n DB -->- Auth : profile\\n Auth -->- App : access + refresh token\\n alt [token exchange ok]\\n App --> Browser : Set-Cookie: session\\n Browser --> User : signed in\\n else [exchange failed]\\n App --> Browser : 401 Unauthorized\\n Browser --> User : retry\\n end\\n deactivate App\",\n \"notes\": \"Almost every product ships this flow, and almost every whiteboard drawing of it is subtly wrong about *who is active when*. A sequence diagram makes the call order and the active spans explicit.\\n\\n**Lifeline kinds carry meaning.** The `boundary` Browser, the `control` App, and the `entity`/`database` user store render as their UML symbols, so a reviewer reads the architecture at a glance: the browser is the UI edge, the app orchestrates, the auth server and store are collaborators.\\n\\n**Activation bars track the redirect dance.** OAuth bounces the user between the app and the auth server twice. The `+`/`-` suffixes open and close execution-specification bars exactly where each party becomes busy and hands control back — the `Auth -->- Browser` reply both returns the auth code *and* closes the auth server's first activation.\\n\\n**The branch is a real fragment, not two diagrams.** The `alt` frame captures the success and failure paths in one place: a valid token exchange sets the session cookie; a failed one returns `401`. That is the single most common place sequence diagrams earn their keep — showing the unhappy path next to the happy one instead of hiding it.\"\n },\n {\n \"slug\": \"sequence-object-lifecycle\",\n \"diagram\": \"sequence\",\n \"title\": \"Object lifecycle — create, found, lost, destroy\",\n \"description\": \"The four UML interaction lifecycle markers in one short diagram — a create message draws its arrow to the new participant's box, a found message starts from a filled circle, a lost message ends at one, and destroy terminates a lifeline with an ✕.\",\n \"standard\": \"OMG UML 2.5.1 §17 (Interactions)\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"create\",\n \"destroy\",\n \"found-message\",\n \"lost-message\",\n \"lifecycle\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"sequence\\n participant Factory\\n Factory -> *Worker : «create»\\n o-> Worker : external trigger\\n Worker -x : fire-and-forget\\n destroy Worker\",\n \"notes\": \"UML interactions model not just messages but the *birth and death* of participants — the part most text-to-diagram tools skip. This tiny diagram shows all four markers.\\n\\n**Create.** `Factory -> *Worker` — the `*` prefix creates `Worker`; its arrow lands on the *side of the new participant's box*, which appears partway down rather than at the top, the UML convention for \\\"instantiated here.\\\"\\n\\n**Found and lost.** `o-> Worker` is a *found* message — it starts from a filled circle, meaning \\\"from outside the modelled scope\\\" (an external trigger). `Worker -x` is a *lost* message — it ends at a circle, a fire-and-forget whose receiver isn't shown.\\n\\n**Destroy.** `destroy Worker` terminates the lifeline with the ✕ marker, so the diagram shows exactly when the object ceases to exist.\"\n },\n {\n \"slug\": \"sequence-retry-timeout-circuit-breaker\",\n \"diagram\": \"sequence\",\n \"title\": \"Retry, timeout, and circuit breaker\",\n \"description\": \"UML sequence diagram for a gateway calling a payment service through a circuit breaker, with retry attempts, timeout handling, a break fragment for an open breaker, and an asynchronous fallback event.\",\n \"standard\": \"OMG UML 2.5.1\",\n \"tags\": [\n \"sequence\",\n \"uml\",\n \"retry\",\n \"timeout\",\n \"circuit-breaker\",\n \"resilience\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sequence \\\"Checkout payment resilience\\\"\\n autonumber 1 1\\n actor Client\\n boundary API as \\\"Checkout API\\\"\\n control Breaker as \\\"Circuit Breaker\\\"\\n participant Payment as \\\"Payment Provider\\\"\\n queue Jobs as \\\"Fallback Queue\\\"\\n\\n Client ->+ API : POST /checkout/pay\\n API -> Breaker : allowRequest()\\n alt [breaker closed]\\n Breaker --> API : permit\\n loop (1,3)\\n API ->+ Payment : authorize(amount)\\n alt [response before timeout]\\n Payment -->- API : auth result\\n break [authorized]\\n API -->- Client : 200 Authorized\\n end\\n else [timeout]\\n API -> Breaker : recordFailure(timeout)\\n API ->> Jobs : enqueue retry context\\n end\\n end\\n API -->- Client : 202 Pending verification\\n else [breaker open]\\n Breaker --> API : reject\\n API ->> Jobs : enqueue deferred payment\\n API -->- Client : 503 Retry later\\n end\",\n \"notes\": \"## Scenario\\n\\nA checkout API must protect itself from a slow or failing payment provider. The diagram makes the resilience policy reviewable: the gateway checks the breaker, retries bounded attempts, records timeouts, and falls back to asynchronous recovery instead of blocking the customer forever.\\n\\n## Annotation key\\n\\n- `loop (1,3)` documents the bounded retry policy.\\n- `alt` separates fast responses, timeouts, and open-breaker rejection.\\n- `break [authorized]` exits the retry loop once a successful authorization arrives.\\n- `->>` marks asynchronous fallback work queued outside the request path.\"\n },\n {\n \"slug\": \"sfc-bake-cool-concurrent\",\n \"diagram\": \"sfc\",\n \"title\": \"Bake & cool concurrent batch (SFC)\",\n \"description\": \"Simultaneous-branch SFC of a batch oven that bakes (15-minute D-qualified action) and cools the chamber jacket (5-minute L-qualified action) concurrently after a heat-up phase. Both branches must complete before the converge bar fires. Exercises the IEC 61131-3 §6.5.4 double-bar simultaneous divergence and time-parameterized action qualifiers.\",\n \"standard\": \"IEC 61131-3:2013 §6.5\",\n \"tags\": [\n \"sfc\",\n \"plc\",\n \"simultaneous-branch\",\n \"time-qualified\",\n \"batch-reactor\",\n \"oven\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"sfc \\\"Bake and cool concurrently\\\"\\n\\nvar BakeReady: bool\\nvar Bake_Done: bool\\nvar Cool_Done: bool\\n\\nstep S0 [initial]\\n\\nstep S_Heat\\n N Heater_On\\n\\nsim from: S_Heat: TRUE\\n branch:\\n step S_Bake\\n D Oven_Run T#15m\\n branch:\\n step S_Cool\\n L Cooler_On T#5m\\nmerge_to: S_Done: Bake_Done AND Cool_Done\\n\\nstep S_Done\\n N AnnounceDone\\n\\ntransition from: S0 to: S_Heat: BakeReady\\ntransition from: S_Done to: S0: NOT BakeReady\",\n \"notes\": \"A real batch reactor or industrial oven rarely runs phases one at a time — once the chamber is hot, you want to start the bake timer and the chamber-jacket cooling cycle simultaneously, because the cooling jacket protects equipment downstream and has its own independent timeout. SFC's simultaneous-branch construct captures this exactly: one entry transition fires both branches in lockstep, both branches run concurrently, and the chart waits at the convergence until *every* branch is done.\\n\\n**Two parallel horizontal lines = simultaneous bar.** The IEC 61131-3 §6.5.4 grammar uses **single-line bars** for alternative (OR-semantic) branches and **double-line bars** for simultaneous (AND-semantic) branches — visually distinct so an experienced eye can tell at a glance which kind of fork they're looking at. Schematex renders the double bar with a 4px gap between the two lines, exactly per spec.\\n\\n**The shared transition above and below.** Notice the `TRUE` transition just above the simultaneous divergence — that's the *single shared* condition that triggers the fork. Both branches start at once when `TRUE` fires (in this case unconditionally, because the heater step's job was already complete). At the bottom, the `Bake_Done AND Cool_Done` is the merge condition: the chart waits at the simultaneous convergence until *both* branch outcomes are asserted, then moves to S_Done. This shared-transition placement (above the divergence, below the convergence) is the inverse of how alternative branches work — alternative branches have their condition *between* the bar and each branch.\\n\\n**D vs L qualifiers — different time semantics.** S_Bake's `D Oven_Run T#15m` is a **time-delayed** action: when the step becomes active, wait 15 minutes, *then* start running `Oven_Run`. This matches a real oven: you want a soak interval before the heating element actually fires. S_Cool's `L Cooler_On T#5m` is **time-limited**: start running `Cooler_On` immediately on step entry, but stop after 5 minutes regardless. Both qualifiers render with a small bottom row inside the action block showing the duration literal — `T#15m` and `T#5m` — so anyone reviewing the chart can read the timing at a glance without cross-referencing a separate timing table.\\n\\n**Why concurrency matters here.** If the bake and cool ran sequentially, the total recipe time would be `15m + 5m = 20m` per batch. Running them in parallel cuts to `max(15m, 5m) = 15m`. Across 50 batches per shift, that's nearly an extra hour of throughput — the kind of optimization that's invisible in ladder-only programs but obvious in SFC. The reason most plants don't have it: the engineer didn't have a graphical sequential language in their toolbox. Schematex fills that gap.\"\n },\n {\n \"slug\": \"sfc-bottle-filling\",\n \"diagram\": \"sfc\",\n \"title\": \"Bottle filling sequence (SFC)\",\n \"description\": \"Three-step sequential function chart for a bottle-filling station — idle with valve closed, fill while tank level rises, signal done. Exercises the IEC 61131-3 §6.5 initial-step double border, N-qualified actions, and condition expressions on transitions.\",\n \"standard\": \"IEC 61131-3:2013 §6.5\",\n \"tags\": [\n \"sfc\",\n \"plc\",\n \"iec-61131-3\",\n \"sequential-control\",\n \"packaging\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"sfc \\\"Bottle Filling\\\"\\n\\nvar StartBtn: bool\\nvar TankLevel: real\\nvar DoneBtn: bool\\n\\nstep S0 [initial]\\n N FillValve_Closed\\n\\nstep S1 [label: \\\"Filling\\\"]\\n N FillValve_Open\\n\\nstep S2 [label: \\\"Done\\\"]\\n N Confirm_Done\\n\\ntransition from: S0 to: S1: StartBtn\\ntransition from: S1 to: S2: TankLevel >= 80.0\\ntransition from: S2 to: S0: DoneBtn\",\n \"notes\": \"Sequential function charts are the most underused PLC language. Most automation code is written in ladder, but ladder describes per-scan combinational logic — it can't express \\\"we're in the *fill* phase right now and the next phase begins when the tank hits 80%.\\\" Engineers fake state machines in ladder using auxiliary boolean tags (one per state, set/reset by transition logic), and the result is unreadable six months later. SFC makes the state machine explicit: each step is a phase, each transition is a boolean condition that triggers the handoff.\\n\\n**Three steps, three phases.** S0 is the **initial step** — drawn with a double border per IEC 61131-3 §6.5.1.2, marking the entry point when the program starts. While S0 is active, its single N-qualified action `FillValve_Closed` runs every scan. The chart sits in S0 until the StartBtn transition fires; then control moves to S1.\\n\\n**S1 — filling phase.** While in S1, the action `FillValve_Open` runs every scan. The chart waits in S1 until the transition `TankLevel >= 80.0` evaluates true. Note that condition is just plain text — Schematex doesn't parse or evaluate IEC structured-text expressions; it stores them verbatim and renders them next to the bar. The PLC runtime is what actually evaluates.\\n\\n**S2 — done phase.** S2 holds with `Confirm_Done` running until the operator presses the DoneBtn (or whatever signals the cycle complete) — at which point we loop back to S0. Because S0 is not linearly adjacent to S2 in the body, this transition renders as a **margin jump arrow** on the side of the chart, with the target step id and the condition both labeled.\\n\\n**N qualifier — non-stored.** The `N` letter on each action means *non-stored*: the action runs only while its owning step is active, and stops automatically when the step deactivates. This is by far the most common qualifier — about 80% of real SFC actions use it. The SFC standard supports ten others (S/R for stored, L/D for time-limited/delayed, P for one-scan pulses, etc.) but for this example N is exactly right.\\n\\n**Why this is SFC and not a flowchart.** A flowchart of the same machine would show diamond decisions (\\\"is start pressed? if yes, ...\\\") and you'd lose the explicit \\\"we're *in* phase X\\\" semantics. SFC's active-step token model — one step holds the token at any moment, transitions move it — is the formal definition of *cyclic sequential control*, and it maps directly to how real PLC scan engines execute. When you bring this diagram to a code review with the maintenance team, they'll instantly recognize the pattern.\"\n },\n {\n \"slug\": \"sfc-order-routing-alt\",\n \"diagram\": \"sfc\",\n \"title\": \"Order routing — express vs standard shipping (SFC)\",\n \"description\": \"Alternative-branch SFC of an order-fulfillment routing decision. After picking the product, exactly one branch fires per scan based on the leftmost-true entry transition (priority 1 = express shipping first). Both branches converge to a common shipping step. Exercises the IEC 61131-3 §6.5.4 single-bar OR semantics, branch priority annotations, and per-branch entry/exit transitions.\",\n \"standard\": \"IEC 61131-3:2013 §6.5\",\n \"tags\": [\n \"sfc\",\n \"plc\",\n \"alternative-branch\",\n \"priority\",\n \"routing\",\n \"e-commerce\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"sfc \\\"Order routing\\\"\\n\\nvar ProductOrdered: bool\\nvar IsExpressShipping: bool\\nvar IsStandardShipping: bool\\nvar Shipped: bool\\n\\nstep S0 [initial]\\n\\nstep S_Pick\\n N PickFromBin\\n\\nalt from: S_Pick:\\n branch [priority: 1]:\\n transition: IsExpressShipping\\n step S_Express\\n N PrepExpressBox\\n transition: TRUE\\n branch [priority: 2]:\\n transition: IsStandardShipping\\n step S_Standard\\n N PrepStandardBox\\n transition: TRUE\\nmerge_to: S_Ship\\n\\nstep S_Ship\\n N CarrierPickup\\n\\ntransition from: S0 to: S_Pick: ProductOrdered\\ntransition from: S_Ship to: S0: Shipped\",\n \"notes\": \"A modern fulfillment center handles both express (next-day) and standard (3–5 day) shipping on the same physical line, with the same picking robots and the same carrier-pickup conveyor. The only divergence is the boxing step: express boxes are different sizes, use rigid corrugate, and get extra tracking labels. SFC's alternative branch is the right shape for this: one step (picking) splits into two paths (express boxing OR standard boxing) and they converge back to a common end step (carrier pickup).\\n\\n**Single horizontal bar = alternative.** IEC 61131-3 §6.5.4 uses a **single horizontal line** for alternative (OR-semantic) divergence and convergence. Visually it's the simpler cousin of the double-bar simultaneous fork; semantically it's the opposite — only *one* branch fires per scan, picked by which entry transition's condition evaluates true first under the priority order.\\n\\n**Priority annotation matters.** Both branches have `[priority: N]` markers — express is priority 1, standard is priority 2. If both `IsExpressShipping` and `IsStandardShipping` were somehow true at the same time (a bug, but a common one in early integration), the priority forces the express path. The renderer puts a small red number near each branch entry to make the priority visible at review time.\\n\\n**Per-branch entry and exit transitions.** Inside each branch, there are two `transition: ...` lines — the first is the **entry transition** (fires when control reaches the divergence bar; renders between the bar and the first step in that branch), and the second is the **exit transition** (fires when the branch's last step completes; renders between that step and the convergence bar). Most exit transitions are `TRUE` (unconditional) because the *step* itself is what's gating the work — once the step completes, you want to leave the branch. The entry transitions are where the actual decision logic lives.\\n\\n**Why not flowchart?** A flowchart of this would render the routing as a diamond with two branches and labels on each branch. You'd lose the explicit step semantics — in flowchart, the diamond *is* the decision point and there's no notion of \\\"the picking step is currently active and the next step depends on shipping type.\\\" That distinction matters for PLC code: while the picking step is active, the picking robot is physically holding the product, and you need to know exactly when the routing decision happens (at step exit, not step entry) to coordinate the conveyor handoff. SFC's \\\"step active → transition → next step active\\\" semantics are what real PLC scan engines do; flowchart's diamond/box semantics are not.\\n\\n**The shared S_Ship destination.** Both branches converge to S_Ship, where `CarrierPickup` runs. This is one of the strengths of alternative-branch SFC: the post-routing step is shared infrastructure, drawn exactly once. If you moved to multiple destinations (e.g. express has its own carrier door, standard has another), you'd skip the convergence and let each branch end at its own terminal step — also a valid SFC pattern.\"\n },\n {\n \"slug\": \"sld-commercial-solar-pv\",\n \"diagram\": \"sld\",\n \"title\": \"Commercial solar PV interconnection\",\n \"description\": \"Single-line diagram for a commercial PV array feeding a combiner, inverter, AC disconnect, production meter, and main switchboard.\",\n \"standard\": \"IEEE 315 / NEC 690\",\n \"tags\": [\n \"sld\",\n \"solar\",\n \"pv\",\n \"inverter\",\n \"interconnection\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"sld \\\"Commercial PV Interconnection\\\"\\nPV1 = solar [rating: \\\"250 kWdc\\\", label: \\\"PV Array\\\"]\\nCMB = hub [rating: \\\"600 Vdc\\\", label: \\\"DC Combiner\\\"]\\nDISC_DC = switch_load [rating: \\\"600 Vdc\\\", label: \\\"DC Disconnect\\\"]\\nINV = load [rating: \\\"200 kWac\\\", label: \\\"Grid-tie Inverter\\\"]\\nDISC_AC = switch_load [rating: \\\"480V 400A\\\", label: \\\"AC Disconnect\\\"]\\nMTR = watthour_meter [label: \\\"Production Meter\\\"]\\nMSB = bus [voltage: \\\"480V\\\", label: \\\"Main Switchboard\\\"]\\nUTIL = utility [voltage: \\\"480V\\\", label: \\\"Utility\\\"]\\n\\nPV1 -> CMB [cable: \\\"PV string conductors\\\"]\\nCMB -> DISC_DC\\nDISC_DC -> INV\\nINV -> DISC_AC\\nDISC_AC -> MTR\\nMTR -> MSB\\nUTIL -> MSB\",\n \"notes\": \"## Scenario\\n\\nCommercial PV one-lines have a recognizable chain: DC array, combiner, inverter, AC disconnect, meter, and point of interconnection. This example uses standard SLD equipment while preserving PV-specific ratings in labels.\\n\\n## Annotation key\\n\\n- `solar` marks the generation source.\\n- `hub` stands in for the combiner point.\\n- `watthour_meter` captures the production metering requirement.\"\n },\n {\n \"slug\": \"sld-data-center-2n-ups\",\n \"diagram\": \"sld\",\n \"title\": \"Data center 2N UPS single-line\",\n \"description\": \"Single-line diagram for a dual-path data center power train with utility feeds, UPS A/B, static transfer switch, and critical load panels.\",\n \"standard\": \"IEEE 315 / Uptime Institute topology convention\",\n \"tags\": [\n \"sld\",\n \"data-center\",\n \"ups\",\n \"2n\",\n \"sts\",\n \"critical-power\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sld \\\"Data Center 2N UPS\\\"\\nUTIL_A = utility [voltage: \\\"13.8kV\\\", label: \\\"Utility A\\\"]\\nUTIL_B = utility [voltage: \\\"13.8kV\\\", label: \\\"Utility B\\\"]\\nXFMR_A = transformer [rating: \\\"2500 kVA\\\", voltage: \\\"13.8kV/480V\\\", label: \\\"TX-A\\\"]\\nXFMR_B = transformer [rating: \\\"2500 kVA\\\", voltage: \\\"13.8kV/480V\\\", label: \\\"TX-B\\\"]\\nSWGR_A = bus [voltage: \\\"480V\\\", label: \\\"Switchgear A\\\"]\\nSWGR_B = bus [voltage: \\\"480V\\\", label: \\\"Switchgear B\\\"]\\nUPS_A = ups [rating: \\\"1 MW\\\", label: \\\"UPS A\\\"]\\nUPS_B = ups [rating: \\\"1 MW\\\", label: \\\"UPS B\\\"]\\nSTS = ats [rating: \\\"1600A\\\", label: \\\"Static Transfer Switch\\\"]\\nPDU_A = load [label: \\\"PDU A\\\"]\\nPDU_B = load [label: \\\"PDU B\\\"]\\nCRIT = load [label: \\\"Critical IT Load\\\"]\\n\\nUTIL_A -> XFMR_A\\nUTIL_B -> XFMR_B\\nXFMR_A -> SWGR_A\\nXFMR_B -> SWGR_B\\nSWGR_A -> UPS_A\\nSWGR_B -> UPS_B\\nUPS_A -> STS\\nUPS_B -> STS\\nSTS -> PDU_A\\nSTS -> PDU_B\\nPDU_A -> CRIT\\nPDU_B -> CRIT\",\n \"notes\": \"## Scenario\\n\\nData centers are sold on redundancy. A 2N power path has two independent sources and UPS chains so either side can carry the critical load. A one-line diagram makes that redundancy auditable.\\n\\n## Annotation key\\n\\n- Two utility and transformer paths stay separate until the transfer point.\\n- `ups` nodes show the energy-storage conversion stage.\\n- The transfer switch feeds two PDUs before the critical IT load.\"\n },\n {\n \"slug\": \"sld-generator-ats\",\n \"diagram\": \"sld\",\n \"title\": \"Generator + ATS backup power\",\n \"description\": \"Single-line diagram for a utility + emergency generator ATS transfer system feeding critical loads on a 480 V bus — per IEEE 315 for facility design review.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"ATS\",\n \"generator\",\n \"backup-power\",\n \"bus\",\n \"breaker\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sld \\\"Utility + Generator Backup\\\"\\nUTIL = utility [voltage: \\\"480V\\\", label: \\\"Utility\\\"]\\nGEN = generator [rating: \\\"500 kW\\\", voltage: \\\"480V\\\", label: \\\"Emergency Gen\\\"]\\nATS1 = ats [rating: \\\"800A\\\", label: \\\"ATS-1\\\"]\\nBUS1 = bus [voltage: \\\"480V\\\", label: \\\"Critical Load Bus\\\"]\\nCB1 = breaker [rating: \\\"200A\\\"]\\nCB2 = breaker [rating: \\\"200A\\\"]\\nL1 = load [rating: \\\"100A\\\", label: \\\"Critical Load 1\\\"]\\nL2 = load [rating: \\\"100A\\\", label: \\\"Critical Load 2\\\"]\\nUTIL -> ATS1\\nGEN -> ATS1\\nATS1 -> BUS1\\nBUS1 -> CB1\\nBUS1 -> CB2\\nCB1 -> L1\\nCB2 -> L2\",\n \"notes\": \"## Scenario\\n\\nA facility engineer draws this one-line during the design review of a data-center UPS bypass or hospital emergency power system. The single-line diagram (SLD) is the first document a utility inspector or commissioning engineer asks for — it must show every source, switching device, bus, and load path in a single horizontal view without wiring details.\\n\\n## Annotation key\\n\\n- `utility` — mains supply; drawn as the IEEE 315 utility symbol (three-line source)\\n- `generator` — diesel or gas genset; drawn as rotating-machine circle with winding symbol\\n- `ats` — Automatic Transfer Switch; drawn as the NEMA/IEEE transfer-switch symbol\\n- `bus` — horizontal bus bar; all connected devices share the same voltage rail\\n- `breaker` — molded-case or air circuit breaker; drawn as the IEEE 315 breaker symbol\\n- `load` — end-consumer device or feeder\\n- `UTIL -> ATS1` — directed line representing the power path from source to device\\n\\n## How to read\\n\\nTwo sources (utility and generator) feed into the ATS. The ATS selects the live source and connects it to the 480 V critical load bus. From the bus, two independently-fused circuit breakers (CB1, CB2) feed their respective critical loads. If utility power fails, the ATS senses the loss, the generator starts, and the ATS transfers within seconds — all without interrupting the bus downstream.\"\n },\n {\n \"slug\": \"sld-residential-iec-60364-consumer-unit\",\n \"diagram\": \"sld\",\n \"title\": \"Residential consumer unit — generic IEC 60364\",\n \"description\": \"Generic European residential consumer unit per IEC 60364 / EN 61439-3 — service head, isolator, type-AC main RCD, and per-circuit MCBs for lighting, sockets, kitchen, water heater, EV charger (with type-B RCBO), and outdoor circuit.\",\n \"standard\": \"IEC 60364 / EN 61439-3\",\n \"tags\": [\n \"sld\",\n \"residential\",\n \"iec-60364\",\n \"en-61439\",\n \"europe\",\n \"consumer-unit\",\n \"rcd\",\n \"rcbo\",\n \"mcb\",\n \"isolator\",\n \"ev-charger\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sld \\\"Residential Consumer Unit — IEC 60364\\\"\\nSERVICE = utility [voltage: \\\"230V\\\", label: \\\"Service head 230V/63A\\\"]\\nKWHM = watthour_meter [label: \\\"kWh meter\\\"]\\nISO = breaker [rating: \\\"63A 6kA\\\", label: \\\"Main isolator\\\"]\\nRCD = ground_fault [rating: \\\"63A / 30mA Type AC\\\", label: \\\"Main RCD\\\"]\\nCU = bus [voltage: \\\"230V\\\", label: \\\"Consumer-unit busbar\\\"]\\nMCB1 = breaker [rating: \\\"6A B-curve\\\", label: \\\"MCB lighting\\\"]\\nMCB2 = breaker [rating: \\\"16A B-curve\\\", label: \\\"MCB sockets ground floor\\\"]\\nMCB3 = breaker [rating: \\\"16A B-curve\\\", label: \\\"MCB sockets first floor\\\"]\\nMCB4 = breaker [rating: \\\"20A C-curve\\\", label: \\\"MCB kitchen ring\\\"]\\nMCB5 = breaker [rating: \\\"20A C-curve\\\", label: \\\"MCB water heater\\\"]\\nRCBO_EV = ground_fault [rating: \\\"32A / 30mA Type B\\\", label: \\\"RCBO EV charger\\\"]\\nMCB6 = breaker [rating: \\\"10A B-curve\\\", label: \\\"MCB outdoor\\\"]\\nL1 = load [label: \\\"Lighting circuit\\\"]\\nL2 = load [label: \\\"Sockets — ground floor\\\"]\\nL3 = load [label: \\\"Sockets — first floor\\\"]\\nL4 = load [label: \\\"Kitchen ring final\\\"]\\nL5 = load [label: \\\"Water heater 4.5 kW\\\"]\\nEV = load [label: \\\"EV charger 7.4 kW Mode 3\\\"]\\nL6 = load [label: \\\"Outdoor / garden\\\"]\\nSERVICE -> KWHM\\nKWHM -> ISO\\nISO -> RCD\\nRCD -> CU\\nCU -> MCB1\\nMCB1 -> L1 [cable: \\\"1.5 mm² Cu PVC\\\"]\\nCU -> MCB2\\nMCB2 -> L2 [cable: \\\"2.5 mm² Cu PVC\\\"]\\nCU -> MCB3\\nMCB3 -> L3 [cable: \\\"2.5 mm² Cu PVC\\\"]\\nCU -> MCB4\\nMCB4 -> L4 [cable: \\\"4 mm² Cu PVC\\\"]\\nCU -> MCB5\\nMCB5 -> L5 [cable: \\\"4 mm² Cu PVC\\\"]\\nCU -> RCBO_EV\\nRCBO_EV -> EV [cable: \\\"6 mm² Cu XLPE\\\"]\\nCU -> MCB6\\nMCB6 -> L6 [cable: \\\"2.5 mm² Cu XLPE\\\"]\",\n \"notes\": \"## Scenario\\n\\nA domestic electrical installer in any IEC 60364 jurisdiction — France (NF C 15-100), Germany (DIN VDE 0100), the United Kingdom (BS 7671), Italy (CEI 64-8), Australia / New Zealand (AS/NZS 3000), and most of the rest of the world outside the NEC — files this single-line as part of the *Certificat de Conformité* / *Elektroinstallationsattest* / *Electrical Installation Condition Report* required after a new installation or major alteration. EN 61439-3 is the European harmonized standard for *Distribution Boards intended to be operated by Ordinary persons* (DBO), and IEC 60364-4-41 governs the protection-against-shock chain (isolation → 30 mA RCD → branch protection). Unlike NEC residential practice where the *panel* lives as a leaf on the SLD with internals on a separate panel schedule, the IEC 60364 single-line is expected to expand the consumer unit's internal protection chain.\\n\\n## Annotation key\\n\\n- `utility [voltage:..., label: \\\"Service head…\\\"]` — the cut-out / service-fuse head where the distribution network terminates and the customer installation begins\\n- `watthour_meter` — utility-owned kWh meter (smart meter in most modern installations)\\n- `breaker [label: \\\"Main isolator\\\"]` — main switch / isolator that disconnects the entire installation, sized at or above the cut-out fuse rating\\n- `ground_fault [rating: \\\"…A / 30mA Type AC\\\", label: \\\"Main RCD\\\"]` — whole-installation residual-current device, 30 mA sensitivity, Type AC (the IEC 60364 default for circuits without significant DC residual content)\\n- `bus [voltage: \\\"230V\\\", label: \\\"Consumer-unit busbar\\\"]` — the internal busbar of the consumer unit, rendered as a horizontal rail to which every branch device connects\\n- `breaker [rating: \\\"…A B-curve\\\" or \\\"…A C-curve\\\", label: \\\"MCB …\\\"]` — branch *miniature circuit breaker*: B-curve (3–5 × In) for resistive / lighting / general-sockets circuits, C-curve (5–10 × In) for inductive loads (kitchen ring, immersion heater) — per IEC 60898-1\\n- `ground_fault [rating: \\\"32A / 30mA Type B\\\", label: \\\"RCBO EV charger\\\"]` — Type B RCBO is mandatory on EV charging circuits per IEC 60364-7-722 / HD 60364-7-722 because Mode-3 chargers can leak DC residual currents that blind a Type AC RCD\\n- `load` — the final circuit served by each MCB / RCBO\\n- `[cable: \\\"… mm² Cu PVC|XLPE\\\"]` — conductor cross-sectional area, copper, with PVC insulation for indoor cables and XLPE for outdoor / EV runs\\n\\n## How to read\\n\\nThe service head delivers single-phase 230 V at the cut-out fuse rating (63 A here). The kWh meter records consumption, then the main isolator gives a single-action means of disconnecting the entire installation for maintenance. Downstream of the isolator the main RCD provides shock protection at 30 mA Type AC for the bulk of branch circuits; from the consumer-unit busbar, six MCBs feed lighting, two socket circuits, a kitchen ring, a water heater, and an outdoor circuit. The EV charger does not share the main RCD — IEC 60364-7-722 requires a Type B RCBO on the charger circuit because the Mode-3 charge controller can produce smooth DC residual currents that a Type AC RCD cannot detect, leaving people unprotected against shock during a DC fault. Cable sizes scale with the MCB rating per the relevant national reference method (1.5 mm² for 6 A lighting, 2.5 mm² for 16 A sockets, 4 mm² for 20 A kitchen / heater, 6 mm² for the 32 A EV charger). An inspector reads the diagram top-down to verify the protection chain and the discrimination between the main RCD and the EV-circuit RCBO.\"\n },\n {\n \"slug\": \"sld-residential-rebt-cgmp\",\n \"diagram\": \"sld\",\n \"title\": \"Residential CGMP — Spanish REBT vivienda\",\n \"description\": \"Cuadro General de Mando y Protección for a Spanish residence per REBT ITC-BT-17 — acometida, contador/ICP, IGA, diferencial Tipo A 30 mA, and per-circuit PIAs (MCBs) feeding lighting, sockets, kitchen, washer, bathroom, and HVAC circuits with H07V-K cables.\",\n \"standard\": \"REBT ITC-BT-17\",\n \"tags\": [\n \"sld\",\n \"residential\",\n \"rebt\",\n \"spain\",\n \"latam\",\n \"cgmp\",\n \"iga\",\n \"diferencial\",\n \"pia\",\n \"mcb\",\n \"iec-60364\",\n \"h07v-k\",\n \"esquema-unifilar\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sld \\\"Vivienda — CGMP REBT ITC-BT-17\\\"\\nACOM = utility [voltage: \\\"230V\\\", label: \\\"Acometida 230V mono\\\"]\\nICP = watthour_meter [label: \\\"Contador + ICP 25A\\\"]\\nIGA = breaker [rating: \\\"40A curva C, 6kA\\\", label: \\\"IGA\\\"]\\nID = ground_fault [rating: \\\"40A / 30mA Tipo A\\\", label: \\\"Diferencial general\\\"]\\nBUS = bus [voltage: \\\"230V\\\", label: \\\"Embarrado CGMP\\\"]\\nC1 = breaker [rating: \\\"10A curva C\\\", label: \\\"PIA C1\\\"]\\nC2 = breaker [rating: \\\"16A curva C\\\", label: \\\"PIA C2\\\"]\\nC3 = breaker [rating: \\\"25A curva C\\\", label: \\\"PIA C3\\\"]\\nC4 = breaker [rating: \\\"20A curva C\\\", label: \\\"PIA C4\\\"]\\nC5 = breaker [rating: \\\"16A curva C\\\", label: \\\"PIA C5\\\"]\\nC6 = breaker [rating: \\\"25A curva C\\\", label: \\\"PIA C6\\\"]\\nL1 = load [label: \\\"C1 Iluminación\\\"]\\nL2 = load [label: \\\"C2 Tomas uso general\\\"]\\nL3 = load [label: \\\"C3 Cocina + horno\\\"]\\nL4 = load [label: \\\"C4 Lavadora / lavavajillas\\\"]\\nL5 = load [label: \\\"C5 Tomas baño y cocina\\\"]\\nL6 = load [label: \\\"C6 Aerotermia / climatización\\\"]\\nACOM -> ICP\\nICP -> IGA\\nIGA -> ID\\nID -> BUS\\nBUS -> C1\\nC1 -> L1 [cable: \\\"1.5 mm² Cu H07V-K\\\"]\\nBUS -> C2\\nC2 -> L2 [cable: \\\"2.5 mm² Cu H07V-K\\\"]\\nBUS -> C3\\nC3 -> L3 [cable: \\\"6 mm² Cu H07V-K\\\"]\\nBUS -> C4\\nC4 -> L4 [cable: \\\"4 mm² Cu H07V-K\\\"]\\nBUS -> C5\\nC5 -> L5 [cable: \\\"2.5 mm² Cu H07V-K\\\"]\\nBUS -> C6\\nC6 -> L6 [cable: \\\"6 mm² Cu H07V-K\\\"]\",\n \"notes\": \"## Scenario\\n\\nA Spanish electrician (or an electrical-engineering student preparing the *Esquema Unifilar* for a course or permit) documents the *Cuadro General de Mando y Protección* (CGMP) of a single-family home. Spain's *Reglamento Electrotécnico para Baja Tensión* (REBT) §ITC-BT-17 is explicit about what the residential single-line must show: the incoming *acometida*, the utility-owned *Interruptor de Control de Potencia* (ICP) inside the meter cabinet, the consumer-owned *Interruptor General Automático* (IGA), one or more residual-current devices (*Diferenciales*), and a per-circuit *Pequeño Interruptor Automático* (PIA / MCB) for every final circuit — typically C1 through C6 in a basic *grado de electrificación básica* dwelling. The same pattern applies across Latin America (ABNT NBR 5410 in Brazil, NMX-J-098 in Mexico) and to most IEC-60364 jurisdictions, in contrast to NEC residential practice where the panel internals would normally live on a separate panel schedule.\\n\\n## Annotation key\\n\\n- `utility [voltage:..., label:...]` — *Acometida*: the 230 V single-phase service drop from the distribution network up to the meter cabinet\\n- `watthour_meter [label:...]` — *Contador + ICP*: revenue meter and the utility's tamper-sealed power-limiter breaker (25 A here, contracted at 5.75 kW)\\n- `breaker [rating:\\\"…A curva C, …kA\\\", label: \\\"IGA\\\"]` — *Interruptor General Automático*: customer-owned main breaker; REBT requires curve C and ≥ 6 kA breaking capacity for residential\\n- `ground_fault [rating: \\\"…A / 30mA Tipo A\\\", label: \\\"Diferencial general\\\"]` — Type-A residual-current device tripping at 30 mA per ITC-BT-17 §1.2 (Tipo A covers AC + pulsating DC residual currents from electronics and inverter loads)\\n- `bus [voltage: \\\"230V\\\", label: \\\"Embarrado CGMP\\\"]` — common busbar inside the consumer unit; every PIA taps off this rail\\n- `breaker [rating:\\\"…A curva C\\\", label: \\\"PIA Cn\\\"]` — branch-circuit *PIA*: one MCB per final circuit, sized per ITC-BT-25 Table 1 (10 A lighting, 16 A general sockets, 20–25 A kitchen / washer / HVAC)\\n- `load [label: \\\"Cn …\\\"]` — the final circuit's loads grouped under their REBT circuit designation (C1–C6)\\n- `[cable: \\\"… mm² Cu H07V-K\\\"]` — conductor cross-sectional area, copper, single-core insulated H07V-K — the canonical cable type for residential indoor wiring per UNE-EN 50525\\n\\n## How to read\\n\\nPower enters at the *acometida* and reaches the meter cabinet, where the utility's ICP enforces the contracted 5.75 kW power limit. Past the meter, the customer's CGMP begins: the IGA isolates the whole installation; the *Diferencial general* (40 A, 30 mA, Type A) trips on any earth-leakage fault to protect against electric shock per ITC-BT-24 §4.1; downstream of the differential, the busbar fans out to six branch circuits — lighting (1.5 mm²), general sockets (2.5 mm²), kitchen and oven (6 mm²), high-current appliances such as washer or dishwasher (4 mm²), bathroom and kitchen sockets (2.5 mm²), and the heat-pump / aerotermia (6 mm²). Each branch passes through its own PIA (curve C, sized per ITC-BT-25) before reaching the final circuit, so a fault in any one circuit drops only that circuit, not the whole dwelling. An REBT inspector reads this diagram top-down to verify selectivity (PIA < differential < IGA < ICP) and that conductor sizing matches PIA rating per the §ITC-BT-19 ampacity table.\"\n },\n {\n \"slug\": \"sld-substation-13kv\",\n \"diagram\": \"sld\",\n \"title\": \"13.8 kV utility substation\",\n \"description\": \"13.8 kV distribution substation single-line diagram with 138 kV grid input, 15 MVA step-down transformer, and three feeder breakers per IEEE 315.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"substation\",\n \"transformer\",\n \"bus\",\n \"feeder\",\n \"HV\",\n \"MV\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sld \\\"13.8 kV Substation\\\"\\nutility = utility [label: \\\"Grid 138 kV\\\"]\\nxfmr1 = transformer [kva: 15000, primary: 138, secondary: 13.8]\\nbus_hv = bus [voltage: 138]\\nbus_mv = bus [voltage: 13.8]\\nbrk1 = breaker [amps: 1200]\\nbrk2 = breaker [amps: 1200]\\nbrk3 = breaker [amps: 1200]\\nfeeder1 = load [label: \\\"Feeder 1\\\"]\\nfeeder2 = load [label: \\\"Feeder 2\\\"]\\nfeeder3 = load [label: \\\"Feeder 3\\\"]\\nutility -> bus_hv\\nbus_hv -> xfmr1\\nxfmr1 -> bus_mv\\nbus_mv -> brk1\\nbrk1 -> feeder1\\nbus_mv -> brk2\\nbrk2 -> feeder2\\nbus_mv -> brk3\\nbrk3 -> feeder3\",\n \"notes\": \"## Scenario\\n\\nA power systems engineer documents a distribution substation design for a utility interconnection application or a facility's electrical permit drawings. The single-line diagram is the first deliverable in any power system project — required by IEEE, NFPA 70E, and utility interconnection standards before detailed engineering begins.\\n\\n## Annotation key\\n\\n- `utility = utility [label: \\\"...\\\"]` — utility supply source (three-phase symbol)\\n- `[type: transformer, kva:..., primary:..., secondary:...]` — step-down transformer with rated kVA and voltage levels\\n- `[type: bus, voltage:...]` — horizontal bus bar at the specified voltage level\\n- `[type: breaker, amps:...]` — rated circuit breaker\\n- `[type: load, label:...]` — load or feeder destination\\n- `->` — directed power path from source to load\\n\\n## How to read\\n\\nThe 138 kV grid source feeds the high-voltage bus, which connects to the primary of the 15 MVA step-down transformer. The transformer secondary feeds the 13.8 kV medium-voltage bus. Three 1200 A circuit breakers fan out from the MV bus to three distribution feeders — each breaker isolates its feeder independently.\"\n },\n {\n \"slug\": \"sociogram-criminal-network\",\n \"diagram\": \"sociogram\",\n \"title\": \"Criminal communication network\",\n \"description\": \"Investigative sociogram of a covert organization — weighted command ties between the principal and lieutenants, directed courier and associate links to external contacts, and a weak tie that hints at an unconfirmed connection. The force-directed layout surfaces the command hierarchy and the bridging couriers.\",\n \"standard\": \"Moreno 1934\",\n \"tags\": [\n \"force-directed\",\n \"weighted-ties\",\n \"directed\",\n \"bridging\",\n \"command-hierarchy\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"sociogram \\\"Operation Sunset - Communication Network\\\"\\n config: layout = force-directed\\n boss [label: \\\"Subject Alpha\\\"]\\n lt1 [label: \\\"Lieutenant 1\\\"]\\n lt2 [label: \\\"Lieutenant 2\\\"]\\n courier1 [label: \\\"Courier A\\\"]\\n courier2 [label: \\\"Courier B\\\"]\\n contact1 [label: \\\"External Contact 1\\\"]\\n contact2 [label: \\\"External Contact 2\\\"]\\n associate1 [label: \\\"Associate 1\\\"]\\n associate2 [label: \\\"Associate 2\\\"]\\n boss <-> lt1 [weight: 4]\\n boss <-> lt2 [weight: 4]\\n lt1 -> courier1\\n lt1 -> courier2\\n lt2 -> associate1\\n lt2 -> associate2\\n courier1 -> contact1 [label: \\\"supplier\\\"]\\n courier2 -> contact2 [label: \\\"distributor\\\"]\\n lt1 <-> lt2 [weight: 2]\\n associate1 -.- courier1\",\n \"notes\": \"## Scenario\\n\\nA link-analysis unit reconstructs a covert organization from intercept metadata. The sociogram is the standard deliverable: who talks to whom, how strongly, and in which direction — so the analyst can identify the principal, the lieutenants who insulate him, and the couriers who bridge the organization to outside suppliers.\\n\\n## Annotation key\\n\\n- `<-> [weight: N]` — a reciprocal, weighted tie; the heavier `weight: 4` command links between `boss` and the two lieutenants render thicker than the `weight: 2` peer link\\n- `->` — a directed contact (one party initiates), used for the courier and associate tasking lines\\n- `-> [label: ...]` — a directed tie carrying a role annotation (`supplier`, `distributor`)\\n- `-.-` — a weak/unconfirmed tie, drawn dashed: `associate1 -.- courier1` flags a suspected but unverified connection\\n\\n## How to read\\n\\nSubject Alpha sits at the center, tied strongly to both lieutenants but never directly to the couriers or external contacts — the classic insulation pattern. Lieutenant 1 controls both couriers, each of whom reaches a single external contact, so the couriers are the bridging nodes whose removal would sever the outside supply. The dashed `associate1 -.- courier1` tie is the lead worth developing: an unconfirmed cross-link between the two lieutenants' sub-networks.\"\n },\n {\n \"slug\": \"sociogram-playground-dynamics\",\n \"diagram\": \"sociogram\",\n \"title\": \"Playground dynamics\",\n \"description\": \"Moreno sociogram of classroom playground dynamics — mutual friendships, one-way choices, and peer conflicts mapped by gender group using force-directed layout.\",\n \"standard\": \"Moreno 1934\",\n \"tags\": [\n \"groups\",\n \"force-directed\",\n \"mutual\",\n \"conflict\",\n \"classroom\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"sociogram \\\"Playground Dynamics\\\"\\n config: layout = force-directed\\n config: coloring = group\\n\\n group boys [label: \\\"Boys\\\", color: \\\"#42A5F5\\\"]\\n tom; jack; mike; leo\\n\\n group girls [label: \\\"Girls\\\", color: \\\"#EF5350\\\"]\\n anna; beth; chloe; diana\\n\\n tom <-> jack\\n tom -> mike\\n jack -> leo\\n mike -x> leo [label: \\\"conflict\\\"]\\n anna <-> beth\\n anna <-> chloe\\n beth <-> chloe\\n anna -> diana\\n diana -.- tom\\n leo -.- anna\",\n \"notes\": \"## Scenario\\n\\nA school counselor administers a sociometric survey to a class and maps the results to identify social stars, isolates, and conflict pairs. The force-directed layout naturally clusters tight friendship groups and surfaces bridging individuals — the counselor can immediately see who is at social risk and which cross-group connections are worth nurturing.\\n\\n## Annotation key\\n\\n- `group id [label:..., color:...]` — defines a named group; members listed below with `;` separator\\n- `<->` — mutual/reciprocal choice (both children named each other)\\n- `->` — one-way positive nomination (A chose B, B did not choose A)\\n- `-x>` — conflict or rejection edge; rendered with an X marker\\n- `-.-` — neutral / weak tie; neither positive nor negative nomination\\n- `config: layout = force-directed` — uses physics simulation to position nodes; tightly connected nodes cluster naturally\\n- `config: coloring = group` — colors each node by its assigned group\\n\\n## How to read\\n\\nThe diagram shows two tight cliques: the blue boys' group (Tom–Jack mutual friendship, with Leo drifting at the edge) and the red girls' group (Anna–Beth–Chloe triangle). Leo and Mike have a conflict edge — an immediate flag for the counselor. Diana sits between groups with only a weak tie to Tom, suggesting social isolation risk. Anna has the most outward nominations, making her a social star worth engaging as a peer ally.\"\n },\n {\n \"slug\": \"sociogram-team-influence\",\n \"diagram\": \"sociogram\",\n \"title\": \"Engineering team influence mapping\",\n \"description\": \"Informal influence map of an engineering team showing tech leads, senior ICs, and junior members — reveals bridging nodes and isolated individuals.\",\n \"standard\": \"Moreno 1934\",\n \"tags\": [\n \"force-directed\",\n \"groups\",\n \"bridging\",\n \"stars\",\n \"isolates\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"sociogram \\\"Engineering team — informal influence\\\"\\n config: layout = force-directed\\n group leads [label: \\\"Tech leads\\\", color: \\\"#1976D2\\\"]\\n alex; sam\\n group sr [label: \\\"Senior ICs\\\", color: \\\"#66BB6A\\\"]\\n priya; jordan; kim; tao\\n group jr [label: \\\"Junior\\\", color: \\\"#FFA726\\\"]\\n lee; ravi; nina; dev\\n alex <-> sam\\n alex -> priya\\n sam -> jordan\\n priya <-> kim\\n jordan <-> tao\\n kim -> lee\\n priya -> ravi\\n tao -> nina\\n dev -.- lee\\n nina -.- priya\",\n \"notes\": \"## Scenario\\n\\nAn engineering manager runs an informal network analysis survey (\\\"Who do you go to when you're stuck?\\\") and maps the results to identify knowledge hubs, bridging individuals between seniority tiers, and team members who are drifting toward isolation before performance reviews surface the issue.\\n\\n## Annotation key\\n\\n- `group id [label:..., color:...]` — assigns individuals to organizational tiers, color-coded\\n- `<->` — mutual influence; both nominated each other\\n- `->` — one-way influence nomination\\n- `-.-` — weak tie; neither party nominated the other in the survey\\n- The force-directed layout clusters mutual-nomination groups and separates isolates\\n\\n## How to read\\n\\nAlex and Sam (tech leads) are mutually influential. Alex bridges down to Priya, Sam to Jordan — healthy knowledge flow across tiers. Priya and Kim form a strong senior IC hub. Dev and Nina have only weak ties (--. to the network), suggesting integration risk. Dev's only connection is a weak tie to Lee — a coaching opportunity before the next performance cycle.\"\n },\n {\n \"slug\": \"state-checkout-composite-history\",\n \"diagram\": \"state\",\n \"title\": \"Checkout session with composite state and history\",\n \"description\": \"UML statechart for a checkout session with a composite Payment state, entry and exit activities, guards, and retry transitions.\",\n \"standard\": \"OMG UML 2.5.1\",\n \"tags\": [\n \"statechart\",\n \"uml\",\n \"composite\",\n \"guard\",\n \"checkout\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"stateDiagram-v2 [direction: LR]\\n\\n[*] --> Cart\\nCart --> Checkout : begin_checkout\\nCheckout --> Payment : submit_shipping [addressValid] / createIntent()\\nCheckout --> Cart : edit_cart\\nPayment --> Confirmed : captured / sendReceipt()\\nPayment --> Checkout : failed [retries < 3] / showError()\\nPayment --> Cancelled : failed [retries >= 3]\\nConfirmed --> [*]\\nCancelled --> [*]\\n\\nstate Payment {\\n entry / startPaymentTimer()\\n exit / stopPaymentTimer()\\n [*] --> Authorizing\\n Authorizing --> Capturing : authorized\\n Authorizing --> Failed : declined\\n Capturing --> Captured : capture_ok\\n Capturing --> Failed : capture_error\\n}\\n\\nnote right of Payment : Composite state hides gateway detail\",\n \"notes\": \"## Scenario\\n\\nCheckout is a lifecycle, not a process list: the session can move forward, retry, or terminate depending on events and guards. A composite state keeps the external lifecycle readable while still showing the internal payment substates.\\n\\n## Annotation key\\n\\n- `state Payment { ... }` creates the composite state.\\n- `entry /` and `exit /` activities document side effects on state entry and exit.\\n- Transition labels use the UML `trigger [guard] / action` format.\"\n },\n {\n \"slug\": \"state-ecommerce-order\",\n \"diagram\": \"state\",\n \"title\": \"E-commerce order lifecycle (state diagram)\",\n \"description\": \"Full order state machine — from Pending through payment routing (choice pseudo-state), composite Processing state with Picking/Packing/Shipped sub-states, delivery, refund, and cancellation paths. Demonstrates composite states, choice pseudo-states, guard conditions, entry actions, and UML notes.\",\n \"standard\": \"OMG UML 2.5.1 §14\",\n \"tags\": [\n \"state\",\n \"uml\",\n \"composite\",\n \"choice\",\n \"guard\",\n \"order-management\",\n \"e-commerce\",\n \"lifecycle\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"state \\\"E-Commerce Order Lifecycle\\\"\\n\\ninitial i\\ni -> Pending\\n\\nPending -> Confirmed : place_order [items_in_stock] / reserveInventory()\\nPending -> Cancelled : cancel\\n\\nchoice PayRoute\\nConfirmed -> PayRoute : pay\\nPayRoute -> Processing : [method == \\\"card\\\"]\\nPayRoute -> Processing : [method == \\\"wallet\\\"]\\nPayRoute -> AwaitingTransfer : [method == \\\"bank_transfer\\\"]\\n\\nAwaitingTransfer -> Processing : transfer_received [amount_correct]\\nAwaitingTransfer -> Cancelled : transfer_timeout\\n\\ncomposite Processing {\\n initial pi\\n final pf\\n\\n pi -> Picking\\n Picking -> Packing : picked / updateWarehouse()\\n Packing -> Shipped : label_printed\\n Shipped -> pf : carrier_confirmed\\n}\\n\\nProcessing -> Delivered : delivered / notifyCustomer()\\nProcessing -> Failed : fulfillment_error\\n\\nDelivered -> Refunded : return_request [within_30_days] / initiateRefund()\\nFailed -> Pending : retry [attempt < 3]\\nFailed -> Cancelled : retry [attempt >= 3]\\n\\nfinal f\\nDelivered -> f\\nRefunded -> f\\nCancelled -> f\\n\\nnote right_of AwaitingTransfer : SLA: 48 h before timeout.\",\n \"notes\": \"Order state machines are one of the most common backend design artifacts, and one of the most commonly under-specified. Teams often start with a simple enum (`PENDING / PAID / SHIPPED / DELIVERED`) and then bolt on edge cases over time: partial shipments, payment holds, carrier errors, refund windows. Six months later the enum has twelve values, the transition logic is scattered across three services, and nobody can explain what sequence of events gets an order from `FAILED` to `CANCELLED` versus from `FAILED` back to `PENDING`. A UML state diagram catches all of this upfront.\\n\\n**Guard conditions on `place_order`.** The transition from `Pending` to `Confirmed` carries `[items_in_stock]` — a guard. Guards are boolean predicates that must be true for the transition to fire even when the trigger event (`place_order`) occurs. If the guard is false, the trigger is silently absorbed and the system stays in `Pending`. In practice this means inventory is checked synchronously during order placement, and the transition only proceeds if stock is available. The action `/ reserveInventory()` fires when the transition does go through, atomically.\\n\\n**Choice pseudo-state for payment routing.** `PayRoute` is a UML choice pseudo-state (drawn as a diamond). When the `pay` trigger fires from `Confirmed`, the machine immediately evaluates the guards on all outgoing transitions from `PayRoute`. If `method == \\\"card\\\"` or `method == \\\"wallet\\\"`, control goes directly to `Processing`. If `method == \\\"bank_transfer\\\"`, it goes to `AwaitingTransfer` — a waiting state with its own 48-hour SLA note. Choice pseudo-states do not dwell; they route. This is the correct model for \\\"take different paths based on a value computed at runtime.\\\"\\n\\n**Composite state for fulfillment.** `Processing` is a composite state — it contains its own internal state machine with `Picking`, `Packing`, and `Shipped`. From the outside, the system is \\\"in Processing\\\" whether it's picking, packing, or confirming with the carrier. From the inside, the sub-machine tracks exactly where the warehouse is. The composite state has its own `initial` and `final` pseudo-states: the machine enters at `pi` (starts picking) and exits through `pf` (carrier confirmed), which fires the outer transition to `Delivered`. Cross-composite transitions to `Failed` are also valid — a fulfillment error at any sub-state terminates the Processing phase and moves to the outer `Failed` state.\\n\\n**Retry with bounded attempts.** `Failed` has two outgoing transitions back to `Pending` and `Cancelled`, both triggered by `retry` but guarded on `attempt`. This is the explicit model for \\\"retry up to N times, then give up.\\\" Without the state diagram, this logic typically lives in a cron job or a dead-letter queue processor that nobody fully understands. Here it is the specification: anyone reading the diagram knows the retry policy without digging through queue configurations.\\n\\n**Final state convergence.** `Delivered`, `Refunded`, and `Cancelled` all transition to the same `final` pseudo-state. In implementation, \\\"final\\\" might mean the order record is archived, the event bus receives an `order.closed` event, and no further state transitions are accepted. The model is silent on what happens after final — that's intentional. The state machine is done; downstream processes (analytics, accounting, data retention) are separate concerns.\"\n },\n {\n \"slug\": \"state-subscription-lifecycle\",\n \"diagram\": \"state\",\n \"title\": \"SaaS subscription lifecycle\",\n \"description\": \"UML statechart for a subscription moving through trial, active service, payment recovery, pause, cancellation, and reactivation.\",\n \"standard\": \"OMG UML 2.5.1\",\n \"tags\": [\n \"statechart\",\n \"subscription\",\n \"billing\",\n \"lifecycle\",\n \"guards\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"state \\\"Subscription Lifecycle\\\" [direction: LR]\\n\\ninitial start\\nstart -> Trialing\\n\\nTrialing -> Active : trial_end [payment_method_valid] / startBilling()\\nTrialing -> Incomplete : trial_end [payment_method_missing] / requestPaymentMethod()\\nTrialing -> Cancelled : cancel\\n\\ncomposite Active {\\n entry / provisionWorkspace()\\n exit / syncEntitlements()\\n initial ai\\n ai -> Current\\n Current -> GracePeriod : invoice_failed\\n GracePeriod -> Current : payment_succeeded / restoreAccess()\\n GracePeriod -> PastDue : grace_expired\\n PastDue -> Current : payment_succeeded / clearDunning()\\n final af\\n Current -> af : cancel_at_period_end\\n}\\n\\nActive -> Paused : pause [plan_allows_pause] / suspendBilling()\\nPaused -> Active : resume / resumeBilling()\\nActive -> Cancelled : cancel_now / revokeAccess()\\nIncomplete -> Active : payment_method_added / retryInvoice()\\nIncomplete -> Cancelled : expires\\nActive -> Cancelled : period_end\\nCancelled -> Active : reactivate [within_retention_window] / restoreSubscription()\\n\\nfinal done\\nCancelled -> done : purge_after_retention\\n\\nnote right_of Active : Composite state keeps dunning detail inside active service.\",\n \"notes\": \"## Scenario\\n\\nSubscription logic is where simple status enums drift out of sync with billing providers. This statechart makes the product contract explicit: trial conversion, incomplete setup, dunning recovery, pause, cancellation, and reactivation are separate transitions with guards and actions.\\n\\n## Annotation key\\n\\n- `Active` is a composite state because payment recovery happens while the product is still notionally active.\\n- Guard labels such as `[payment_method_valid]` document provider-dependent branching.\\n- Entry and exit actions mark entitlement provisioning and sync points.\"\n },\n {\n \"slug\": \"state-traffic-light\",\n \"diagram\": \"state\",\n \"title\": \"Traffic light (state diagram)\",\n \"description\": \"A three-state finite state machine for a traffic signal — Red, Green, Yellow — with timer-driven transitions and a power_off exit to a final state. Introduces UML initial and final pseudo-states, transition labels, and the cyclic structure that makes state diagrams the right tool for reactive systems.\",\n \"standard\": \"OMG UML 2.5.1 §14\",\n \"tags\": [\n \"state\",\n \"uml\",\n \"fsm\",\n \"state-machine\",\n \"embedded\",\n \"reactive\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"state \\\"Traffic Light\\\"\\n\\ninitial i\\nfinal f\\n\\ni -> Red\\nRed -> Green : timer\\nGreen -> Yellow : timer\\nYellow -> Red : timer\\nRed -> f : power_off\",\n \"notes\": \"The traffic light is to state diagrams what the pump loop is to P&IDs: every textbook uses it, every engineer has drawn it, and if you understand it you understand the grammar of every more complex model.\\n\\n**Why a state diagram and not a flowchart.** A flowchart for a traffic light would show a loop: start → Red → (timer fires?) → Green → (timer fires?) → Yellow → back to Red. That works for describing an algorithm, but it misses the essential question: *what is the system doing right now?* A state machine makes the current state a first-class concept. The traffic light is not executing a loop — it *is* Red, or it *is* Green. Transitions are events that change what it is. This distinction matters the moment you add complexity: \\\"what happens if a pedestrian button is pressed while we're in Green?\\\" You answer that by looking at the transitions out of Green, not by tracing a flowchart path.\\n\\n**UML pseudo-states.** The filled black circle (`initial i`) and the bull's-eye circle (`final f`) are pseudo-states — they are not real states the system can dwell in, just notational entry and exit points. The initial pseudo-state shows where the machine starts; the arrow from `i` to Red tells you Red is the first real state. The final pseudo-state shows where the machine terminates. In the traffic light, termination is the `power_off` event from Red — the system shuts down from the Red state only (it wouldn't be safe to power off mid-Green).\\n\\n**Transition labels.** Each arrow is labeled with the trigger event that causes the transition. `timer` means \\\"the countdown for this phase has elapsed.\\\" In a real embedded implementation, this would be a hardware timer interrupt or a software watchdog expiry. Schematex doesn't execute the state machine — it renders the model. The labels are free text; you write exactly what your system calls the event.\\n\\n**Cyclic structure.** The three main states form a cycle: Red → Green → Yellow → Red. Most state diagrams describing continuous systems have cycles — the system runs until something external stops it. The `power_off` transition is the only way to reach the final state, and it is only modeled on Red because that is the safe state to stop in. If you wanted to model an emergency override (traffic officer stops the light mid-cycle), you would add `power_off` transitions from Green and Yellow too.\\n\\n**From model to code.** A UML state diagram maps directly to an enum + switch statement, a state table, or a state-machine framework (XState, Boost.MSM, Qt State Machine). The diagram is the specification; the implementation strategy is separate. Generating this diagram from a DSL means you can keep the spec in version control alongside the code, diff it in PRs, and regenerate it from an LLM prompt when requirements change.\"\n },\n {\n \"slug\": \"threatmodel-ecommerce-checkout\",\n \"diagram\": \"threatmodel\",\n \"title\": \"E-commerce checkout threat model (STRIDE)\",\n \"description\": \"A security data-flow diagram for a checkout flow with three trust boundaries. The engine applies the STRIDE-per-element mapping and flags every flow that crosses a trust boundary — where spoofing and tampering concentrate.\",\n \"standard\": \"Microsoft STRIDE / Shostack (2014)\",\n \"tags\": [\n \"threatmodel\",\n \"stride\",\n \"dfd\",\n \"trust-boundary\",\n \"security\",\n \"data-flow\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"threatmodel \\\"E-commerce checkout\\\"\\nexternal: Customer\\nexternal: Payment Gateway\\nprocess 1.0: Web App\\nprocess 2.0: Order Service\\ndatastore D1: Orders DB\\ndatastore D2: Audit Log\\nCustomer -> 1.0 : \\\"HTTPS Checkout\\\"\\n1.0 -> 2.0 : \\\"Place order\\\"\\n2.0 -> D1 : \\\"Write order\\\"\\n2.0 -> Payment Gateway : \\\"Charge card\\\"\\n2.0 -> D2 : \\\"Order event\\\"\\nboundary \\\"Internet\\\" { Customer, Payment_Gateway }\\nboundary \\\"DMZ\\\" { 1.0 }\\nboundary \\\"Internal\\\" { 2.0, D1, D2 }\",\n \"notes\": \"## What this shows\\n\\nA STRIDE threat model of an e-commerce checkout drawn as a data-flow diagram (DFD): two external entities (the customer and a third-party payment gateway), two processes (the web app in the DMZ, the order service internally), and two data stores (the orders database and an audit log). Three trust boundaries partition the system — Internet, DMZ, Internal — and the labelled flows carry the data crossing between them.\\n\\nThe engine does the STRIDE-per-element analysis, not just the boxes. It applies the canonical mapping — externals get Spoofing/Repudiation, processes get the full S-T-R-I-D-E, stores get Tampering/Information-disclosure/DoS, and the **audit log additionally gets Repudiation** because it matches the log/journal pattern. Most usefully, it **flags every flow that crosses a trust boundary** — the customer→web-app HTTPS request (Internet→DMZ), the order-service→payment-gateway charge (Internal→Internet) — because boundary crossings are where spoofing, tampering, and information disclosure concentrate. Each element and flow carries its applicable STRIDE categories in `data-*`.\"\n },\n {\n \"slug\": \"timeline-company-milestones\",\n \"diagram\": \"timeline\",\n \"title\": \"Company milestone history\",\n \"description\": \"Lollipop timeline of a company's first five years — fundraising rounds, key hires, product GAs — suited for an investor deck or anniversary blog post.\",\n \"standard\": \"Timeline convention\",\n \"tags\": [\n \"timeline\",\n \"milestones\",\n \"fundraising\",\n \"company-history\",\n \"pitch\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timeline \\\"Acme — First Five Years\\\"\\nconfig: style = lollipop\\n\\n2020-06: \\\"Founders meet at Y Combinator\\\" [side: below]\\n2020-11: milestone \\\"Incorporation + pre-seed $1M\\\" [side: above, color: #1565C0]\\n2021-04: \\\"First engineer hired\\\" [side: below]\\n2021-09: milestone \\\"Product beta — 50 design partners\\\" [side: above, color: #2E7D32]\\n2022-03: milestone \\\"Seed round — $6M\\\" [side: above, color: #1565C0]\\n2022-11: \\\"Team reaches 20 people\\\" [side: below]\\n2023-05: milestone \\\"Platform v1 GA\\\" [side: above, color: #6A1B9A]\\n2023-10: milestone \\\"Series A — $22M\\\" [side: above, color: #1565C0]\\n2024-06: \\\"100th enterprise customer\\\" [side: below]\\n2025-01: milestone \\\"Platform v2 launched\\\" [side: above, color: #6A1B9A]\",\n \"notes\": \"## Scenario\\n\\nThe founder drops this into the first page of the fundraising deck. Funding rounds, product GAs, and growth markers alternate above/below the axis, which makes the parallel story — \\\"we raised capital and shipped on time\\\" — visible in one glance. Reviewers who only read the top of the page still get the two-line story.\\n\\n## Annotation key\\n\\n- `style = lollipop` — dot-on-stick markers alternating above/below axis\\n- `milestone` — diamond marker for headline events\\n- `[side: above|below]` — explicit placement\\n- `[color: #hex]` — colour-code category (fundraising / product / team)\\n\\n## How to read\\n\\nTime runs left to right. Each marker is a single dated event; *milestone* markers are the diamond-shaped headline items (fundraising, GAs). Colour carries category: blue = fundraising, purple = product, green = early commercial traction. Events below the axis are supporting context (people, growth stats); events above are the announceable headlines.\"\n },\n {\n \"slug\": \"timeline-litigation-case\",\n \"diagram\": \"timeline\",\n \"title\": \"Litigation case timeline\",\n \"description\": \"Lollipop litigation timeline with pleadings, discovery, motions, settlement conference, and trial milestones.\",\n \"standard\": \"Legal case chronology convention\",\n \"tags\": [\n \"timeline\",\n \"litigation\",\n \"lollipop\",\n \"legal\",\n \"milestones\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timeline \\\"Smith v. Acme - Case Timeline\\\"\\nconfig: style = lollipop\\n\\n2025-01-10: milestone \\\"Complaint filed\\\" [side: above, color: #1565C0]\\n2025-02-07: \\\"Answer due\\\" [side: below]\\n2025-03-01 - 2025-06-30: \\\"Fact discovery\\\" [category: \\\"discovery\\\"]\\n2025-04-15: \\\"Plaintiff deposition\\\" [side: above]\\n2025-05-22: \\\"Expert reports exchanged\\\" [side: below]\\n2025-07-15: milestone \\\"Summary judgment motion\\\" [side: above, color: #C62828]\\n2025-08-20: \\\"Mediation\\\" [side: below]\\n2025-10-06: milestone \\\"Trial setting\\\" [side: above, color: #2E7D32]\",\n \"notes\": \"## Scenario\\n\\nLitigation timelines mix hard deadlines, long phases, and high-stakes milestones. The lollipop style keeps single events readable while still allowing discovery to appear as a range.\\n\\n## Annotation key\\n\\n- `config: style = lollipop` selects the narrative timeline style.\\n- Date ranges render as spans.\\n- `milestone` emphasizes critical procedural events.\"\n },\n {\n \"slug\": \"timeline-product-launch\",\n \"diagram\": \"timeline\",\n \"title\": \"Product launch timeline\",\n \"description\": \"Gantt-style timeline for a three-month product launch — overlapping workstreams, two milestones, and a freeze window, used for exec status updates.\",\n \"standard\": \"Timeline / Gantt convention\",\n \"tags\": [\n \"timeline\",\n \"gantt\",\n \"product-launch\",\n \"scheduling\",\n \"program\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"timeline \\\"Platform v2 Launch\\\"\\nconfig: style = gantt\\n\\n2025-07-01 - 2025-08-15: \\\"Engineering build\\\" [category: \\\"engineering\\\"]\\n2025-07-15 - 2025-08-31: \\\"Design polish\\\" [category: \\\"design\\\"]\\n2025-08-01 - 2025-09-10: \\\"Marketing collateral\\\" [category: \\\"marketing\\\"]\\n2025-08-20: milestone \\\"Feature freeze\\\" [color: #E53935]\\n2025-08-20 - 2025-09-05: \\\"QA hardening\\\" [category: \\\"engineering\\\"]\\n2025-09-01 - 2025-09-12: \\\"Press embargo outreach\\\" [category: \\\"marketing\\\"]\\n2025-09-15: milestone \\\"Public launch\\\" [color: #2E7D32]\",\n \"notes\": \"## Scenario\\n\\nThe launch PM shares this in weekly exec status. Overlapping bars show where workstreams parallelize (design polishing while engineering still builds) and the feature-freeze diamond makes the handoff between build and QA unmissable. The second milestone (public launch) anchors the entire timeline and is the reason every other bar exists.\\n\\n## Annotation key\\n\\n- `DATE - DATE: \\\"Label\\\"` — range (bar) event\\n- `DATE: milestone \\\"Label\\\"` — point milestone (diamond)\\n- `[category: …]` — group colour in the gantt legend\\n- `[color: #hex]` — explicit marker colour\\n\\n## How to read\\n\\nTime flows left to right. Horizontal bars are continuous work; diamonds are instantaneous events. Overlapping bars mean two teams are working simultaneously — fine, so long as they coordinate. The red *Feature freeze* marks the transition from net-new work to hardening; any engineering bar extending past it needs an exception. The green *Public launch* is the terminal milestone every other bar is serving.\"\n },\n {\n \"slug\": \"timing-clock-rle-shorthand\",\n \"diagram\": \"timing\",\n \"title\": \"Timing diagram with clock and run-length shorthands\",\n \"description\": \"A synchronous bus-read timing diagram written with the clock and rle shorthands so signals stay aligned without hand-counting wave characters.\",\n \"standard\": \"WaveDrom / IEEE 1497\",\n \"tags\": [\n \"clock\",\n \"run-length\",\n \"rle\",\n \"WaveDrom\",\n \"synchronous\",\n \"bus-read\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"timing \\\"Synchronous Bus Read\\\"\\nCLK: clock 8\\nRST: rle 1*2 0*6\\nEN: rle 0*2 1*4 0*2\\nDATA: zz====zz data: [\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\"]\",\n \"notes\": \"## Scenario\\n\\nA digital designer documents an 8-cycle synchronous read. Rather than typing\\n`pppppppp` for the clock and counting `0`/`1` runs by hand for reset and enable —\\nthe most common source of misaligned waveforms — the diagram uses the two\\nlength-explicit shorthands.\\n\\n## Annotation key\\n\\n- **`clock N`** — a clock generator with `N` periods. `CLK: clock 8` expands to\\n `pppppppp`; add `neg` for a negedge clock. No character-counting.\\n- **`rle <state>*<count> …`** — run-length segments. `RST: rle 1*2 0*6` expands to\\n `11000000`; `EN: rle 0*2 1*4 0*2` expands to `00111100`. Every signal's total\\n cell count is explicit, so the waves line up.\\n- **raw wave string** — `DATA: zz====zz` keeps per-cell control where it matters;\\n `data: [...]` labels the four `=` bus segments.\\n\\n## How to read\\n\\nThe clock runs 8 cycles. Reset is asserted for the first 2 cycles, then drops.\\nEnable rises for the middle 4 cycles. The data bus is high-impedance until enable,\\nthen presents four stable bytes `D0…D3`, returning to high-Z after. Because\\n`clock` and `rle` make each signal exactly 8 cells, the edges align without manual\\ncounting.\"\n },\n {\n \"slug\": \"timing-i2c-read-burst\",\n \"diagram\": \"timing\",\n \"title\": \"I2C read burst timing\",\n \"description\": \"WaveDrom-compatible timing diagram for an I2C register read with address, repeated start, data bytes, ACK, and NACK phases.\",\n \"standard\": \"WaveDrom signal notation\",\n \"tags\": [\n \"timing\",\n \"i2c\",\n \"waveform\",\n \"bus\",\n \"embedded\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timing \\\"I2C Read Burst\\\" [hscale: 1.2]\\n[Control]\\nSCL: pppppppppppp\\nSTART: 100000100001\\n---\\n[Bus]\\nSDA: x==========x data: [\\\"ADDR+W\\\",\\\"ACK\\\",\\\"REG\\\",\\\"ACK\\\",\\\"REP START\\\",\\\"ADDR+R\\\",\\\"ACK\\\",\\\"DATA0\\\",\\\"ACK\\\",\\\"DATA1\\\",\\\"NACK\\\"]\\n---\\n[Status]\\nBUSY: 111111111110\",\n \"notes\": \"## Scenario\\n\\nI2C reads are visually clearer as timing diagrams than as prose. The repeated start and ACK/NACK phases are where firmware and hardware teams most often talk past each other.\\n\\n## Annotation key\\n\\n- `[Control]`, `[Bus]`, and `[Status]` group related signals.\\n- `p` renders clock pulses.\\n- `=` segments carry bus labels from the `data:` list.\"\n },\n {\n \"slug\": \"timing-spi-transaction\",\n \"diagram\": \"timing\",\n \"title\": \"SPI transaction timing diagram\",\n \"description\": \"WaveDrom-compatible SPI timing diagram for an 8-byte master-to-slave transaction with clock, chip-select, MOSI, and MISO signals for firmware documentation.\",\n \"standard\": \"WaveDrom / IEEE 1497\",\n \"tags\": [\n \"SPI\",\n \"digital\",\n \"clock\",\n \"chip-select\",\n \"MOSI\",\n \"MISO\",\n \"WaveDrom\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timing \\\"SPI Transaction\\\"\\nCLK: pppppppp\\nCS_N: 10000001\\nMOSI: x======= data: [\\\"0xAB\\\",\\\"0xCD\\\",\\\"0xEF\\\",\\\"0x01\\\",\\\"0x02\\\",\\\"0x03\\\",\\\"0x04\\\",\\\"0x05\\\"]\\nMISO: zzzz==== data: [\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"0xFF\\\",\\\"0x12\\\",\\\"0x34\\\",\\\"0x56\\\"]\",\n \"notes\": \"## Scenario\\n\\nA firmware engineer or hardware designer documents an 8-byte SPI master-to-slave transaction for a device driver review or datasheet. The WaveDrom-compatible syntax means the same DSL can be pasted directly into WaveDrom's online editor or embedded in documentation pipelines.\\n\\n## Annotation key\\n\\n- `p` — clock pulse (high period followed by low); each `p` is one clock cycle\\n- `1` / `0` — logic high / logic low\\n- `=` — data bus: stable data (value unchanged from previous cycle)\\n- `x` — don't-care or undefined state (transition state)\\n- `z` — high-impedance (floating / tri-state)\\n- `data: [...]` — optional data labels for each stable segment, rendered inside the bus bar\\n- `CS_N` — active-low chip select; `1` = deselected, `0` = selected\\n\\n## How to read\\n\\nThe clock runs for 8 cycles. CS_N goes low at cycle 1 and returns high at cycle 8, framing the transaction. MOSI (master out) sends 8 bytes starting at cycle 1. MISO (slave in) is high-Z for the first 4 cycles (slave preparing the response) then transitions to stable data bytes 5–8. The transaction completes when CS_N de-asserts.\"\n },\n {\n \"slug\": \"umlclass-generics-mermaid\",\n \"diagram\": \"umlclass\",\n \"title\": \"Generics and Mermaid-compatible syntax\",\n \"description\": \"A generic repository written in Mermaid classDiagram shorthand — tilde-generics, single-line members, and member classifiers — all rendered with standard-correct adornments, so a Mermaid snippet migrates in one line.\",\n \"standard\": \"OMG UML 2.5.1 §9–§11\",\n \"tags\": [\n \"umlclass\",\n \"uml\",\n \"mermaid\",\n \"generics\",\n \"interface\",\n \"realization\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"classDiagram\\nclass Repository~T~ {\\n +findAll() List~T~\\n +findById(id : ID) Optional~T~\\n +cache : Map~String,List~int~~\\n +count$\\n +flush()*\\n}\\nclass CrudService\\nCrudService : <<service>>\\nCrudService : +repo : Repository~User~\\nCrudService : +save(e : User) User\\nRepository~T~ <|.. CrudService\",\n \"notes\": \"## What this shows\\n\\nThe same diagram a developer would paste from a Mermaid `classDiagram`, rendered with Schematex's standard-correct adornments and layered layout.\\n\\n**Tilde-generics** convert to angle brackets: `List~T~` → `List`, and they nest — `Map~String,List~int~~` → `Map>`. The generic also works on the class name itself (`class Repository~T~` → `Repository`).\\n\\n**Single-line members** append to a class: `CrudService : +repo : Repository~User~` adds an attribute, and `CrudService : <<service>>` sets the stereotype — no `{ … }` block required.\\n\\n**Member classifiers** are the Mermaid suffixes: `flush()*` marks an abstract operation (rendered italic) and `count$` a static member (rendered underlined). Return types may be space-separated (`findAll() List~T~`) the way Mermaid writes them. A lone leading `~` is still the package-visibility glyph, so the two never collide.\"\n },\n {\n \"slug\": \"umlclass-namespaces\",\n \"diagram\": \"umlclass\",\n \"title\": \"Packages and namespaces\",\n \"description\": \"Group classifiers into labelled containment frames with namespace blocks — dot-notation auto-creates parent packages, and blocks nest, so a layered architecture reads as nested boxes the way an architect draws it.\",\n \"standard\": \"OMG UML 2.5.1 §9–§11\",\n \"tags\": [\n \"umlclass\",\n \"uml\",\n \"namespace\",\n \"package\",\n \"architecture\",\n \"mermaid\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"umlclass\\ntitle: \\\"Layered packages\\\"\\n\\nnamespace Platform {\\nnamespace Auth {\\nclass UserService {\\n + login()\\n + logout()\\n}\\n}\\nnamespace Data {\\nclass Repository {\\n + find()\\n + save()\\n}\\n}\\n}\\n\\nclass Gateway {\\n + route()\\n}\\n\\nGateway --> UserService : delegates\\nGateway --> Repository : delegates\",\n \"notes\": \"## What this shows\\n\\nA **`namespace` block** groups its classifiers into a labelled bounding frame. Frames are computed as the **union of their members plus any nested sub-packages**, padded, with a label band on top — the same C4-style containment Schematex uses for the `network` engine's site/zone boundaries. Here `Platform` contains `Auth` and `Data`, each holding one service; `Gateway` lives outside the package and delegates into both.\\n\\n**Frames never overlap and always enclose.** A package-clustering pass keeps same-package classifiers contiguous within each layout rank, so the frame stays a clean rectangle instead of a ragged shape that swallows unrelated boxes.\\n\\n**Dot-notation also works.** Writing `namespace Company.Engineering.Backend { … }` auto-creates `Company` and `Company.Engineering` as parent frames, so you can declare a deep package in one line. An explicit label is available too: `namespace plat[\\\"Platform Layer\\\"] { … }`.\"\n },\n {\n \"slug\": \"umlclass-order-model\",\n \"diagram\": \"umlclass\",\n \"title\": \"Order model — aggregation, composition, and dependency\",\n \"description\": \"A small domain model that exercises every relationship-end adornment that confuses first-time UML readers — filled diamond for composition, hollow diamond for aggregation, plain association, and a dashed dependency.\",\n \"standard\": \"OMG UML 2.5.1 §11.5 (Associations)\",\n \"tags\": [\n \"umlclass\",\n \"uml\",\n \"composition\",\n \"aggregation\",\n \"dependency\",\n \"multiplicity\",\n \"static\",\n \"derived\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"umlclass\\ntitle: \\\"Order model\\\"\\n\\nclass Order {\\n - id : String\\n + total : Money {readOnly}\\n + place() : void\\n + count : int {static}\\n}\\n\\nclass LineItem {\\n + qty : int\\n + subtotal() : Money\\n}\\n\\nclass Customer {\\n + name : String\\n}\\n\\nclass Address {\\n + city : String\\n}\\n\\nclass TaxPolicy {\\n + rate(c : Country) : Percent\\n}\\n\\nOrder *-- \\\"1..*\\\" LineItem : contains\\nCustomer o-- \\\"0..*\\\" Address : has\\nCustomer \\\"1\\\" -- \\\"*\\\" Order : places\\nOrder ..> TaxPolicy : uses\",\n \"notes\": \"## Why the diamonds are not interchangeable\\n\\nUML's two diamond shapes encode genuinely different lifetime semantics, and they're the single most-confused pair on the notation.\\n\\n**Composition** (filled diamond) means *the part dies with the whole*: when an `Order` is deleted, its `LineItem`s are deleted with it — the line items have no independent existence. The filled diamond sits at the `Order` (whole) end of `*--`, regardless of which id the author typed first.\\n\\n**Aggregation** (hollow diamond) means *the part outlives the whole*: an `Address` exists in its own right and a `Customer` aggregating it is just a structural reference — deleting the customer should not delete the address.\\n\\n**Plain association** (no diamond) is just \\\"these two types are structurally linked\\\" — the line carries multiplicity (`1` ↔ `*`) and a name (`places`) but makes no claim about ownership.\\n\\n**Dependency** (dashed + open arrow) says `Order` *uses* `TaxPolicy` without holding a reference to it — typically a method parameter or a transient call. The dashed line distinguishes a using-relationship from a structural one at a glance.\\n\\nThe `{readOnly}`, `{static}`, and `{abstract}` property strings render as the standard UML annotations; `count` is underlined to mark it as class-scope.\"\n },\n {\n \"slug\": \"umlclass-payment-strategy\",\n \"diagram\": \"umlclass\",\n \"title\": \"Payment strategy pattern with enum + custom stereotype\",\n \"description\": \"The Strategy pattern as a UML class diagram — a payment service depending on an interface that three concrete strategies realize, plus an enumeration for the supported methods and a custom «service» stereotype.\",\n \"standard\": \"OMG UML 2.5.1 §9–§11\",\n \"tags\": [\n \"umlclass\",\n \"uml\",\n \"strategy-pattern\",\n \"interface\",\n \"enum\",\n \"stereotype\",\n \"dependency\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"umlclass\\ntitle: \\\"Payment strategy\\\"\\n\\n«enumeration» PaymentMethod {\\n CARD\\n BANK_TRANSFER\\n WALLET\\n}\\n\\n«interface» PaymentStrategy {\\n + authorize(amount : Money) : AuthResult\\n + capture(auth : AuthResult) : Receipt\\n}\\n\\n«service» class CheckoutService {\\n - strategies : Map<PaymentMethod, PaymentStrategy>\\n + pay(method : PaymentMethod, amount : Money) : Receipt\\n}\\n\\nclass CardStrategy { + authorize(amount : Money) : AuthResult + capture(auth : AuthResult) : Receipt }\\nclass BankStrategy { + authorize(amount : Money) : AuthResult + capture(auth : AuthResult) : Receipt }\\nclass WalletStrategy { + authorize(amount : Money) : AuthResult + capture(auth : AuthResult) : Receipt }\\n\\nPaymentStrategy <|.. CardStrategy\\nPaymentStrategy <|.. BankStrategy\\nPaymentStrategy <|.. WalletStrategy\\n\\nCheckoutService ..> PaymentStrategy : delegates to\\nCheckoutService ..> PaymentMethod : selects by\",\n \"notes\": \"## Reading the diagram\\n\\nThe Strategy pattern is one of the canonical Gang-of-Four examples and is almost always introduced as a UML class diagram for a reason: a single picture says exactly what an interface-based design buys you.\\n\\n**`«enumeration»` and `«service»` are both stereotypes.** The enum keyword is a standard UML stereotype that swaps the rendering: literals sit in the attribute compartment without visibility glyphs, and there's no operations compartment populated. The `«service»` keyword on `CheckoutService` is a *custom* stereotype — any guillemet-wrapped word above a class name. Custom stereotypes are how teams tag classifiers with their architectural role (`«service»`, `«controller»`, `«entity»`, `«repository»`) without inventing new visual primitives.\\n\\n**Realization vs dependency at a glance.** The three concrete strategies *realize* the interface — dashed line, hollow triangle, drawn three times pointing at the same interface (a future render pass may merge the triangle heads into a single shared head). The `CheckoutService`'s relationship is a *dependency* — it uses both `PaymentStrategy` and `PaymentMethod` through its public API but does not commit to a structural containment. The dashed-line-with-open-arrow encoding makes the using-relationship visible without implying ownership.\\n\\nThe `Map` attribute type renders inline as text — generic type *names* are part of v0.1; parameterised classifier *boxes* (`List`) are deferred.\"\n },\n {\n \"slug\": \"umlclass-shape-hierarchy\",\n \"diagram\": \"umlclass\",\n \"title\": \"Shape class hierarchy with an interface\",\n \"description\": \"The canonical UML 2.5.1 class diagram — an interface, an abstract base class, and two concrete leaves — showing generalization, realization, and a generalization-driven layered layout where parents float to the top.\",\n \"standard\": \"OMG UML 2.5.1 §9–§11\",\n \"tags\": [\n \"umlclass\",\n \"uml\",\n \"generalization\",\n \"realization\",\n \"interface\",\n \"abstract-class\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"umlclass\\ntitle: \\\"Shape hierarchy\\\"\\n\\n«interface» Shape {\\n + area() : double\\n + perimeter() : double\\n}\\n\\nabstract class AbstractShape {\\n # name : String\\n + area() : double {abstract}\\n + perimeter() : double {abstract}\\n + describe() : String\\n}\\n\\nclass Circle {\\n + radius : double\\n + area() : double\\n + perimeter() : double\\n}\\n\\nclass Square {\\n + side : double\\n + area() : double\\n + perimeter() : double\\n}\\n\\nShape <|.. AbstractShape\\nAbstractShape <|-- Circle\\nAbstractShape <|-- Square\",\n \"notes\": \"## What this shows\\n\\nThe smallest diagram that exercises the three notations every UML primer covers in the first hour: an **interface** (rendered with the `«interface»` keyword), an **abstract class** (rendered in *italics*, with an abstract `area()` operation also in italics), and two concrete leaves.\\n\\n**Layering is generalization-driven.** Inheritance edges (`<|--`) and realization edges (`<|..`) define the rank hierarchy, so the interface floats to the very top, the abstract base sits below it, and the two concrete classes anchor the bottom — without any author-side layout hints. This is the visual default a UML textbook expects, and it's why a class diagram should not ride a generic flowchart layout.\\n\\n**Adornments carry the semantics.** Realization is dashed + hollow triangle; generalization is solid + hollow triangle. The two distinctions render identically in `theme: monochrome` because the meaning is in the shape, not the colour — exactly the point of UML 2.5.1.\"\n },\n {\n \"slug\": \"usecase-atm\",\n \"diagram\": \"usecase\",\n \"title\": \"ATM use case diagram (UML)\",\n \"description\": \"The canonical software-engineering use case diagram — a Customer and an external Bank system around an ATM, with four withdraw/deposit/balance/transfer use cases. Exercises stick-figure actors, the external-system rectangle, subject sizing, and primary/supporting actor flanking.\",\n \"standard\": \"OMG UML 2.5.1 §18\",\n \"tags\": [\n \"usecase\",\n \"uml\",\n \"requirements\",\n \"actor\",\n \"subject\"\n ],\n \"complexity\": 1,\n \"featured\": true,\n \"dsl\": \"usecase\\ntitle: \\\"ATM\\\"\\nsystem: \\\"ATM System\\\"\\n\\nactor: Customer\\nactor: Bank (external)\\n\\nusecase: \\\"Withdraw Cash\\\" as Withdraw\\nusecase: \\\"Deposit Funds\\\" as Deposit\\nusecase: \\\"Check Balance\\\" as Check\\nusecase: \\\"Transfer Funds\\\" as Transfer\\n\\nCustomer -- Withdraw\\nCustomer -- Deposit\\nCustomer -- Check\\nCustomer -- Transfer\\n\\nWithdraw -- Bank\\nDeposit -- Bank\\nCheck -- Bank\\nTransfer -- Bank\",\n \"notes\": \"The ATM is the hello-world of UML use case diagrams — it appears in nearly every software-engineering textbook because it shows the whole notation with no clutter. The diagram answers \\\"what can you do at an ATM, and who does the work behind the scenes?\\\"\\n\\n**Two actors, two roles.** `Customer` is the **primary actor** — the human who initiates the interaction — so Schematex places the stick figure on the **left**. `Bank` is declared `(external)`, marking it as another software system rather than a person; it renders as a rectangle carrying the `«actor»` stereotype and is placed on the **right** as a supporting actor. This left-primary / right-supporting convention comes from the Bittner & Spence style guide and matches what reviewers expect to see.\\n\\n**Four use cases, one subject.** Each `usecase:` becomes an ellipse, and the `system: \\\"ATM System\\\"` header wraps them in a rounded **subject** rectangle with the system name at the top. The subject is sized *after* the use cases are placed, so it always hugs its contents.\\n\\n**Plain associations.** Every `--` line is an undirected association — a solid line from the actor to the use-case ellipse perimeter. The Customer triggers all four operations; each operation in turn talks to the Bank to settle the transaction. There are no `«include»` or `«extend»` relationships here — that's deliberate. The ATM diagram's job is to establish *scope*, and at this level of detail plain associations are exactly right. Reach for include/extend only when use cases genuinely compose.\"\n },\n {\n \"slug\": \"usecase-online-bookstore\",\n \"diagram\": \"usecase\",\n \"title\": \"Online bookstore use case diagram (include + extend)\",\n \"description\": \"An e-commerce checkout use case diagram showing «include» chains, an «extend» relationship with a condition and extension point, and the extension-point compartment inside the base ellipse. A primary customer, an external payment gateway, and a supporting warehouse actor.\",\n \"standard\": \"OMG UML 2.5.1 §18\",\n \"tags\": [\n \"usecase\",\n \"uml\",\n \"include\",\n \"extend\",\n \"extension-point\",\n \"requirements\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"usecase\\ntitle: \\\"Online Bookstore — Checkout\\\"\\nsystem: \\\"Bookstore System\\\"\\n\\nactor: Customer\\nactor: \\\"Payment Gateway\\\" as PG (external)\\nactor: \\\"Warehouse Staff\\\" as WH\\n\\nusecase: \\\"Browse Catalog\\\" as Browse\\nusecase: \\\"Add to Cart\\\" as AddCart\\nusecase: \\\"Checkout\\\" as Checkout {\\n extension point: payment failed\\n extension point: stock depleted\\n}\\nusecase: \\\"Pay\\\" as Pay\\nusecase: \\\"Validate Card\\\" as ValidateCard\\nusecase: \\\"Cancel Order\\\" as Cancel\\nusecase: \\\"Ship Order\\\" as Ship\\n\\nCustomer -- Browse\\nCustomer -- AddCart\\nCustomer -- Checkout\\nCheckout ..> Pay : «include»\\nPay ..> ValidateCard : «include»\\nPay -- PG\\nCancel <.. Checkout : «extend» [payment failed] (extension point: payment failed)\\nShip -- WH\\nCheckout ..> Ship : «include»\",\n \"notes\": \"This is the diagram a business analyst hands to engineering when an online store is being scoped. It uses every relationship in the use case vocabulary, and each one means something precise.\\n\\n**Three actors on two sides.** `Customer` is the primary actor (left). `Payment Gateway` is `(external)` — a third-party system, drawn as an `«actor»` rectangle on the right. `Warehouse Staff` is a supporting human actor, also on the right. Schematex flanks the subject automatically.\\n\\n**`«include»` — mandatory composition.** `Checkout ..> Pay` reads \\\"Checkout *includes* Pay\\\": every checkout always runs the payment sub-flow, so the arrow points from the base toward the included use case. The chain continues — `Pay ..> ValidateCard` — so payment always validates the card. Include is the right tool when a step *always* happens and you want to factor it out for reuse. The dashed line, open arrowhead, and `«include»` pill are all UML-standard.\\n\\n**`«extend»` — optional, conditional behavior.** `Cancel <.. Checkout` reads \\\"Cancel Order *extends* Checkout\\\": cancellation is *optional* behavior that only kicks in under a condition. The `[payment failed]` clause is that condition, and `(extension point: payment failed)` ties it to the named extension point declared inside the Checkout ellipse. Note the arrow still points at the base (Checkout) even though Cancel is written first — that's the UML rule, and Schematex normalises it for you. Extend lines are drawn in the accent color because they're the rarer, more surprising relationship.\\n\\n**Extension points live in the ellipse.** Because `Checkout` declares `extension point: payment failed` and `stock depleted`, those appear in a compartment below the name, separated by a divider. They're the hooks an `«extend»` relationship can attach to.\\n\\nThe result reads top-to-bottom as a flow: browse → add to cart → checkout, with checkout fanning out into pay (→ validate card, → payment gateway), ship (→ warehouse), and an optional cancel path. That's exactly the scope picture a stakeholder review needs.\"\n },\n {\n \"slug\": \"venn-customer-segments\",\n \"diagram\": \"venn\",\n \"title\": \"Customer segment overlap\",\n \"description\": \"Three-set Venn showing email subscriber, paid-user, and mobile-app-user overlap with counts for every region — useful for lifecycle marketing planning.\",\n \"standard\": \"Venn (1880)\",\n \"tags\": [\n \"segmentation\",\n \"marketing\",\n \"analytics\",\n \"venn\",\n \"audience\"\n ],\n \"complexity\": 2,\n \"featured\": true,\n \"dsl\": \"venn \\\"Customer Segments — Q3 2025\\\"\\nset email \\\"Email subscribers\\\" [color: \\\"#1E88E5\\\"]\\nset paid \\\"Paid users\\\" [color: \\\"#E53935\\\"]\\nset mobile \\\"Mobile app users\\\" [color: \\\"#43A047\\\"]\\nemail & paid : 1840\\nemail & mobile : 920\\npaid & mobile : 2100\\nemail & paid & mobile : 650\\nemail only : 12400\\npaid only : 3200\\nmobile only : 8700\",\n \"notes\": \"## Scenario\\n\\nA lifecycle marketer is planning Q4 campaigns and needs to see which audiences overlap before deciding where to spend budget. The 650-strong triple intersection is the highest-LTV segment; the 12.4k email-only group is the biggest conversion opportunity. Putting the numbers on one Venn makes the gaps and overlaps argue for themselves in a 30-second leadership review.\\n\\n## Annotation key\\n\\n- `set ID \\\"Label\\\"` — declare a circle\\n- `A & B : n` — count in the intersection of A and B\\n- `A only : n` — count exclusive to A\\n\\n## How to read\\n\\nEach circle is a total audience; each overlap is people who belong to multiple audiences. The triple intersection (email ∩ paid ∩ mobile, 650 users) is your most engaged cohort — the obvious group to upsell. The *email only* and *mobile only* exclusive regions are your largest activation opportunities because each represents users who have not yet crossed into the other channels.\"\n },\n {\n \"slug\": \"venn-programming-paradigms\",\n \"diagram\": \"venn\",\n \"title\": \"Programming paradigm overlap\",\n \"description\": \"Venn diagram showing the intersection of object-oriented, functional, and logic programming paradigms with language counts — a teaching aid for CS curricula.\",\n \"standard\": \"Venn (1880)\",\n \"tags\": [\n \"education\",\n \"programming\",\n \"paradigms\",\n \"venn\",\n \"teaching\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"venn \\\"Programming Paradigms\\\"\\nset oop \\\"Object-Oriented\\\" [color: \\\"#1E88E5\\\"]\\nset fp \\\"Functional\\\" [color: \\\"#E53935\\\"]\\nset logic \\\"Logic\\\" [color: \\\"#43A047\\\"]\\noop & fp : 180\\noop & logic : 45\\nfp & logic : 90\\noop & fp & logic : 12\\noop only : 620\\nfp only : 340\\nlogic only : 95\",\n \"notes\": \"## Scenario\\n\\nA CS instructor opens a lecture on programming paradigms with this Venn. Counts come from a language survey — how many languages offer strong OOP, FP, and logic support. The tiny triple-overlap (12) tells students that languages supporting all three well are rare; the large OOP-only region shows industry gravity; the FP ∩ logic overlap (90) is where languages like Prolog-with-lambdas sit.\\n\\n## Annotation key\\n\\n- `set ID \\\"Label\\\"` — paradigm circle\\n- `A & B : n` — number of languages supporting both paradigms strongly\\n- `A only : n` — languages committed to a single paradigm\\n\\n## How to read\\n\\nEach circle represents a paradigm. Overlapping regions count multi-paradigm languages. The `oop & fp` intersection (180) is where modern mainstream languages — Scala, Kotlin, Swift, TypeScript — sit. The tiny triple intersection (12) is a reminder that truly multi-paradigm language design is expensive; the larger exclusive regions show how few languages commit to logic programming at all.\"\n }\n];\n\nexport const SYNTAX: Readonly<Record<string, GeneratedSyntax>> = {\n \"genogram\": {\n \"title\": \"Genogram\",\n \"content\": \"## 1. Your first genogram\\n\\nThe smallest clinically useful genogram: two parents, one child.\\n\\n```\\ngenogram\\n alice [female, 1980]\\n bob [male, 1978]\\n alice -- bob \\\"m. 2005\\\"\\n carol [female, 2008]\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `genogram`, optionally followed by a quoted title.\\n2. Declare each person on their own line: `id [attributes]`. Attributes go in square brackets, comma-separated.\\n3. Connect two people with a **couple operator** — `--` (marriage) here; see §4.1 for all six. A trailing quoted string is the relationship label.\\n4. **Indent under the couple line** to add their children.\\n\\n> Comments must be on their own line, starting with `#`, `//`, or Mermaid-style `%%`. Trailing inline comments (`bob [male, 1978] # ...`) are not supported and will break the parser — see §8.\\n\\n---\\n\\n## 2. Individuals\\n\\nAn individual line is `id [attr1, attr2, …]`. Attributes are comma-separated, order-independent, all optional.\\n\\n**ID rules.** Must match `[a-zA-Z][a-zA-Z0-9_-]*`. IDs are case-insensitive internally but preserve their original casing as the display label (override with `label:\\\"…\\\"`).\\n\\n**Attributes accepted by the parser today:**\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| Sex | `male`, `female`, `unknown`, `other` | Shape: square, circle, diamond, diamond |\\n| Status | `deceased`, `stillborn`, `miscarriage`, `abortion` | Visual modifier (X-out, scaled shape, etc.) |\\n| Birth year | 4-digit number, e.g. `1980` | First 4-digit token = birth year |\\n| Death year | 4-digit number after birth, e.g. `1980, 2055` | Second 4-digit token = death year |\\n| `index` | flag | Concentric shape = identified patient |\\n| `unknown-siblings` | flag | Diamond with `?` — placeholder for ≥1 siblings of unknown count |\\n| `age:N` | e.g. `age:42` | Age shown inside shape |\\n| `death:YYYY` | e.g. `death:2020` | Explicit death year |\\n| `label:\\\"…\\\"` | e.g. `label:\\\"Dr. Smith\\\"` | Display label override |\\n| `sibling-of:<id>` | e.g. `sibling-of:monica` | Pins same generation as the referenced sibling, draws a dashed bracket — for known relatives with unknown ancestry. |\\n| `conditions:…` | see §5 | Medical/psychological conditions |\\n| `key:value` | any custom | Stored as metadata |\\n\\n```\\ngenogram\\n grandma [female, 1920, 2002, deceased]\\n dad [male, 1950, age:74]\\n me [male, 1985, index]\\n daughter [female, 2012, label:\\\"Em\\\"]\\n```\\n\\n---\\n\\n## 3. Shapes\\n\\n| Visual | Sex value | Meaning |\\n|---|---|---|\\n| ☐ Square | `male` | Male |\\n| ○ Circle | `female` | Female |\\n| ◇ Diamond | `unknown`, `other`, *or* attribute omitted | Unknown / unspecified |\\n\\nStatus modifiers layer on top of the base shape:\\n\\n```\\ngenogram\\n alive [male, 1960]\\n passed [male, 1930, 2010, deceased]\\n stillborn_child [unknown, stillborn]\\n lost [unknown, miscarriage]\\n```\\n\\n---\\n\\n## 4. Connections\\n\\n### 4.1 Couple operators\\n\\nThe parser tries these in order. The first one that matches wins — so `-x-` beats `--`.\\n\\n| Operator | Type | Example | Meaning |\\n|---|---|---|---|\\n| `-x-` | divorced | `a -x- b` | Divorce |\\n| `-/-` | separated | `a -/- b` | Separation (married) |\\n| `-//` | separated | `a -// b` | Separation (alias for `-/-`) |\\n| `-o-` | engaged | `a -o- b` | Engagement |\\n| `==` | consanguineous | `a == b` | Blood-related couple |\\n| `--` | married | `a -- b` | Marriage |\\n| `~` | cohabiting | `a ~ b` | Cohabiting / LTR (current) |\\n| `~/~` | cohabiting-ended | `a ~/~ b` | Cohabitation has ended (never-married). Common in LATAM child-protection caseloads where biological parents lived together unmarried and the relationship has since broken — distinct from `-x-` divorce (no marriage) and `-/-` separation (still married). |\\n\\nA trailing quoted string becomes the relationship label (`a -- b \\\"m. 2005\\\"`).\\n\\n### 4.2 Inline individual on the right side\\n\\nIf the right-hand person hasn't been declared yet, you can declare them in-place:\\n\\n```\\ngenogram\\n ann [female, 1970]\\n ann -- ben [male, 1968] \\\"m. 1995\\\"\\n kim [female, 1997]\\n```\\n\\n### 4.3 Children (indented under a couple)\\n\\nIndentation under a couple line = \\\"these are the children of this couple.\\\" Any indent greater than the couple's indent works; by convention use 2 more spaces. Children are rendered in order of declaration (render also sorts by birth year when present).\\n\\n```\\ngenogram\\n dad [male, 1950]\\n mom [female, 1952]\\n dad -- mom\\n eldest [male, 1975]\\n middle [female, 1978, adopted]\\n twin_a [male, 1985, twin-identical]\\n twin_b [male, 1985, twin-identical]\\n```\\n\\n**Special child attributes:**\\n\\n| Attribute | Effect |\\n|---|---|\\n| `adopted` | Adoption line style |\\n| `foster` | Foster relationship |\\n| `guardian` | Guardianship by a non-parent relative (e.g. grandparent custody). Same primitive as `foster` — drawn as a secondary \\\"current caregiver\\\" link when biological parents are also declared. |\\n| `twin-identical` | Grouped with other `twin-identical` children of the same couple |\\n| `twin-fraternal` | Grouped with other `twin-fraternal` children |\\n| `unknown-siblings` | Single diamond with `?` glyph — \\\"≥1 siblings, count and identities unknown\\\" (pedigree convention). |\\n\\n### 4.3.1 Dual-parent families (foster, adoption, guardianship)\\n\\nChildren placed with a non-biological caregiver while biological parents are still part of the case can be declared under both couples. **Declare the child with full attributes the first time** (under the biological couple), then **redeclare with just `[foster]` / `[adopted]` / `[guardian]`** under the current caregiver. The first declaration wins layout; the second is drawn as a secondary dotted \\\"current caregiver\\\" link that does not pull the child away from their biological position.\\n\\n```\\ngenogram \\\"Foster placement\\\"\\n bp1 [male, label: \\\"Bio dad\\\"]\\n bp2 [female, label: \\\"Bio mom\\\"]\\n bp1 ~/~ bp2\\n child [male, 2018, index]\\n fp1 [male, label: \\\"Foster dad\\\"]\\n fp2 [female, label: \\\"Foster mom\\\"]\\n fp1 -- fp2\\n own [male, 2010]\\n child [foster]\\n```\\n\\nThe same primitive serves adoption (closed/open), foster placement, and guardianship by a relative — only the keyword differs. Re-declaration **merges** non-conflicting attributes (sex, birth year, label, `index` marker) into the original; declaring a conflicting `male` vs `female` raises a parse error rather than silently overwriting.\\n\\n### 4.3.2 Unknown-count siblings\\n\\nWhen a case file mentions \\\"the child has siblings\\\" without naming them, use either the `?` shorthand on its own line, or `[unknown-siblings]` on a regular id. Both render as a single diamond with a \\\"?\\\" glyph — the standard pedigree marker for \\\"one or more siblings, identities unknown.\\\"\\n\\n```\\ngenogram\\n dad [male]\\n mom [female]\\n dad -- mom\\n ?\\n known_kid [male, 2018]\\n```\\n\\n### 4.3.3 Sibling-of (known relative, unknown ancestry)\\n\\nTo express \\\"X is a sibling of Y\\\" without inventing parents, use the `sibling-of: <id>` property. The renderer pins X to Y's generation and draws a dashed bracket above the two — the standard pedigree convention for a known relative whose ancestry is not part of the case.\\n\\n```\\ngenogram\\n monica [female, 1990]\\n uncle [male, label: \\\"Tío materno\\\", sibling-of: monica]\\n```\\n\\n### 4.4 Emotional relationships\\n\\nSeparate line, parser pattern `A -TYPE- B` (non-directional) or `A -TYPE-> B` (directional). An optional quoted label goes at the end. **Both individuals must already be declared** before the emotional line.\\n\\n```\\nharry -cutoff- petunia # non-directional\\nharry -hostile- dudley \\\"since 1991\\\"\\nuncle -abuse-> nephew # directional (arrow)\\n```\\n\\nAll 32 types the parser accepts today:\\n\\n| Category | Types |\\n|---|---|\\n| Positive / close | `harmony`, `close`, `bestfriends`, `love`, `inlove`, `friendship` |\\n| Negative / hostile | `hostile`, `conflict`, `enmity`, `distant-hostile`, `cutoff` |\\n| Ambivalent | `close-hostile`, `fused`, `fused-hostile` |\\n| Distance | `distant`, `normal`, `nevermet` |\\n| Abuse *(directional)* | `abuse`, `physical-abuse`, `emotional-abuse`, `sexual-abuse`, `neglect` |\\n| Control *(directional)* | `manipulative`, `controlling`, `jealous` |\\n| Special | `focused`, `focused-neg`, `distrust`, `admirer`, `limerence` |\\n\\n```\\ngenogram\\n dad [male, 1950]\\n son [male, 1985]\\n daughter [female, 1988]\\n dad -close- daughter\\n dad -conflict- son\\n son -cutoff- dad \\\"since 2010\\\"\\n```\\n\\n---\\n\\n## 5. Medical conditions\\n\\nSyntax: `conditions: name(fill) [+ name(fill, #color)]…`\\n\\n```\\nfather [male, 1945, conditions: heart(full, #E53935)]\\nmother [female, 1948, conditions: diabetes(half-left) + anxiety(half-right, #26A69A)]\\n```\\n\\n- **`name`** — any identifier you choose (displayed in legend/tooltip).\\n- **`fill`** — required, controls which region of the shape is colored. See table below.\\n- **`color`** — optional hex. Default depends on the renderer theme.\\n- Multiple conditions are joined with `+`. Each needs its own `(fill)`.\\n\\n**Fill positions:**\\n\\n| `fill` value | Region |\\n|---|---|\\n| `full` | Entire shape |\\n| `half-left` / `half-right` | Left / right half |\\n| `half-top` / `half-bottom` | Top / bottom half |\\n| `quad-tl` / `quad-tr` / `quad-bl` / `quad-br` | One quadrant |\\n| `striped` | Diagonal stripe pattern (asymptomatic carrier) |\\n| `dotted` | Dot pattern |\\n\\n```\\ngenogram\\n dad [male, 1950, conditions: heart(full, #E53935)]\\n mom [female, 1952, conditions: diabetes(half-left) + depression(half-right, #5C6BC0)]\\n dad -- mom\\n son [male, 1980, conditions: carrier(striped)]\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `genogram \\\"Smith Family\\\"` — first line only.\\n- **Person label override:** `alice [female, label:\\\"Dr. Alice Smith\\\"]`.\\n- **Relationship label:** trailing quoted string on a couple or emotional line — `alice -- bob \\\"m. 2005\\\"`.\\n- **Comments:** `#`, `//`, or `%%` at the start of a line (after leading whitespace). Inline comments are **not** supported.\\n\\n```\\ngenogram \\\"Smith Family\\\"\\n # this line is a comment — fine\\n %% Mermaid-style comment — also fine\\n alice [female, 1980] # ← THIS trailing comment breaks the parser\\n```\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `genogram` (header keyword).\\n\\n**Reserved operator tokens** inside a line — avoid using these sequences in IDs:\\n`--`, `~`, `~/~`, `==`, `-x-`, `-/-`, `-//`, `-o-`, and any `-<type>-` / `-<type>->` matching an emotional-relationship type.\\n\\n**Reserved id `?`** — bare `?` on a child line auto-generates a synthetic placeholder with the `unknown-siblings` marker. Do not use `?` as a real id.\\n\\n**Strings with spaces** must be double-quoted: titles, labels, `label:\\\"…\\\"`. Single quotes and backticks are not recognized.\\n\\n---\\n\\n## 8. Common mistakes\\n\\nReal parser errors, what triggers them, and how to fix.\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `alex [nonbinary, 1995]` | `Unknown property 'nonbinary'` | Use `unknown` or `other` (nonbinary is §13 Roadmap) |\\n| `alice [female, transgender]` | `Unknown property 'transgender'` | Not yet parseable (§13 Roadmap) |\\n| `dad -- mom` ← followed by `child [male, 2010]` at the **same indent** | Child parsed as a new top-level individual, not as their child | Indent the child line deeper than the couple line (2 spaces is enough) |\\n| `A -- B` where `A` was never declared | `Unknown individual 'A'` | Declare `A [sex, year]` on a line above |\\n| `father -- mother \\\"married\\\"` on line 1 (no `genogram` header) | `Expected \\\"genogram\\\" header` | Start the file with `genogram` or `genogram \\\"Title\\\"` |\\n| `conditions: diabetes + cancer` (no parens) | `Invalid condition format 'diabetes'` | Add fill: `conditions: diabetes(half-left) + cancer(half-right)` |\\n| `[triplet-identical]` | `Unknown property 'triplet-identical'` | Triplets not yet parseable (§13 Roadmap) |\\n| `dad -- mom # first marriage` | Trailing inline `#` comment is treated as part of the label / errors | Move the comment to its own line |\\n| Same id declared twice with different sex (`x [male]` then `x [female]`) | `Conflicting sex for 'x': previously 'male', now 'female'` | Pick one or rename one of the ids |\\n| `child [foster]` redeclared but biological parents never declared | `child` becomes the foster couple's regular child (no secondary link drawn) | This is intentional — secondary links require an existing primary parent-child rel from a prior declaration |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | individual | couple-block | emotional)*\\n\\nheader = \\\"genogram\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nindividual = INDENT id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\ncouple-block = INDENT id WS coupleOp WS right-side ( WS quoted-string )? NEWLINE\\n ( deeper-indent child )*\\nchild = INDENT id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\n | INDENT \\\"?\\\" NEWLINE // unknown-count sibling shorthand\\nright-side = id ( \\\"[\\\" attrs \\\"]\\\" )?\\n\\nemotional = INDENT id WS \\\"-\\\" type \\\"-\\\" id ( WS quoted-string )? NEWLINE\\n | INDENT id WS \\\"-\\\" type \\\"->\\\" id ( WS quoted-string )? NEWLINE\\n\\ncoupleOp = \\\"~/~\\\" | \\\"-//\\\" | \\\"-x-\\\" | \\\"-/-\\\" | \\\"-o-\\\" | \\\"==\\\" | \\\"--\\\" | \\\"~\\\"\\ntype = \\\"harmony\\\" | \\\"close\\\" | \\\"bestfriends\\\" | \\\"love\\\" | \\\"inlove\\\"\\n | \\\"friendship\\\" | \\\"hostile\\\" | \\\"conflict\\\" | \\\"enmity\\\"\\n | \\\"distant-hostile\\\" | \\\"cutoff\\\" | \\\"close-hostile\\\" | \\\"fused\\\"\\n | \\\"fused-hostile\\\" | \\\"distant\\\" | \\\"normal\\\" | \\\"nevermet\\\"\\n | \\\"abuse\\\" | \\\"physical-abuse\\\" | \\\"emotional-abuse\\\"\\n | \\\"sexual-abuse\\\" | \\\"neglect\\\" | \\\"manipulative\\\" | \\\"controlling\\\"\\n | \\\"jealous\\\" | \\\"focused\\\" | \\\"focused-neg\\\" | \\\"distrust\\\"\\n | \\\"admirer\\\" | \\\"limerence\\\"\\n\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\nattrs = attr (\\\",\\\" attr)*\\nattr = \\\"male\\\" | \\\"female\\\" | \\\"unknown\\\" | \\\"other\\\"\\n | \\\"deceased\\\" | \\\"stillborn\\\" | \\\"miscarriage\\\" | \\\"abortion\\\"\\n | \\\"adopted\\\" | \\\"foster\\\" | \\\"guardian\\\"\\n | \\\"twin-identical\\\" | \\\"twin-fraternal\\\"\\n | \\\"index\\\" | \\\"unknown-siblings\\\"\\n | digit digit digit digit // year\\n | \\\"age\\\" \\\":\\\" digits\\n | \\\"death\\\" \\\":\\\" digit digit digit digit\\n | \\\"label\\\" \\\":\\\" quoted-string\\n | \\\"sibling-of\\\" \\\":\\\" id\\n | \\\"conditions\\\" \\\":\\\" condition (\\\"+\\\" condition)*\\n | key \\\":\\\" value // custom\\ncondition = name \\\"(\\\" fill (\\\",\\\" \\\"#\\\" hex)? \\\")\\\"\\nfill = \\\"full\\\" | \\\"half-left\\\" | \\\"half-right\\\" | \\\"half-top\\\" | \\\"half-bottom\\\"\\n | \\\"quad-tl\\\" | \\\"quad-tr\\\" | \\\"quad-bl\\\" | \\\"quad-br\\\"\\n | \\\"striped\\\" | \\\"dotted\\\"\\n\\ncomment = INDENT ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/genogram/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"ecomap\": {\n \"title\": \"Ecomap\",\n \"content\": \"## 1. Your first ecomap\\n\\nThe smallest useful ecomap: one center and three outside systems.\\n\\n```\\necomap\\n center: client [label: \\\"Maria\\\"]\\n mom [label: \\\"Mother\\\", category: family]\\n work [label: \\\"Tech Corp\\\", category: work]\\n therapist [label: \\\"Dr. Patel\\\", category: mental-health]\\n mom === client\\n work --- client\\n therapist <-> client [label: \\\"weekly\\\"]\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `ecomap`, optionally followed by a quoted title.\\n2. Declare the center on its own line: `center: id [label: \\\"…\\\"]`. Exactly one center per diagram.\\n3. Declare each outside system on its own line: `id [label: \\\"…\\\", category: …]`.\\n4. Connect any two declared IDs with a **connection operator** — `===` (strong), `---` (normal), `<->` (reciprocal), etc. See §3 for the full table. A trailing `[label: \\\"…\\\"]` adds an edge label.\\n\\n> Comments must be on their own line, starting with `#`, `//`, or Mermaid-style `%%`. Inline trailing comments will break the parser.\\n\\n---\\n\\n## 2. Center and outside systems\\n\\nEvery ecomap has one **center** and any number of **outside systems**. Both use the same `id [attrs]` syntax; the only difference is the `center:` prefix.\\n\\n**ID rules.** Must match `[a-zA-Z][a-zA-Z0-9_-]*`. IDs are case-insensitive; the original token is kept as the default label.\\n\\n**Attributes accepted by the parser today:**\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| `label:\\\"…\\\"` | any quoted string | Display label override |\\n| `category:…` | see §2.1 | Color / grouping of a system node |\\n| `size:…` | `small`, `medium`, `large` | Node size |\\n| `importance:…` | `major`, `moderate`, `minor` | Visual weight |\\n| `sector:…` | `top`, `right`, `bottom`, `left` | Hint for which side of the center the system sits on |\\n| `age:N` | e.g. `age:34` | Age shown inside a person-typed center |\\n| `male` / `female` / `unknown` | flag | Sex for a person-typed center |\\n\\n### 2.1 System categories\\n\\nCategories color-code outside systems by the life domain they belong to. The parser accepts any string — these are the values the renderer has themed palettes for:\\n\\n| Category | Typical examples |\\n|---|---|\\n| `family` | Extended family, in-laws, cousins |\\n| `friends` | Friends, neighbors |\\n| `work` | Employer, coworkers |\\n| `education` | School, college, training program |\\n| `health` | Primary care, specialist, hospital |\\n| `mental-health` | Therapist, psychiatrist, support group |\\n| `religion` | Church, temple, spiritual community |\\n| `recreation` | Sports, hobbies, clubs |\\n| `legal` | Lawyer, probation, court |\\n| `government` | Social services, housing, immigration |\\n| `financial` | Bank, benefits, financial aid |\\n| `community` | Neighborhood groups, sponsors |\\n| `cultural` | Cultural/ethnic organizations |\\n| `substance` | Recovery programs or, if negative, active-use sources |\\n| `technology` | Online community, support forum |\\n| `pet` | Pets, service animals |\\n\\n```\\necomap\\n center: client [label: \\\"Marcus, age 15\\\"]\\n mom [label: \\\"Mother\\\", category: family]\\n dad [label: \\\"Father (divorced)\\\", category: family]\\n school [label: \\\"East High School\\\", category: education]\\n coach [label: \\\"Soccer Coach\\\", category: community]\\n therapist [label: \\\"Ms. Chen\\\", category: mental-health]\\n mom === client\\n dad --- client [label: \\\"EOW weekends\\\"]\\n school === client\\n coach --> client [label: \\\"mentor\\\"]\\n therapist <-> client [label: \\\"weekly\\\"]\\n```\\n\\n---\\n\\n## 3. Connections\\n\\nA connection is one line: `fromId OP toId` optionally followed by `[label: \\\"…\\\"]`. Both IDs must already be declared (center counts).\\n\\n### 3.1 Relationship-quality operators\\n\\n| Operator | Type | Meaning |\\n|---|---|---|\\n| `===` | strong | Close, supportive, high-frequency |\\n| `==` | moderate | Positive, moderate involvement |\\n| `---` | normal | Neutral / average |\\n| `- -` | weak | Tenuous, fragile, early-stage |\\n| `~~~` | stressful | Stressful relationship |\\n| `~=~` | stressful-strong | Close *and* stressful |\\n| `~x~` | conflictual | Active conflict |\\n| `-/-` | broken | Severed, estranged, cutoff |\\n\\n### 3.2 Energy-flow operators\\n\\nLayer arrow direction onto strong or normal lines:\\n\\n| Operator | Meaning |\\n|---|---|\\n| `-->` | One-way: energy flows from center to system |\\n| `<--` | One-way: energy flows from system to center |\\n| `<->` | Reciprocal / bidirectional |\\n| `===>` | Strong one-way outflow (draining) |\\n| `<===` | Strong one-way inflow (nourishing) |\\n| `<=>` | Strong reciprocal |\\n| `==>` | Moderate one-way outflow |\\n| `<==` | Moderate one-way inflow |\\n\\nThe parser normalizes direction so arrows read relative to the center. Writing `family === resettlement` and `resettlement === family` produces the same diagram; writing `clinic --> family` vs `family <-- clinic` likewise produces the same arrow pointing *from* the clinic *to* the family.\\n\\n```\\necomap\\n center: client [label: \\\"Rosa\\\"]\\n mom [category: family]\\n ex [category: family]\\n aa [label: \\\"AA Group\\\", category: substance]\\n job [label: \\\"Warehouse\\\", category: work]\\n mom === client [label: \\\"daily calls\\\"]\\n ex ~x~ client [label: \\\"custody disputes\\\"]\\n aa <== client [label: \\\"sponsor support\\\"]\\n job - - client [label: \\\"unstable hours\\\"]\\n```\\n\\n### 3.3 Edge labels\\n\\nA trailing `[label: \\\"…\\\"]` is the only attribute a connection line accepts. Put schedule, nature, or a short note here:\\n\\n```\\nfamily === temple [label: \\\"weekly service\\\"]\\nclinic --> family [label: \\\"vaccinations\\\"]\\ncaseworker <-> family [label: \\\"every Tuesday\\\"]\\n```\\n\\n---\\n\\n## 4. Labels & comments\\n\\n- **Title:** `ecomap \\\"Nguyen Family\\\"` — first line only.\\n- **Node label override:** `family [label: \\\"The Nguyens\\\"]`.\\n- **Edge label:** trailing `[label: \\\"…\\\"]` on a connection line.\\n- **Mode suffix:** `ecomap:strengths \\\"Smith family\\\"` is accepted. The suffix is stored as `metadata.mode`; current renderers ignore it.\\n- **Comments:** `#`, `//`, or `%%` at the start of a line (after leading whitespace). Inline trailing comments are **not** supported.\\n\\n```\\necomap \\\"Marcus Intake\\\"\\n # caseworker's notes — fine\\n // also fine\\n %% Mermaid-style comments are fine\\n mom [category: family] # ← THIS trailing comment breaks the parser\\n```\\n\\n---\\n\\n## 5. Reserved words & escaping\\n\\n**Reserved at line start:** `ecomap`, `center:`.\\n\\n**Reserved operator tokens** inside a line — avoid using these sequences in IDs:\\n`===`, `==`, `---`, `- -`, `~~~`, `~=~`, `~x~`, `-/-`, and the directional variants listed in §3.2.\\n\\n**Strings with spaces** must be double-quoted: titles and any label. Single quotes and backticks are not recognized.\\n\\n---\\n\\n## 6. Common mistakes\\n\\nReal parser errors, what triggers them, and how to fix.\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `family -- school` | `Unexpected: family -- school` | Ecomap uses `===`/`---`/`<->` etc. `--` is a genogram/pedigree operator |\\n| `family === school` where `school` was never declared | Silently creates an empty `school` node with no label/category | Declare systems above their connection lines |\\n| No `center:` anywhere | Renders but with no visual center anchor | Every ecomap needs exactly one `center:` line |\\n| Two `center:` lines | Only the first is treated as center; the second becomes a regular system | Pick one |\\n| `family==school` (no spaces) | `Unexpected: family==school` | Operators require a space on each side |\\n| `family === school [weekly]` | Bare token `weekly` is parsed as a property flag, no label shown | Use `[label: \\\"weekly\\\"]` |\\n| `family === school # daily` | Trailing `#` is consumed as part of the line | Move the comment above |\\n\\n---\\n\\n## 7. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | center | system | connection)*\\n\\nheader = \\\"ecomap\\\" ( \\\":\\\" mode )? ( WS quoted-string )? NEWLINE\\nmode = [A-Za-z] [A-Za-z0-9_-]*\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\ncenter = \\\"center:\\\" WS id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\nsystem = id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\nconnection = id WS op WS id ( WS \\\"[\\\" \\\"label:\\\" quoted-string \\\"]\\\" )? NEWLINE\\n\\nop = \\\"===\\\" | \\\"==\\\" | \\\"---\\\" | \\\"- -\\\" | \\\"~~~\\\" | \\\"~=~\\\" | \\\"~x~\\\" | \\\"-/-\\\"\\n | \\\"===>\\\" | \\\"<===\\\" | \\\"<=>\\\" | \\\"==>\\\" | \\\"<==\\\"\\n | \\\"-->\\\" | \\\"<--\\\" | \\\"<->\\\"\\n\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\nattrs = attr (\\\",\\\" attr)*\\nattr = \\\"label\\\" \\\":\\\" quoted-string\\n | \\\"category\\\" \\\":\\\" category\\n | \\\"size\\\" \\\":\\\" (\\\"small\\\" | \\\"medium\\\" | \\\"large\\\")\\n | \\\"importance\\\" \\\":\\\" (\\\"major\\\" | \\\"moderate\\\" | \\\"minor\\\")\\n | \\\"sector\\\" \\\":\\\" (\\\"top\\\" | \\\"right\\\" | \\\"bottom\\\" | \\\"left\\\")\\n | \\\"age\\\" \\\":\\\" digits\\n | \\\"male\\\" | \\\"female\\\" | \\\"unknown\\\"\\n | key \\\":\\\" value // custom, stored as metadata\\n\\ncategory = \\\"family\\\" | \\\"friends\\\" | \\\"work\\\" | \\\"education\\\" | \\\"health\\\"\\n | \\\"mental-health\\\" | \\\"religion\\\" | \\\"recreation\\\" | \\\"legal\\\"\\n | \\\"government\\\" | \\\"financial\\\" | \\\"community\\\" | \\\"cultural\\\"\\n | \\\"substance\\\" | \\\"technology\\\" | \\\"pet\\\" | \\\"other\\\"\\n\\ncomment = ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/ecomap/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"pedigree\": {\n \"title\": \"Pedigree\",\n \"content\": \"## 1. Your first pedigree\\n\\nThe smallest clinically useful pedigree: two parents and their affected child.\\n\\n```\\npedigree\\n I-1 [male, carrier]\\n I-2 [female, carrier]\\n I-1 -- I-2\\n II-1 [male, affected, proband]\\n II-2 [female, unaffected]\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `pedigree`, optionally followed by a quoted title.\\n2. Declare each individual on their own line: `id [attributes]`. Conventionally IDs are `I-1`, `II-3`, etc. — Roman-numeral generation, dash, position within the generation.\\n3. Connect two individuals with a **couple operator** — `--` (mated), `==` (consanguineous), `-/-` (separated), `~` (no offspring). See §4.\\n4. **Indent under the couple line** to add their children. Any deeper indent works; two spaces is conventional.\\n\\n> Comments must be on their own line, starting with `#`, `//`, or Mermaid-style `%%`. Inline trailing comments will break the parser.\\n\\n---\\n\\n## 2. Individuals\\n\\nAn individual line is `id [attr1, attr2, …]`. Attributes are comma-separated, order-independent, all optional.\\n\\n**ID rules.** Must match `[a-zA-Z][a-zA-Z0-9_-]*`. IDs are case-insensitive internally but preserve their original casing as the display label (override with `label:\\\"…\\\"`).\\n\\n**Attributes accepted by the parser today:**\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| Sex | `male`, `female`, `unknown`, `amab`, `afab`, `uaab` | Shape: square, circle, diamond (see §3) |\\n| Genetic status | `unaffected`, `affected`, `carrier`, `carrier-x`, `obligate-carrier`, `presymptomatic` | Fill / inner marker (see §3) |\\n| Marker | `proband`, `consultand`, `evaluated` | Arrow + letter annotation (see §3.3) |\\n| Life status | `deceased`, `stillborn`, `pregnancy`, `sab`, `tab`, `ectopic` | Visual modifier |\\n| Birth year | 4-digit number, e.g. `1958` | Shown below shape |\\n| `label:\\\"…\\\"` | any quoted string | Display label override |\\n| `affected: trait1+trait2` | see §5 | Multi-trait quadrant fill |\\n\\n```\\npedigree\\n I-1 [male, 1942, deceased]\\n I-2 [female, 1945, affected, deceased]\\n II-1 [female, affected, proband, label: \\\"Jane (42)\\\"]\\n II-2 [male, evaluated]\\n II-3 [female, presymptomatic]\\n```\\n\\n---\\n\\n## 3. Shapes, status, markers\\n\\n### 3.1 Shapes (Bennett 2022)\\n\\n| Visual | Sex value | Meaning |\\n|---|---|---|\\n| ☐ Square | `male` or `amab` | Assigned male at birth |\\n| ○ Circle | `female` or `afab` | Assigned female at birth |\\n| ◇ Diamond | `unknown`, `uaab`, or omitted | Unknown / DSD / not disclosed / in utero |\\n\\nBennett 2022 formalized that square and circle represent **assigned sex at birth**, not gender identity. If gender identity differs, record it in the label (`[female, label: \\\"Trans man (AFAB)\\\"]`) — do not change the shape.\\n\\n### 3.2 Genetic status (fill)\\n\\n| Status | Meaning |\\n|---|---|\\n| (default, no status token) | Unaffected — empty shape |\\n| `unaffected` | Explicit unaffected |\\n| `affected` | Fully filled shape |\\n| `carrier` | Half-filled — autosomal carrier |\\n| `carrier-x` | Center dot — X-linked carrier female |\\n| `obligate-carrier` | Center dot — inferred from pedigree structure |\\n| `presymptomatic` | Vertical line through shape — tested positive, no clinical signs yet |\\n\\n```\\npedigree\\n I-1 [male, unaffected]\\n I-2 [female, affected]\\n I-3 [female, carrier]\\n I-4 [female, carrier-x]\\n I-5 [male, obligate-carrier]\\n I-6 [female, presymptomatic]\\n```\\n\\n### 3.3 Markers\\n\\n| Marker | Meaning |\\n|---|---|\\n| `proband` | Arrow + \\\"P\\\" — the index case who triggered the referral |\\n| `consultand` | Arrow + \\\"C\\\" — the person who sought genetic counseling |\\n| `evaluated` | \\\"E\\\" — evaluated but no positive finding recorded |\\n\\n### 3.4 Life status\\n\\n| Value | Meaning |\\n|---|---|\\n| `deceased` | Diagonal slash across the shape |\\n| `stillborn` | Small shape + \\\"SB\\\" label |\\n| `pregnancy` | Shape + \\\"P\\\" label, or diamond if sex unknown |\\n| `sab` | Small triangle — spontaneous abortion |\\n| `tab` | Small triangle with bar — terminated pregnancy |\\n| `ectopic` | Small triangle + \\\"ECT\\\" label |\\n\\nMultiple tokens combine: `[female, affected, deceased]`, `[male, sab]`, `[unknown, pregnancy, presymptomatic]`.\\n\\n---\\n\\n## 4. Couples and children\\n\\n### 4.1 Couple operators\\n\\nThe parser tries these in order. The first match wins — so `-/-` beats `--`.\\n\\n| Operator | Type | Example | Meaning |\\n|---|---|---|---|\\n| `-/-` | separated | `a -/- b` | Mated pair, no longer together |\\n| `==` | consanguineous | `a == b` | Blood-related union (clinically critical) |\\n| `--` | married | `a -- b` | Mated pair with offspring |\\n| `~` | cohabiting | `a ~ b` | Partners without offspring |\\n\\n### 4.2 Inline individual on the right side\\n\\nIf the right-hand individual has not been declared yet, declare them in place:\\n\\n```\\npedigree\\n I-1 [female, carrier]\\n I-1 -- I-2 [male, unaffected]\\n II-1 [female, affected, proband]\\n II-2 [male, carrier]\\n```\\n\\n### 4.3 Children (indented under a couple)\\n\\nIndentation under a couple line = \\\"these are the children of this couple.\\\" Any indent greater than the couple's indent works; two spaces is conventional.\\n\\n```\\npedigree \\\"Cystic Fibrosis — autosomal recessive\\\"\\n I-1 [male, carrier]\\n I-2 [female, carrier]\\n I-1 -- I-2\\n II-1 [male, affected, proband]\\n II-2 [female, carrier]\\n II-3 [male, unaffected]\\n```\\n\\n### 4.4 Consanguineous unions\\n\\nConsanguinity is rendered as a double line and must be made visible — it is the single most load-bearing piece of information on many pedigrees.\\n\\n```\\npedigree \\\"Consanguineous union\\\"\\n I-1 [male, carrier]\\n I-2 [female, unaffected]\\n I-1 -- I-2\\n II-1 [male, carrier]\\n I-3 [male, unaffected]\\n I-4 [female, carrier]\\n I-3 -- I-4\\n II-3 [female, carrier]\\n II-1 == II-3\\n III-1 [male, affected, proband]\\n```\\n\\n---\\n\\n## 5. Multi-trait pedigrees\\n\\nFor families that carry more than one heritable condition, use `legend:` lines to define which quadrant of the shape represents which trait, then tag individuals with `affected: trait1+trait2`.\\n\\n```\\npedigree \\\"Cancer Family Syndrome\\\"\\n legend: breast = \\\"Breast cancer\\\" (fill: quad-tl)\\n legend: ovarian = \\\"Ovarian cancer\\\" (fill: quad-tr)\\n legend: prostate = \\\"Prostate cancer\\\" (fill: quad-bl)\\n legend: colon = \\\"Colon cancer\\\" (fill: quad-br)\\n\\n I-1 [male, affected: prostate, deceased]\\n I-2 [female, affected: breast, deceased]\\n I-1 -- I-2\\n II-1 [female, affected: breast+ovarian]\\n II-2 [male, unaffected]\\n```\\n\\n**Legend syntax:** `legend: id = \\\"Human label\\\" (fill: POSITION)`.\\n\\n| `fill` position | Region |\\n|---|---|\\n| `full` | Entire shape (default if `(fill: …)` omitted) |\\n| `quad-tl` / `quad-tr` / `quad-bl` / `quad-br` | Top-left / top-right / bottom-left / bottom-right quadrant |\\n| `half-left` / `half-right` / `half-top` / `half-bottom` | A half of the shape |\\n\\nIndividuals use the legend trait IDs: `[affected: breast]`, `[affected: breast+ovarian]`. The `+` joins traits; quadrants fill cumulatively.\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `pedigree \\\"BRCA1 Family\\\"` — first line only.\\n- **Individual label override:** `II-1 [female, affected, label: \\\"Jane Smith (42)\\\"]`.\\n- **Legend entry:** `legend: id = \\\"Label\\\" (fill: POSITION)` — see §5.\\n- **Mode suffix:** `pedigree:autosomal-dominant \\\"Family X\\\"` is accepted. The suffix is stored as `metadata.mode`; current renderers ignore it.\\n- **Comments:** `#`, `//`, or `%%` at the start of a line (after leading whitespace). Inline trailing comments are **not** supported.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `pedigree` (header), `legend:` (legend entry).\\n\\n**Reserved operator tokens** inside a line — avoid using these sequences in IDs:\\n`--`, `==`, `-/-`, `~`.\\n\\n**Reserved attribute tokens** inside `[…]` — the parser will interpret these regardless of position: sex tokens (`male`, `female`, `unknown`, `amab`, `afab`, `uaab`), genetic statuses (`affected`, `carrier`, `carrier-x`, `obligate-carrier`, `presymptomatic`, `unaffected`), markers (`proband`, `consultand`, `evaluated`), and life statuses (`deceased`, `stillborn`, `pregnancy`, `sab`, `tab`, `ectopic`).\\n\\n**Strings with spaces** must be double-quoted. Single quotes and backticks are not recognized.\\n\\n---\\n\\n## 8. Common mistakes\\n\\nReal parser errors, what triggers them, and how to fix.\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `II-1 -- II-4` where `II-4` was never declared | `Unknown individual 'II-4'` | Declare `II-4` above, or use inline form: `II-1 -- II-4 [male, unaffected]` |\\n| `II-1 [nonbinary]` | Silently stored as a custom property; shape stays diamond | Bennett 2022 distinguishes assigned sex from gender — use `amab`/`afab`/`uaab` and record identity in `label:` |\\n| `II-3 [twin-mz]` | Stored as a custom property; no twin line rendered | Twin notation is §10 Roadmap |\\n| `I-1 -- I-2` followed by `II-1 [male]` at the **same indent** | Child parsed as a new top-level individual, not as offspring | Indent the child line deeper than the couple line |\\n| `I-1 [affected: breast]` with no matching `legend:` | Trait ID stored but no legend-keyed fill is rendered | Add `legend: breast = \\\"…\\\" (fill: quad-tl)` above |\\n| `II-1[affected]` (no space, no attrs split) | Works for a single token; breaks when a second attribute is added | Always separate `id` and `[…]` with a space |\\n| Line 1 is `I-1 [male]` with no `pedigree` header | `Expected \\\"pedigree\\\" header` | Start with `pedigree` or `pedigree \\\"Title\\\"` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | legend | individual | couple-block)*\\n\\nheader = \\\"pedigree\\\" ( \\\":\\\" mode )? ( WS quoted-string )? NEWLINE\\nmode = [A-Za-z] [A-Za-z0-9_-]*\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nlegend = INDENT \\\"legend:\\\" WS id WS \\\"=\\\" WS quoted-string\\n ( WS \\\"(\\\" \\\"fill:\\\" fill-value \\\")\\\" )? NEWLINE\\n\\nindividual = INDENT id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\ncouple-block = INDENT id WS coupleOp WS right-side NEWLINE\\n ( deeper-indent child )*\\nchild = INDENT id ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\nright-side = id ( \\\"[\\\" attrs \\\"]\\\" )?\\n\\ncoupleOp = \\\"-/-\\\" | \\\"==\\\" | \\\"--\\\" | \\\"~\\\"\\n\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\nattrs = attr (\\\",\\\" attr)*\\nattr = sex\\n | genetic-status\\n | marker\\n | life-status\\n | digit digit digit digit // birth year\\n | \\\"label\\\" \\\":\\\" quoted-string\\n | \\\"affected\\\" \\\":\\\" trait-id ( \\\"+\\\" trait-id )*\\n | key \\\":\\\" value // custom\\n\\nsex = \\\"male\\\" | \\\"female\\\" | \\\"unknown\\\" | \\\"amab\\\" | \\\"afab\\\" | \\\"uaab\\\"\\ngenetic-status = \\\"unaffected\\\" | \\\"affected\\\" | \\\"carrier\\\" | \\\"carrier-x\\\"\\n | \\\"obligate-carrier\\\" | \\\"presymptomatic\\\"\\nmarker = \\\"proband\\\" | \\\"consultand\\\" | \\\"evaluated\\\"\\nlife-status = \\\"deceased\\\" | \\\"stillborn\\\" | \\\"pregnancy\\\"\\n | \\\"sab\\\" | \\\"tab\\\" | \\\"ectopic\\\"\\nfill-value = \\\"full\\\" | \\\"half-left\\\" | \\\"half-right\\\" | \\\"half-top\\\" | \\\"half-bottom\\\"\\n | \\\"quad-tl\\\" | \\\"quad-tr\\\" | \\\"quad-bl\\\" | \\\"quad-br\\\"\\n\\ncomment = INDENT ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/pedigree/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"phylo\": {\n \"title\": \"Phylogenetic tree\",\n \"content\": \"## 1. Your first phylogenetic tree\\n\\nThe smallest useful tree: four taxa, two clades.\\n\\n```\\nphylo \\\"Vertebrates\\\"\\n newick: \\\"((Human:0.1,Chimp:0.08):0.03,(Dog:0.35,Cat:0.30):0.2);\\\"\\n```\\n\\nThree rules cover 80% of usage:\\n\\n1. Start with `phylo`, optionally followed by a quoted title and bracket props.\\n2. Provide the tree topology in `newick:` format — the standard Newick string, quoted, on one line. The trailing `;` is optional.\\n3. Optionally define **clade** highlight groups and a **scale** label below the newick line.\\n\\n> Comments must start with `#` on their own line. Inline trailing comments are not supported.\\n\\n---\\n\\n## 2. Input formats\\n\\n### 2.1 Newick format\\n\\nNewick is the primary input. The full grammar is:\\n\\n```\\n(A,B,(C,D)); # topology only\\n(A:0.1,B:0.2,(C:0.3,D:0.4):0.5); # with branch lengths\\n((A:0.1,B:0.2):0.05[&&NHX:B=98],(C,D):0.08); # NHX bootstrap\\n('Homo sapiens':0.1,'Mus musculus':0.2); # quoted names with spaces\\n```\\n\\nBranch lengths follow the node name after a colon. Internal node support values can appear as plain brackets `[95]` or as NHX `[&&NHX:B=95]`.\\n\\n```\\nphylo \\\"Newick examples\\\"\\n newick: \\\"((A:0.1,B:0.2):0.05[&&NHX:B=98],(C:0.3,D:0.4):0.08[&&NHX:B=87]);\\\"\\n```\\n\\n**Newick rules the parser accepts:**\\n\\n| Feature | Syntax | Notes |\\n|---|---|---|\\n| Leaf name | `A`, `Homo_sapiens` | No spaces — use `_` or quote |\\n| Quoted leaf name | `'Homo sapiens'` | Single quotes; `''` is a literal quote inside |\\n| Branch length | `:0.035` after name | Float; optional |\\n| Internal node name | `(A,B)ancestor` | After closing `)` |\\n| Bootstrap (plain) | `(A,B)[95]` | Integer or float in brackets |\\n| Bootstrap (NHX) | `(A,B)[&&NHX:B=95]` | `B=` field; other NHX fields stored but not rendered |\\n| Semicolon | `;` at end | Optional — parser strips it |\\n| Polytomy | `(A,B,C)` | More than 2 children |\\n\\n### 2.2 Indent DSL\\n\\nFor hand-written or small trees, Schematex offers an indentation-based alternative that is easier to read and edit than raw Newick:\\n\\n```\\nphylo \\\"Vertebrates (indent DSL)\\\" [mode: phylogram]\\nroot:\\n :0.03\\n Human: 0.1\\n Chimp: 0.08\\n :0.2\\n Dog: 0.35\\n Cat: 0.30\\nscale \\\"substitutions/site\\\"\\n```\\n\\n**Indent DSL rules:**\\n\\n| Syntax | Meaning |\\n|---|---|\\n| `Name: length` | Leaf node with branch length |\\n| `: length` | Unnamed internal node with branch length |\\n| `Name` | Leaf node, no branch length (cladogram) |\\n| `Name [N]` | Node with support value N |\\n| Deeper indent | Child of the node above at a shallower indent |\\n| `#` line | Comment, ignored |\\n\\nThe first line that ends with `:` and has no spaces triggers indent-tree mode (e.g. `root:`). The name before the colon becomes the root label; all indented lines below become its children.\\n\\n---\\n\\n## 3. Layout\\n\\nSet the layout in the header brackets: `phylo \\\"Title\\\" [layout: rectangular]`.\\n\\n| Layout | Value | Description |\\n|---|---|---|\\n| Rectangular | `rectangular` | Default. L-shaped branches; root on left, tips on right |\\n| Slanted | `slanted` | Diagonal lines from parent to child; more compact |\\n| Circular | `circular` | Root at center, tips around the circumference |\\n| Unrooted | `unrooted` | Equal-angle radial; emphasizes distance, not ancestry |\\n\\n`[unrooted]` as a bare flag is equivalent to `[layout: unrooted]`.\\n\\n**Circular** — root at center, tips fanning outward. Most visually striking for many-taxa trees with clade highlights.\\n\\n```\\nphylo \\\"Vertebrates — circular\\\" [layout: circular]\\n newick: \\\"((Human:0.1,Chimp:0.08,Gorilla:0.12):0.15,(Dog:0.35,Cat:0.30,Wolf:0.32):0.2,(Salmon:0.5,Zebrafish:0.45):0.3);\\\"\\n clade Primates = (Human, Chimp, Gorilla) [color: \\\"#1E88E5\\\", label: \\\"Primates\\\", highlight: both]\\n clade Carnivora = (Dog, Cat, Wolf) [color: \\\"#E53935\\\", label: \\\"Carnivora\\\", highlight: both]\\n```\\n\\n**Rectangular** — L-shaped branches; root on the left, tips on the right. The classic phylogram form for published figures.\\n\\n```\\nphylo \\\"Bacterial Diversity\\\" [layout: rectangular, mode: phylogram]\\n newick: \\\"((((Ecoli:0.1,Salmonella:0.12):0.05[&&NHX:B=98],Vibrio:0.2):0.08,((Bacillus:0.15,Staph:0.18):0.06[&&NHX:B=92],Listeria:0.22):0.1):0.15,((Myco_tb:0.3,Myco_leprae:0.28):0.12[&&NHX:B=100],(Strepto:0.25,Lactobacillus:0.2):0.08):0.2);\\\"\\n clade Gamma = (Ecoli, Salmonella, Vibrio) [color: \\\"#1E88E5\\\", label: \\\"γ-Proteobacteria\\\"]\\n clade Firmi = (Bacillus, Staph, Listeria) [color: \\\"#E53935\\\", label: \\\"Firmicutes\\\"]\\n scale \\\"substitutions/site\\\"\\n```\\n\\n**Slanted** — diagonal lines from parent to child; more compact than rectangular, same left-to-right reading direction.\\n\\n```\\nphylo \\\"Vertebrates — slanted\\\" [layout: slanted]\\n newick: \\\"((Human:0.1,Chimp:0.08,Gorilla:0.12):0.15,(Dog:0.35,Cat:0.30,Wolf:0.32):0.2,(Salmon:0.5,Zebrafish:0.45):0.3);\\\"\\n clade Primates = (Human, Chimp, Gorilla) [color: \\\"#1E88E5\\\", label: \\\"Primates\\\"]\\n clade Carnivora = (Dog, Cat, Wolf) [color: \\\"#E53935\\\", label: \\\"Carnivora\\\"]\\n scale \\\"substitutions/site\\\"\\n```\\n\\n**Unrooted** — equal-angle radial layout; de-emphasizes the root, emphasizes pairwise distance between all taxa.\\n\\n```\\nphylo \\\"Vertebrates — unrooted\\\" [unrooted]\\n newick: \\\"((Human:0.1,Chimp:0.08,Gorilla:0.12):0.15,(Dog:0.35,Cat:0.30,Wolf:0.32):0.2,(Salmon:0.5,Zebrafish:0.45):0.3);\\\"\\n clade Primates = (Human, Chimp, Gorilla) [color: \\\"#1E88E5\\\", label: \\\"Primates\\\"]\\n clade Carnivora = (Dog, Cat, Wolf) [color: \\\"#E53935\\\", label: \\\"Carnivora\\\"]\\n```\\n\\n---\\n\\n## 4. Mode\\n\\nSet with `[mode: …]` in the header (or in a `style [mode: …]` line).\\n\\n| Mode | Value | Branch length meaning |\\n|---|---|---|\\n| Phylogram | `phylogram` | Default. Proportional to evolutionary distance (substitutions/site) |\\n| Cladogram | `cladogram` | Ignored — tips align; only topology matters |\\n| Chronogram | `chronogram` | Proportional to divergence time; all tips align to \\\"present\\\" |\\n| Dendrogram | `dendrogram` | Branch length is **merge height** — the distance at which two clusters join |\\n\\nChronogram requires branch lengths in units of time plus `[mrsd: \\\"YYYY\\\"]` (most-recent sampling date) in the header so the renderer can align tips to present.\\n\\n```\\nphylo \\\"SARS-CoV-2 variants\\\" [mode: chronogram, mrsd: \\\"2023\\\"]\\n newick: \\\"((Alpha:0.5,Delta:0.4):0.3,Omicron:0.8);\\\"\\n scale \\\"years\\\"\\n```\\n\\n**Dendrogram** — the standard output of hierarchical agglomerative clustering, not evolution. Each internal node is placed at its **merge height** (the cophenetic distance at which its two child clusters fuse), all leaves align at a common baseline, and the branches are rectangular elbow connectors. A height axis is drawn so you can read off the distance at which any two leaves first share a cluster. Reach for this mode when the same Newick/indent tree describes a clustering result — gene-expression clusters, sample similarity, survey-response groups — rather than a phylogeny.\\n\\nAdd a `cut <value>` line to slice the tree at a chosen height: every subtree whose merge height falls below the threshold becomes one flat cluster, each colored distinctly, and a dashed threshold line is drawn across the tree at that height. This is the dendrogram equivalent of `fcluster` in scipy — turning a continuous tree into a discrete set of groups.\\n\\n```\\nphylo \\\"Gene expression clusters\\\" [mode: dendrogram]\\n newick: \\\"(((A:1,B:1):2,C:3):2,(D:2,E:2):3);\\\"\\n cut 4\\n scale \\\"cluster distance\\\"\\n```\\n\\nOmit `cut` to show the bare dendrogram with no flat-cluster coloring:\\n\\n```\\nphylo \\\"Sample clustering\\\" [mode: dendrogram]\\n newick: \\\"(((A:1,B:1):2,C:3):2,(D:2,E:2):3);\\\"\\n scale \\\"cluster distance\\\"\\n```\\n\\n---\\n\\n## 5. Clade highlighting\\n\\nA `clade` line marks a monophyletic group with a color, an optional label, and an optional highlight mode.\\n\\n```\\nclade ID = (member1, member2, ...) [color: \\\"#hex\\\", label: \\\"text\\\", highlight: mode]\\n```\\n\\n| Prop | Values | Effect |\\n|---|---|---|\\n| `color:` | hex string e.g. `\\\"#1E88E5\\\"` | Branch and/or background color |\\n| `label:` | quoted string | Clade label shown at right margin |\\n| `highlight:` | `branch`, `background`, `both` | `branch` colors lines; `background` shades the region; `both` does both |\\n\\nMembers are tip (leaf) IDs from the Newick string. The renderer computes the MRCA of the listed tips and highlights the entire subtree rooted there.\\n\\n```\\nphylo \\\"Mammal clades\\\" [layout: rectangular]\\n newick: \\\"(((Human:0.1,Chimp:0.08,Gorilla:0.12):0.15,Mouse:0.45):0.05,(Dog:0.35,(Cat:0.30,Tiger:0.32):0.1):0.2);\\\"\\n clade Primates = (Human, Chimp, Gorilla) [color: \\\"#1E88E5\\\", label: \\\"Primates\\\", highlight: both]\\n clade Carnivora = (Dog, Cat, Tiger) [color: \\\"#E53935\\\", label: \\\"Carnivora\\\", highlight: branch]\\n```\\n\\n---\\n\\n## 6. Scale bar and outgroup\\n\\n**Scale bar:** `scale \\\"label\\\"` — adds a bar at the bottom. The label describes the unit (e.g. `\\\"substitutions/site\\\"`, `\\\"Mya\\\"`). Omit for cladogram mode where branch lengths have no meaning.\\n\\n**Outgroup:** `outgroup: taxonId` — records the outgroup for documentation; the renderer may use it to visually mark the outgroup taxon.\\n\\n```\\nphylo \\\"Vertebrates\\\"\\n newick: \\\"((Human:0.1,Chimp:0.08):0.03,Lamprey:0.8);\\\"\\n outgroup: Lamprey\\n scale \\\"substitutions/site\\\"\\n```\\n\\n---\\n\\n## 7. Header props reference\\n\\nAll options go inside `[…]` on the `phylo` header line, or in a `style […]` line anywhere in the body.\\n\\n| Prop | Values | Default | Effect |\\n|---|---|---|---|\\n| `layout:` | `rectangular`, `slanted`, `circular`, `unrooted` | `rectangular` | Tree layout |\\n| `mode:` | `phylogram`, `cladogram`, `chronogram`, `dendrogram` | `phylogram` | Branch length semantics |\\n| `unrooted` | (flag) | — | Equivalent to `layout: unrooted` |\\n| `branch-width:` | number | `1.5` | Stroke width of branches |\\n| `openAngle:` | number (degrees) | `0` | Fan gap for circular layout (0 = full 360°) |\\n| `mrsd:` | quoted year string | — | Most-recent sampling date for chronograms |\\n\\n---\\n\\n## 8. Labels & comments\\n\\n- **Title:** `phylo \\\"Tree of Life\\\"` — first line only.\\n- **Scale label:** `scale \\\"substitutions/site\\\"` — one per document.\\n- **Clade label:** `[label: \\\"Primates\\\"]` inside a `clade` line.\\n- **Comments:** `#` at the start of a line (after leading whitespace). Inline trailing comments are not supported.\\n\\n---\\n\\n## 9. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `newick: (A,B,C);` (unquoted) | `PhyloParseError: Phylo document must start with 'phylo'` | Quote the Newick string: `newick: \\\"(A,B,C);\\\"` |\\n| Tip name with a space: `Homo sapiens:0.1` | Parsed as `Homo` — space terminates an unquoted name | Use underscore (`Homo_sapiens`) or single-quote (`'Homo sapiens'`) |\\n| Leaf ID in `clade` doesn't match Newick name | Clade silently has 0 members; no highlight | Copy names exactly as they appear in the Newick string |\\n| `clade X = (A, B)` with no `newick:` or indent tree | `PhyloParseError: No tree definition found` | Add a `newick:` line or an indent tree block |\\n| `mode: chronogram` with no branch lengths | Renderer treats all lengths as 0; tips overlap at root | Add `:length` to every edge in the Newick string |\\n| `root:` line not detected | If the `root:` line has a space in the name (e.g. `My root:`) the indent tree is not triggered | Use a single-word root label or `root:` |\\n| Newick with internal node names: `(A,B)ancestor:0.5` | Parses fine — `ancestor` is the internal node label | Supported; internal names appear on internal nodes |\\n\\n---\\n\\n## 10. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | newick-line | scale-line\\n | outgroup-line | clade-line | style-line | cut-line | indent-line)*\\n\\nheader = \\\"phylo\\\" ( WS quoted-string )? ( WS \\\"[\\\" props \\\"]\\\" )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nnewick-line = \\\"newick:\\\" WS quoted-newick NEWLINE\\nscale-line = \\\"scale\\\" ( WS quoted-string )? NEWLINE\\noutgroup-line = \\\"outgroup:\\\" WS id NEWLINE\\ncut-line = \\\"cut\\\" WS number NEWLINE // dendrogram mode: flat-cluster threshold height\\nclade-line = \\\"clade\\\" WS id WS \\\"=\\\" WS \\\"(\\\" id (\\\",\\\" id)* \\\")\\\"\\n ( WS \\\"[\\\" clade-props \\\"]\\\" )? NEWLINE\\nstyle-line = \\\"style\\\" WS \\\"[\\\" props \\\"]\\\" NEWLINE\\n\\n// Indent tree — triggered by a line ending in \\\":\\\" with no spaces\\nindent-tree = root-line indent-node*\\nroot-line = id \\\":\\\" NEWLINE\\nindent-node = INDENT ( id \\\":\\\" length | \\\":\\\" length | id ) ( WS \\\"[\\\" number \\\"]\\\" )? NEWLINE\\n\\nprops = prop (\\\",\\\" prop)*\\nprop = \\\"layout:\\\" layout-value\\n | \\\"mode:\\\" mode-value\\n | \\\"unrooted\\\"\\n | \\\"branch-width:\\\" number\\n | \\\"openAngle:\\\" number\\n | \\\"mrsd:\\\" quoted-string\\n\\nclade-props = clade-prop (\\\",\\\" clade-prop)*\\nclade-prop = \\\"color:\\\" quoted-string\\n | \\\"label:\\\" quoted-string\\n | \\\"highlight:\\\" ( \\\"branch\\\" | \\\"background\\\" | \\\"both\\\" )\\n\\nlayout-value = \\\"rectangular\\\" | \\\"slanted\\\" | \\\"circular\\\" | \\\"unrooted\\\"\\nmode-value = \\\"phylogram\\\" | \\\"cladogram\\\" | \\\"chronogram\\\" | \\\"dendrogram\\\"\\n\\n// Newick grammar (embedded, parsed separately)\\nnewick = subtree \\\";\\\"?\\nsubtree = leaf | internal\\ninternal = \\\"(\\\" subtree (\\\",\\\" subtree)* \\\")\\\" name? nhx? length?\\nleaf = name nhx? length?\\nname = unquoted-name | \\\"'\\\" single-quoted \\\"'\\\")\\nlength = \\\":\\\" number\\nnhx = \\\"[\\\" number \\\"]\\\" // plain bootstrap\\n | \\\"[&&NHX:\\\" nhx-pair (\\\":\\\" nhx-pair)* \\\"]\\\"\\nnhx-pair = key \\\"=\\\" value\\n\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\nnumber = /[+-]?[0-9]+(\\\\.[0-9]+)?([eE][+-]?[0-9]+)?/\\ncomment = INDENT \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/phylo/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"sociogram\": {\n \"title\": \"Sociogram\",\n \"content\": \"## 1. Your first sociogram\\n\\nThe smallest useful sociogram: four people, three different relationship types.\\n\\n```\\nsociogram \\\"Study group\\\"\\n alice [label: \\\"Alice\\\"]\\n bob [label: \\\"Bob\\\"]\\n carol [label: \\\"Carol\\\"]\\n dave [label: \\\"Dave\\\"]\\n alice <-> bob [label: \\\"lab partners\\\"]\\n carol -> alice\\n dave -x> bob [label: \\\"rivalry\\\"]\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `sociogram`, optionally followed by a quoted title.\\n2. Each person is a **node** — declared explicitly with `id [label: \\\"…\\\"]` or auto-created the first time they appear in an edge.\\n3. Connect two nodes with an **edge operator** — `<->` (mutual), `->` (one-way), `-x>` (rejection), `-.-` (neutral). See §3.\\n4. Optionally declare **groups** and **config** lines to control layout and coloring.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Nodes\\n\\nA node line is `id [attr: value, …]`. Nodes are also created implicitly when first referenced in an edge — but explicit declaration lets you set labels, groups, and roles.\\n\\n**ID rules.** Must match `[a-zA-Z][a-zA-Z0-9_-]*`. The ID is used internally; the `label:` attribute sets the display name.\\n\\n**Node attributes:**\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| `label: \\\"…\\\"` | quoted string | Display name (defaults to the ID) |\\n| `group: id` | group ID | Associates the node with a group for coloring |\\n| `role: …` | `star`, `isolate`, `bridge`, `neglectee`, `rejected` | Explicit sociometric role annotation |\\n| `size: …` | `small`, `medium`, `large` | Node size override |\\n\\n```\\nsociogram \\\"Group roles demo\\\"\\n config: layout = circular\\n dr_park [label: \\\"Dr. Park\\\", role: star]\\n james [label: \\\"James\\\"]\\n nina [label: \\\"Nina\\\", role: neglectee]\\n loner [label: \\\"Alex\\\", role: isolate]\\n bridge [label: \\\"Sam\\\", role: bridge, size: large]\\n james -> dr_park\\n james -> bridge\\n bridge -> dr_park\\n bridge -> nina\\n nina -> james\\n```\\n\\n---\\n\\n## 3. Edges\\n\\nAn edge line is `leftId OP rightId` optionally followed by `[label: \\\"…\\\", weight: N]`. Both IDs are auto-registered as nodes if not yet declared.\\n\\n### 3.1 Direction and valence\\n\\n```\\nsociogram \\\"Edge types\\\"\\n config: layout = circular\\n a [label: \\\"A\\\"]\\n b [label: \\\"B\\\"]\\n c [label: \\\"C\\\"]\\n d [label: \\\"D\\\"]\\n e [label: \\\"E\\\"]\\n f [label: \\\"F\\\"]\\n # Positive\\n a -> b [label: \\\"chose B\\\"]\\n b <-> c [label: \\\"mutual\\\"]\\n # Negative\\n c -x> d [label: \\\"rejects D\\\"]\\n d <x-> e [label: \\\"mutual reject\\\"]\\n # Neutral\\n e -.- f [label: \\\"indifferent\\\"]\\n f <.-> a [label: \\\"mutual neutral\\\"]\\n```\\n\\n| Operator | Direction | Valence | Meaning |\\n|---|---|---|---|\\n| `A -> B` | one-way | positive | A chose B |\\n| `A <- B` | one-way | positive | B chose A (same as `B -> A`) |\\n| `A <-> B` | mutual | positive | Both chose each other |\\n| `A -- B` | undirected | positive | Relationship known; direction not recorded |\\n| `A -x> B` | one-way | negative | A rejects B |\\n| `A <x- B` | one-way | negative | B rejects A |\\n| `A <x-> B` | mutual | negative | Mutual rejection |\\n| `A -x- B` | undirected | negative | Conflict; direction unknown |\\n| `A -.> B` | one-way | neutral | A is indifferent toward B |\\n| `A <.-> B` | mutual | neutral | Mutual indifference |\\n| `A -.- B` | undirected | neutral | Neutral relationship |\\n\\n### 3.2 Weight / strength\\n\\nHigher weight = thicker line. Use the shorthand operators or override explicitly with `[weight: N]`.\\n\\n| Weight | Shorthand | Direction | Meaning |\\n|---|---|---|---|\\n| 2 (default) | `->` `<->` `--` `-x>` `-.-` | any | Standard connection |\\n| 3 | `==>` `<==` `<==>` `===` | one-way / mutual / undirected | Strong |\\n| 4 | `===>` `<===` `<===>` | one-way / mutual | Very strong |\\n| custom | `[weight: N]` | — | Any integer |\\n\\n```\\nsociogram \\\"Relationship strengths\\\"\\n config: layout = circular\\n a [label: \\\"A\\\"]\\n b [label: \\\"B\\\"]\\n c [label: \\\"C\\\"]\\n d [label: \\\"D\\\"]\\n a -> b [label: \\\"weight 2 (default)\\\"]\\n b ==> c [label: \\\"weight 3 (strong)\\\"]\\n c ===> d [label: \\\"weight 4 (very strong)\\\"]\\n d -> a [weight: 1, label: \\\"weight 1 (weak)\\\"]\\n```\\n\\n### 3.3 Edge labels\\n\\n`A -> B [label: \\\"best friend\\\"]` — the label appears on the connecting line.\\n\\n---\\n\\n## 4. Groups\\n\\nA `group` block collects nodes into a named subgroup for coloring and layout clustering.\\n\\n**Group syntax:**\\n- `group id [label: \\\"…\\\", color: \\\"#hex\\\"]` — the group header line.\\n- Member lines follow, each indented **at least 4 spaces**, one node per line.\\n- A non-indented line (or the next `group`) closes the current group.\\n- Members can carry their own props: `anna [label: \\\"Anna K.\\\", size: large]`.\\n\\nNodes can also be assigned inline: `alice [group: girls]`.\\n\\n```\\nsociogram \\\"Classroom dynamics\\\"\\n config: layout = force-directed\\n group boys [label: \\\"Boys\\\", color: \\\"#42A5F5\\\"]\\n tom [label: \\\"Tom\\\"]\\n jack [label: \\\"Jack\\\"]\\n mike [label: \\\"Mike\\\"]\\n leo [label: \\\"Leo\\\"]\\n group girls [label: \\\"Girls\\\", color: \\\"#EF5350\\\"]\\n anna [label: \\\"Anna\\\"]\\n beth [label: \\\"Beth\\\"]\\n chloe [label: \\\"Chloe\\\"]\\n diana [label: \\\"Diana\\\"]\\n tom <-> jack\\n anna <-> beth\\n anna <-> chloe\\n beth <-> chloe\\n mike -x> leo [label: \\\"conflict\\\"]\\n diana -> anna\\n tom -> anna [label: \\\"cross-group\\\"]\\n```\\n\\n---\\n\\n## 5. Configuration\\n\\n`config:` lines tune layout and visual encoding. Each is its own line.\\n\\n| Config key | Values | Default | Effect |\\n|---|---|---|---|\\n| `layout` | `circular`, `force-directed`, `concentric` | `circular` | Placement algorithm |\\n| `sizing` | `uniform`, `in-degree`, `betweenness` | `uniform` | Node size by metric |\\n| `coloring` | `default`, `group`, `role` | `default` | Node color scheme |\\n| `highlight` | comma list: `stars`, `isolates`, `cliques` | `stars,isolates` | Which patterns to annotate |\\n\\n**Layout notes:**\\n- `circular` — nodes evenly spaced on a ring. Best for small groups (≤15).\\n- `force-directed` — spring model; clusters emerge automatically. Best for medium-sized groups with distinct subgroups.\\n- `concentric` — inner rings hold high-in-degree nodes. Best for showing core-periphery structure.\\n\\n**Circular** — uniform ring placement; every node equally visible. Best for small, tightly-knit groups.\\n\\n```\\nsociogram \\\"Therapy group — circular\\\"\\n config: layout = circular\\n dr_park [label: \\\"Dr. Park\\\", role: star]\\n james [label: \\\"James\\\"]\\n maria [label: \\\"Maria\\\"]\\n lee [label: \\\"Lee\\\"]\\n sarah [label: \\\"Sarah\\\"]\\n tom [label: \\\"Tom\\\"]\\n nina [label: \\\"Nina\\\", role: neglectee]\\n james -> dr_park\\n james <-> maria [weight: 3]\\n james -> lee\\n maria -> dr_park\\n lee -> dr_park\\n lee -x> nina\\n sarah <-> nina\\n sarah -> dr_park\\n tom -> dr_park\\n nina -> maria\\n```\\n\\n**Force-directed** — spring physics pulls connected nodes together and pushes disconnected ones apart. Subgroups cluster organically.\\n\\n```\\nsociogram \\\"Classroom dynamics — force-directed\\\"\\n config: layout = force-directed\\n group boys [label: \\\"Boys\\\", color: \\\"#42A5F5\\\"]\\n tom [label: \\\"Tom\\\"]\\n jack [label: \\\"Jack\\\"]\\n mike [label: \\\"Mike\\\"]\\n leo [label: \\\"Leo\\\"]\\n group girls [label: \\\"Girls\\\", color: \\\"#EF5350\\\"]\\n anna [label: \\\"Anna\\\"]\\n beth [label: \\\"Beth\\\"]\\n chloe [label: \\\"Chloe\\\"]\\n diana [label: \\\"Diana\\\"]\\n tom <-> jack\\n anna <-> beth\\n anna <-> chloe\\n beth <-> chloe\\n mike -x> leo [label: \\\"conflict\\\"]\\n diana -> anna\\n tom -> anna [label: \\\"cross-group\\\"]\\n jack -> beth\\n```\\n\\n**Concentric** — nodes sorted by in-degree; high-centrality nodes appear on inner rings, peripheral nodes on outer rings.\\n\\n```\\nsociogram \\\"Informal influence — concentric\\\"\\n config: layout = concentric\\n config: sizing = in-degree\\n vp [label: \\\"VP Eng\\\"]\\n lead_a [label: \\\"Lead A\\\"]\\n lead_b [label: \\\"Lead B\\\"]\\n alice [label: \\\"Alice\\\"]\\n bob [label: \\\"Bob\\\"]\\n carol [label: \\\"Carol\\\"]\\n dave [label: \\\"Dave\\\"]\\n alice -> lead_a\\n bob -> lead_a\\n carol -> lead_a\\n carol -> lead_b\\n dave -> lead_b\\n lead_a -> vp\\n lead_b -> vp\\n alice <-> bob\\n carol <-> dave\\n```\\n\\n---\\n\\n## 6. Sociometric roles\\n\\nThe parser stores role annotations on nodes. The renderer uses them to apply visual badges — a star marker for `star`, a dashed border for `isolate`, and so on.\\n\\n| Role | Meaning |\\n|---|---|\\n| `star` | Central figure chosen by many (high in-degree) |\\n| `isolate` | No connections in or out |\\n| `neglectee` | Reaches out to others but receives no choices |\\n| `rejected` | Receives rejection edges from multiple members |\\n| `bridge` | Connects two otherwise separate clusters |\\n\\n```\\nsociogram \\\"Role annotations\\\"\\n config: layout = circular\\n center [label: \\\"Maria\\\", role: star]\\n bridge_node [label: \\\"Sam\\\", role: bridge]\\n newcomer [label: \\\"New Kid\\\", role: neglectee]\\n loner [label: \\\"Alex\\\", role: isolate]\\n outcast [label: \\\"Pat\\\", role: rejected]\\n center <-> bridge_node\\n bridge_node -> outcast\\n newcomer -> center\\n newcomer -> bridge_node\\n center -x> outcast\\n bridge_node -x> outcast\\n```\\n\\n---\\n\\n## 7. Labels & comments\\n\\n- **Title:** `sociogram \\\"Study group\\\"` — first line only.\\n- **Node label:** `alice [label: \\\"Alice K.\\\"]`.\\n- **Group label:** `group boys [label: \\\"Boys\\\"]`.\\n- **Edge label:** `alice -> bob [label: \\\"lab partners\\\"]`.\\n- **Comments:** `#` at the start of a line (after leading whitespace).\\n\\n---\\n\\n## 8. Reserved words & escaping\\n\\n**Reserved at line start:** `sociogram` (header), `group`, `config:`.\\n\\n**Reserved operator tokens** — avoid these sequences inside IDs: `->`, `<-`, `<->`, `--`, `===`, `==>`, `<==`, `<===>`, `-x>`, `<x-`, `-x-`, `<x->`, `-.>`, `<.->`, `-.-`.\\n\\n**Strings with spaces** must be double-quoted in `label:` and `color:` values.\\n\\n---\\n\\n## 9. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `tom; jack; mike` on one group line | `tom;` fails the ID regex — silently ignored | One node per line, each indented ≥4 spaces |\\n| Group members indented 2 spaces | Not treated as group members (parser requires ≥4) | Use 4+ spaces indent |\\n| `alice <> bob` | No matching operator — not parsed as an edge | Use `<->` for mutual positive |\\n| `config: layout = grid` | Unknown value silently ignored; layout stays `circular` | Use `circular`, `force-directed`, or `concentric` |\\n| Node with a space in the ID: `dr park` | Parser takes `dr` as the ID and `park` as a stray token | Use underscore: `dr_park [label: \\\"Dr. Park\\\"]` |\\n\\n---\\n\\n## 10. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | config | group-block | edge | node)*\\n\\nheader = \\\"sociogram\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nconfig = \\\"config:\\\" WS key WS \\\"=\\\" WS value NEWLINE\\nkey = \\\"layout\\\" | \\\"sizing\\\" | \\\"coloring\\\" | \\\"highlight\\\"\\n\\ngroup-block = \\\"group\\\" WS id ( \\\"[\\\" group-attrs \\\"]\\\" )? NEWLINE\\n ( INDENT≥4 member-line )*\\nmember-line = id ( \\\"[\\\" node-attrs \\\"]\\\" )? NEWLINE\\ngroup-attrs = group-attr (\\\",\\\" group-attr)*\\ngroup-attr = \\\"label:\\\" quoted-string | \\\"color:\\\" quoted-string\\n\\nnode = id ( \\\"[\\\" node-attrs \\\"]\\\" )? NEWLINE\\nnode-attrs = node-attr (\\\",\\\" node-attr)*\\nnode-attr = \\\"label:\\\" quoted-string\\n | \\\"group:\\\" id\\n | \\\"role:\\\" role\\n | \\\"size:\\\" (\\\"small\\\" | \\\"medium\\\" | \\\"large\\\")\\n\\nedge = id WS op WS id ( \\\"[\\\" edge-attrs \\\"]\\\" )? NEWLINE\\nedge-attrs = edge-attr (\\\",\\\" edge-attr)*\\nedge-attr = \\\"label:\\\" quoted-string | \\\"weight:\\\" number\\n\\nop = // positive\\n \\\"<===>\\\" | \\\"===>\\\" | \\\"<===\\\"\\n | \\\"<==>\\\"|\\\"==>\\\"|\\\"<==\\\"\\n | \\\"===\\\" | \\\"<->\\\" | \\\"->\\\" | \\\"<-\\\" | \\\"--\\\"\\n // negative\\n | \\\"<x->\\\" | \\\"-x>\\\" | \\\"<x-\\\" | \\\"-x-\\\"\\n // neutral\\n | \\\"<.->\\\" | \\\"-\\\\.>\\\" | \\\"-.-\\\"\\n\\nrole = \\\"star\\\" | \\\"isolate\\\" | \\\"bridge\\\" | \\\"neglectee\\\" | \\\"rejected\\\"\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/sociogram/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"timing\": {\n \"title\": \"Timing diagram\",\n \"content\": \"## 1. Your first timing diagram\\n\\nThe smallest useful timing diagram: a clock and one data signal. The friendliest way to write it avoids counting characters entirely:\\n\\n```\\ntiming\\nCLK: clock 8\\nRST: rle 1*2 0*6\\nDATA: 0011==00 data: [\\\"A\\\",\\\"B\\\"]\\n```\\n\\nThree rules cover 80% of usage:\\n\\n1. Start with the keyword `timing`, optionally followed by a quoted title and `[hscale: N]`.\\n2. Each signal is one line: `NAME: <wave>` — name, colon, then the waveform. The waveform can be:\\n - **`clock N`** — a clock generator with `N` periods (add `neg` for a negedge clock). No character-counting.\\n - **`rle <state>*<count> …`** — run-length segments, e.g. `rle 1*2 0*6` = `11000000`. Auto-aligns length.\\n - **a raw WaveDrom wave string** — a contiguous run of state characters (no internal spaces) for fine control.\\n3. Add `data: [\\\"val1\\\", \\\"val2\\\"]` after a raw wave string to label bus segments.\\n\\n> **Tip for alignment:** the #1 cause of a broken timing diagram is signals of unequal length. `clock N` and `rle` make every signal's cell count explicit, so they line up. Use raw wave strings only when you need per-cell control.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Wave characters\\n\\nThe wave string is a sequence of characters, one per time period. The parser accepts these:\\n\\n| Character | State | Meaning |\\n|---|---|---|\\n| `0` | Logic low | Signal at GND / VSS |\\n| `1` | Logic high | Signal at VDD |\\n| `x` | Unknown | Don't-care, undefined, or uninitialized |\\n| `z` | High-Z | Tri-state / high-impedance |\\n| `p` | Clock pulse (positive) | Rising-edge-active clock; one `p` = one full period (low→high→low) |\\n| `P` | Clock pulse (positive, tall) | Same as `p`, visually taller |\\n| `n` | Clock pulse (negative) | Falling-edge-active; one `n` = one full period (high→low→high) |\\n| `N` | Clock pulse (negative, tall) | Same as `n`, visually taller |\\n| `=` | Bus data | Parallel-bus segment; add labels via `data: […]` |\\n| `2`–`9` | Named bus segment | Same as `=`, indexed into `data: […]` by position |\\n| `.` | Hold / continue | Extend the previous state for one more period |\\n| `h` / `H` | Hold high | Force-high for this period |\\n| `l` / `L` | Hold low | Force-low for this period |\\n| `u` | Rising edge | Diagonal from low to high (transition only) |\\n| `d` / `D` | Falling edge | Diagonal from high to low (transition only) |\\n\\n```\\ntiming \\\"Wave character reference\\\"\\nclk: pppppppppp\\nhigh: 1111111111\\nlow: 0000000000\\nunkn: xxxxxxxxxx\\nhiz: zzzzzzzzzz\\nbus: x========x data: [\\\"ADDR\\\",\\\"DATA\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\"]\\nhold: 0..1..0..1\\nrise: 0u1\\nfall: 1d0\\n```\\n\\n---\\n\\n## 3. Data labels\\n\\nWhen a signal carries a bus value, tag the wave with `data: [\\\"label1\\\", \\\"label2\\\", …]`. Each non-empty quoted string is placed inside the corresponding `=` (or `2`–`9`) segment.\\n\\n```\\nMOSI: x======= data: [\\\"0xAB\\\",\\\"0xCD\\\",\\\"0xEF\\\",\\\"0x01\\\",\\\"0x02\\\",\\\"0x03\\\",\\\"0x04\\\",\\\"0x05\\\"]\\n```\\n\\nEmpty strings `\\\"\\\"` leave a segment unlabeled (useful for segments that extend a previous value).\\n\\n```\\nMISO: zzzz==== data: [\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"0xFF\\\",\\\"0x12\\\",\\\"0x34\\\",\\\"0x56\\\"]\\n# first four z-periods have no label; four = segments get labels starting at 0xFF\\n```\\n\\n```\\ntiming \\\"I2C read burst\\\"\\nSCL: ppppppppppp\\nSDA: x1=======1x data: [\\\"ADDR+R\\\",\\\"ACK\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\",\\\"D4\\\",\\\"D5\\\",\\\"NACK\\\"]\\n```\\n\\n---\\n\\n## 4. Grouping signals\\n\\nWrap related signals in a `[GroupName]` block. A `---` line closes the group and also acts as a visual separator between groups.\\n\\n```\\n[Control]\\nCLK: pppppppp\\nCS_N: 10000001\\n---\\n[Data]\\nMOSI: x======= data: [\\\"0xAB\\\",\\\"0xCD\\\",\\\"0xEF\\\",\\\"0x01\\\",\\\"0x02\\\",\\\"0x03\\\",\\\"0x04\\\",\\\"0x05\\\"]\\nMISO: zzzz==== data: [\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"0xFF\\\",\\\"0x12\\\",\\\"0x34\\\",\\\"0x56\\\"]\\n```\\n\\nAlternative `group \\\"name\\\" { … }` syntax is also accepted (closing `}` closes the group).\\n\\n```\\ntiming \\\"UART frame\\\"\\n[Clock & control]\\nCLK: pppppppppppp\\nTX_EN: 0111111110\\n---\\n[Data lines]\\nTX: 1========== data: [\\\"START\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\",\\\"D4\\\",\\\"D5\\\",\\\"D6\\\",\\\"D7\\\",\\\"STOP\\\"]\\nRX: zz1=======1 data: [\\\"\\\",\\\"\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\",\\\"D4\\\",\\\"D5\\\",\\\"D6\\\",\\\"D7\\\"]\\n```\\n\\n---\\n\\n## 5. Title and hscale\\n\\n**Title:** `timing \\\"SPI Transaction\\\"` — appears at the top of the diagram.\\n\\n**hscale:** `timing \\\"title\\\" [hscale: 2]` — scales the width of each time period. Default is 1. Use 2 for wider periods when data labels need more room.\\n\\n```\\ntiming \\\"Wide bus\\\" [hscale: 2]\\nCLK: pppp\\nDATA: ==== data: [\\\"long label here\\\",\\\"another\\\",\\\"third\\\",\\\"fourth\\\"]\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Signal name:** anything before the first `:` on a signal line. Names with spaces are fine — the colon is the delimiter.\\n- **Data labels:** `data: [\\\"a\\\", \\\"b\\\"]` after the wave string.\\n- **Title:** first token after `timing` keyword, quoted.\\n- **Comments:** `#` at the start of a line (after leading whitespace).\\n\\n```\\ntiming \\\"Demo\\\"\\n# this is a comment\\nCLK: pppp # ← inline trailing comment is NOT supported\\n```\\n\\n---\\n\\n## 7. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `CLK: p p p p` (spaces in wave) | Wave string parsed as `p` only; the rest is treated as data clause | Remove spaces: `CLK: pppp` |\\n| `DATA: =====` with no `data:` | Segments render as unlabeled bus cells | Add `data: [\\\"A\\\",\\\"B\\\",\\\"C\\\",\\\"D\\\",\\\"E\\\"]` |\\n| Wave character `s` or `r` | `TimingParseError: Invalid wave string` | Only the characters listed in §2 are valid |\\n| `CLK pppp` (no colon) | Line does not match signal pattern; silently skipped | The colon after the signal name is required |\\n| `data: [A, B, C]` (unquoted) | Values not recognized — parser looks for `\\\"…\\\"` | Quote each value: `data: [\\\"A\\\",\\\"B\\\",\\\"C\\\"]` |\\n| `[Group Name with spaces]` | Group label is `Group Name with spaces` — parsed fine | Supported |\\n| `hscale: 2` on its own line | Not recognized (hscale goes on the header line) | `timing \\\"title\\\" [hscale: 2]` |\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | group-open | group-close | separator | signal)*\\n\\nheader = \\\"timing\\\" ( WS quoted-string )? ( WS \\\"[\\\" \\\"hscale:\\\" number \\\"]\\\" )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\ngroup-open = \\\"[\\\" label \\\"]\\\" NEWLINE\\n | \\\"group\\\" WS quoted-string WS \\\"{\\\"? NEWLINE\\ngroup-close = \\\"}\\\" NEWLINE\\nseparator = \\\"---\\\" NEWLINE\\n\\nsignal = name \\\":\\\" WS wave-string ( WS data-clause )? NEWLINE\\nname = any text before the first \\\":\\\"\\nwave-string = wave-char+\\nwave-char = \\\"0\\\"|\\\"1\\\"|\\\"x\\\"|\\\"z\\\"\\n | \\\"p\\\"|\\\"P\\\"|\\\"n\\\"|\\\"N\\\"\\n | \\\"h\\\"|\\\"H\\\"|\\\"l\\\"|\\\"L\\\"\\n | \\\"u\\\"|\\\"d\\\"|\\\"D\\\"\\n | \\\"=\\\"|\\\".\\\"|\\\"2\\\"|\\\"3\\\"|\\\"4\\\"|\\\"5\\\"|\\\"6\\\"|\\\"7\\\"|\\\"8\\\"|\\\"9\\\"\\n\\ndata-clause = \\\"data:\\\" WS ( \\\"[\\\" quoted-string (\\\",\\\" quoted-string)* \\\"]\\\"\\n | quoted-string+ )\\n\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/timing/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"logic\": {\n \"title\": \"Logic gate diagram\",\n \"content\": \"## 1. Your first logic gate diagram\\n\\nThe smallest useful diagram: two inputs, one gate, one output.\\n\\n```\\nlogic \\\"NAND check\\\"\\ninput A, B\\noutput F\\nF = NAND(A, B)\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `logic`, optionally followed by a quoted title and `style: ansi` or `style: iec`.\\n2. Declare ports with `input` and `output` lines — comma-separated signal names.\\n3. Each gate is `id = GATE_TYPE(input1, input2, …)`. The `id` becomes a named signal wire.\\n4. An `output` name that matches a gate `id` is automatically wired; use `OUTPUT <- gate_id` when the names differ.\\n\\n> Comments must start with `#` or `--` on their own line (or after the last token on a gate line).\\n\\n---\\n\\n## 2. Gate types\\n\\n### 2.1 Combinational gates\\n\\n| DSL keyword | Function | ANSI shape | IEC symbol |\\n|---|---|---|---|\\n| `AND` | A · B | D-shaped body | Rectangle + `&` |\\n| `OR` | A + B | Curved body | Rectangle + `≥1` |\\n| `NOT` | Ā | Triangle + bubble | Rectangle + `1` + bubble |\\n| `NAND` | ¬(A · B) | AND + bubble | Rectangle + `&` + bubble |\\n| `NOR` | ¬(A + B) | OR + bubble | Rectangle + `≥1` + bubble |\\n| `XOR` | A ⊕ B | OR + extra arc | Rectangle + `=1` |\\n| `XNOR` | ¬(A ⊕ B) | XOR + bubble | Rectangle + `=1` + bubble |\\n| `BUF` | A (buffer) | Triangle, no bubble | Rectangle + `1` |\\n\\n```\\nlogic \\\"Gate gallery\\\" style: ansi\\ninput A, B, C\\noutput Y_and, Y_or, Y_xor, Y_nand, Y_not\\nY_and = AND(A, B)\\nY_or = OR(A, B)\\nY_xor = XOR(A, B)\\nY_nand = NAND(A, B)\\nY_not = NOT(C)\\n```\\n\\n### 2.2 Special-output buffers\\n\\n| DSL keyword | Function |\\n|---|---|\\n| `TRISTATE_BUF` | Three-state buffer — Z output when enable is low |\\n| `TRISTATE_INV` | Three-state inverting buffer |\\n| `OPEN_DRAIN` | Open-drain / open-collector output (external pull-up required) |\\n| `SCHMITT` | Schmitt trigger — hysteresis symbol inside body |\\n\\n```\\nlogic \\\"Special buffers\\\" style: ansi\\ninput A, EN\\noutput Y_tri, Y_od, Y_sch\\nY_tri = TRISTATE_BUF(A, EN)\\nY_od = OPEN_DRAIN(A)\\nY_sch = SCHMITT(A)\\n```\\n\\n### 2.3 Flip-flops and latches\\n\\n| DSL keyword | Type | Key pins |\\n|---|---|---|\\n| `DFF` | D flip-flop (edge-triggered) | D, CLK, Q, Q̄ |\\n| `JKFF` | JK flip-flop | J, K, CLK, Q, Q̄ |\\n| `SRFF` | SR flip-flop | S, R, CLK, Q, Q̄ |\\n| `TFF` | T (toggle) flip-flop | T, CLK, Q, Q̄ |\\n| `LATCH_SR` | SR latch (level-sensitive, no clock) | S, R, Q, Q̄ |\\n| `LATCH_D` | D latch (transparent when enable=1) | D, EN, Q, Q̄ |\\n\\n```\\nlogic \\\"Flip-flop gallery\\\" style: ansi\\ninput D, J, K, CLK, EN\\noutput Q_dff, Q_jk, Q_latch\\nQ_dff = DFF(D, CLK)\\nQ_jk = JKFF(J, K, CLK)\\nQ_latch = LATCH_D(D, EN)\\n```\\n\\n### 2.4 Complex combinational\\n\\n| DSL keyword | Function |\\n|---|---|\\n| `MUX` | Multiplexer |\\n| `DEMUX` | Demultiplexer |\\n| `DECODER` | Binary decoder |\\n| `ENCODER` | Priority encoder |\\n\\n```\\nlogic \\\"Combinational MSI\\\" style: ansi\\ninput A, B, S\\noutput Y_mux, Y_dec\\nY_mux = MUX(A, B, S)\\nY_dec = DECODER(A, B)\\n```\\n\\n### 2.5 Sequential complex\\n\\n| DSL keyword | Function |\\n|---|---|\\n| `COUNTER` | Generic binary counter (`CTR` label, CLK/RESET/Q0–Q3) |\\n| `SHIFT_REG` | Generic shift register (`SRG` label, CLK/SER/Q0–Q7) |\\n\\n```\\nlogic \\\"Sequential MSI\\\" style: ansi\\ninput DATA, CLK, RESET\\noutput Q_cnt, Q_sr\\nQ_cnt = COUNTER(CLK, RESET)\\nQ_sr = SHIFT_REG(DATA, CLK)\\n```\\n\\n---\\n\\n## 3. Inputs and outputs\\n\\n### 3.1 Declaring ports\\n\\n```\\ninput A, B, Cin # three input ports\\noutput Sum, Cout # two output ports\\n```\\n\\nEach name in an `input` or `output` list becomes a named signal wire available throughout the diagram.\\n\\n### 3.2 Active-low inputs\\n\\nPrefix a signal name with `~` in the input list to mark it as active-low. The renderer draws a bubble at the port symbol.\\n\\n```\\ninput ~nRESET, CLK, DATA\\n```\\n\\nActive-low notation also works inside gate input lists:\\n\\n```\\ng1 = AND(~nRESET, CLK)\\n```\\n\\n### 3.3 Wiring outputs to gates\\n\\nIf the output ID matches a gate ID, the connection is implicit:\\n\\n```\\noutput Sum # Sum is also a gate id → auto-wired\\nSum = XOR(s1, Cin)\\n```\\n\\nWhen the names differ, use the explicit assignment operator:\\n\\n```\\noutput F\\nq1 = NOR(A, B)\\nF <- q1 # F draws from q1's output\\n```\\n\\n```\\nlogic \\\"SR latch from NOR gates\\\"\\ninput S, R\\noutput Q, Qn\\nq_gate = NOR(R, Qn)\\nqn_gate = NOR(S, Q)\\nQ <- q_gate\\nQn <- qn_gate\\n```\\n\\n---\\n\\n## 4. Symbol style\\n\\nThe `style:` option on the header line selects the symbol standard. It applies to every gate in the diagram.\\n\\n| Value | Standard | Use when |\\n|---|---|---|\\n| `ansi` (default) | IEEE Std 91 — distinctive curved shapes | US education, hardware docs |\\n| `iec` | IEC 60617-12 — uniform rectangles + function label | International, European industry |\\n\\n```\\nlogic \\\"ALU slice\\\" style: iec\\n```\\n\\n```\\nlogic \\\"1-bit Full Adder\\\" style: iec\\ninput A, B, Cin\\noutput Sum, Cout\\n# XOR stage — sum bits\\ns1 = XOR(A, B)\\nSum = XOR(s1, Cin)\\n# AND/OR stage — carry\\nc1 = AND(A, B)\\nc2 = AND(s1, Cin)\\nCout = OR(c1, c2)\\n```\\n\\n```\\nlogic \\\"Gate gallery — IEC style\\\" style: iec\\ninput A, B, C\\noutput Y_and, Y_or, Y_xor, Y_nand, Y_not\\nY_and = AND(A, B)\\nY_or = OR(A, B)\\nY_xor = XOR(A, B)\\nY_nand = NAND(A, B)\\nY_not = NOT(C)\\n```\\n\\n---\\n\\n## 5. Module blocks\\n\\nUse `module` to group gates into a labeled sub-circuit box. Module blocks are useful for documenting hierarchical designs — each module renders as a named rectangle around its member gates.\\n\\n```\\nlogic \\\"Hierarchical adder\\\"\\ninput A, B, Cin\\noutput Sum, Cout\\n\\nmodule \\\"Half Adder\\\" {\\n s1 = XOR(A, B)\\n c1 = AND(A, B)\\n}\\n\\nSum = XOR(s1, Cin)\\nCout = OR(c1, AND(s1, Cin))\\n```\\n\\nModule syntax rules:\\n- `module \\\"Label\\\" {` — opens a module (quoted label or bare identifier). The `{` must be on the same line.\\n- `}` on its own line closes the most recently opened module.\\n- Modules can be nested.\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Diagram title:** `logic \\\"Full Adder\\\"` — first line only.\\n- **Gate signal names:** the `id` in `id = GATE(…)` is both the gate name and the output wire name.\\n- **Output labels:** `output Sum` — the output port label matches the signal name by default.\\n- **Active-low marker:** `~` prefix on a port or gate input.\\n- **Comments:** `#` or `--` at the start of a line, or after the last meaningful token on a line.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `logic` (header), `input`, `output`, `module`, `}`.\\n\\n**Reserved operator tokens** — avoid these inside signal names: `=`, `(`, `)`, `,`, `<-`, `~`.\\n\\n**Signal name rules:** must match `[a-zA-Z_][a-zA-Z0-9_]*`. Lowercase and uppercase are both accepted; gate type keywords (`AND`, `OR`, etc.) are case-insensitive in the parser.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `f = and(A, B)` (lowercase gate) | Accepted — gate types are case-insensitive | Both `AND` and `and` work |\\n| `output F` then `F <- q1` but `q1` not declared | `LogicParseError: Unknown signal \\\"q1\\\"` | Declare `q1` as a gate before referencing it |\\n| `input A B C` (spaces, no commas) | Parser takes `A` only; `B` and `C` are ignored | Use commas: `input A, B, C` |\\n| `F = BUFFER(A)` | `LogicParseError: Unknown gate type: BUFFER` | Use `BUF` |\\n| `module FullAdder {` (no `{` brace) | Line does not match module pattern — skipped silently | The opening `{` is required on the same line as `module` |\\n| `style: IEEE` on the header | Unknown style value — silently defaults to `ansi` | Use `style: ansi` or `style: iec` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header statement*\\n\\nheader = \\\"logic\\\" ( WS quoted-string )? ( WS \\\"style:\\\" WS style )? NEWLINE\\nstyle = \\\"ansi\\\" | \\\"iec\\\"\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nstatement = blank | comment | input-decl | output-decl | gate-def | assign | module-block\\n\\ncomment = ( \\\"#\\\" | \\\"--\\\" ) any NEWLINE\\n\\ninput-decl = \\\"input\\\" WS port-list NEWLINE\\noutput-decl = \\\"output\\\" WS port-list NEWLINE\\nport-list = port-id ( \\\",\\\" WS? port-id )*\\nport-id = \\\"~\\\"? id\\n\\ngate-def = id WS \\\"=\\\" WS gate-type \\\"(\\\" input-list \\\")\\\" NEWLINE\\ninput-list = ( \\\"~\\\"? id ) ( \\\",\\\" WS? ( \\\"~\\\"? id ) )*\\n\\nassign = id WS \\\"<-\\\" WS id NEWLINE\\n\\nmodule-block = module-open ( statement | module-block )* module-close\\nmodule-open = \\\"module\\\" WS ( quoted-string | id ) WS? \\\"{\\\" NEWLINE\\nmodule-close = \\\"}\\\" NEWLINE\\n\\ngate-type = \\\"AND\\\" | \\\"OR\\\" | \\\"NOT\\\" | \\\"NAND\\\" | \\\"NOR\\\" | \\\"XOR\\\" | \\\"XNOR\\\" | \\\"BUF\\\"\\n | \\\"TRISTATE_BUF\\\" | \\\"TRISTATE_INV\\\" | \\\"OPEN_DRAIN\\\" | \\\"SCHMITT\\\"\\n | \\\"DFF\\\" | \\\"JKFF\\\" | \\\"SRFF\\\" | \\\"TFF\\\"\\n | \\\"LATCH_SR\\\" | \\\"LATCH_D\\\"\\n | \\\"MUX\\\" | \\\"DEMUX\\\" | \\\"DECODER\\\" | \\\"ENCODER\\\"\\n | \\\"COUNTER\\\" | \\\"SHIFT_REG\\\"\\n // all case-insensitive\\n\\nid = [a-zA-Z_] [a-zA-Z0-9_]*\\n```\\n\\nAuthoritative source: `src/diagrams/logic/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"circuit\": {\n \"title\": \"Circuit schematic\",\n \"content\": \"## 1. A minimal circuit (netlist mode — recommended)\\n\\nThe smallest useful circuit: a voltage source, a resistor, and a capacitor to ground — an RC low-pass filter.\\n\\n```\\ncircuit \\\"RC Low-Pass\\\" netlist\\nV1 in 0 5V\\nR1 in out 1k\\nC1 out 0 100n\\n```\\n\\nThree rules cover ~90% of netlist usage:\\n\\n1. Start with `circuit \\\"Title\\\" netlist` (the `netlist` keyword switches on this mode).\\n2. Each line is `componentId nodeA nodeB value` — one component, the two (or more) named nodes it connects to, then its value.\\n3. **Two components that share a node name are wired together.** `0`, `gnd`, or `GND` is the ground net (a ground symbol is drawn automatically).\\n\\nThe component-id prefix sets the symbol: `R*`→resistor, `C*`→capacitor, `L*`→inductor, `V*`→voltage source, `D*`→diode, `Q*`→BJT. When the prefix is ambiguous, add `type=` (e.g. `X1 a b type=opamp`). You never compute coordinates — the engine derives placement from the connectivity.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Components\\n\\n### 2.1 Netlist mode syntax\\n\\nA netlist line has the form:\\n\\n```\\ncomponentId node... [value] [type=…] [label=\\\"…\\\"]\\n```\\n\\nThe positional nodes come first; a trailing token that doesn't look like a node becomes the value. Example — a transistor (4 nodes) and a resistor:\\n\\n```\\nQ1 c b e npn # collector, base, emitter nodes + model\\nRc vcc c 2.2k # two nodes + value\\n```\\n\\n**Optional orientation hint.** The engine auto-orients symbols by role (sources up, ground down, the rest horizontal). To nudge a single symbol, add `dir=right|left|up|down` — connectivity is unchanged, only the symbol's facing rotates:\\n\\n```\\nC1 out 0 100n dir=down # draw C1 as a shunt cap hanging to ground\\n```\\n\\nThis is the lightweight layout-control layer (like Lcapy's per-component orientation): netlist connectivity does the heavy lifting, `dir=` only refines appearance. For full geometric control, use positional mode below.\\n\\n### 2.2 Positional mode syntax (hand-drawing)\\n\\n> Positional mode is for manually laying out a schematic geometrically. **Prefer netlist mode for generated output** — positional mode requires tracking a moving \\\"cursor\\\" across lines, which is error-prone for LLMs.\\n\\nA named component line has the form:\\n\\n```\\nid: type direction [value=\\\"…\\\"] [label=\\\"…\\\"]\\n```\\n\\nAn anonymous component omits the `id:` prefix — the parser assigns an auto ID.\\n\\n```\\nR1: resistor right value=\\\"4.7k\\\" label=\\\"R1\\\"\\ncapacitor down value=\\\"100n\\\"\\n```\\n\\n**Direction** is one of `right` (default), `left`, `up`, `down`. It controls which way the component extends from the current cursor position.\\n\\n### 2.3 Passive components\\n\\n| DSL type | Description |\\n|---|---|\\n| `resistor` | Zigzag (ANSI) or rectangle (IEC) |\\n| `potentiometer` | Resistor + wiper arrow, 3-pin |\\n| `rheostat` | 2-pin variable resistor |\\n| `thermistor_ntc` | NTC thermistor (also: `therm`, `ntc`) |\\n| `thermistor_ptc` | PTC thermistor (also: `ptc`) |\\n| `ldr` | Light-dependent resistor |\\n| `varistor` | Voltage-dependent resistor |\\n| `fuse` | Standard fuse |\\n| `fuse_slow` | Slow-blow fuse (`T` designation) |\\n| `capacitor` | Non-polar capacitor |\\n| `electrolytic_cap` | Polar/electrolytic capacitor (also: `ecap`) |\\n| `variable_cap` | Variable capacitor |\\n| `inductor` | Air-core inductor |\\n| `inductor_iron` | Iron-core inductor |\\n| `inductor_ferrite` | Ferrite-core inductor |\\n| `variable_inductor` | Variable inductor |\\n| `ferrite_bead` | EMI ferrite bead |\\n| `crystal` | Quartz crystal oscillator (also: `xtal`) |\\n| `transformer` | Coupled coils (also: `xfmr`) |\\n\\n```\\ncircuit \\\"Passive components gallery\\\"\\n# Row 1: resistor → capacitor → inductor\\nR1: resistor right value=\\\"1k\\\"\\nwire right\\nC1: capacitor right value=\\\"100n\\\"\\nwire right\\nL1: inductor right value=\\\"10u\\\"\\n# Row 2: crystal and transformer, offset below\\nat: R1.start\\nwire down\\nwire down\\nX1: crystal right\\nwire right\\nwire right\\nT1: transformer right\\n```\\n\\n### 2.4 Sources and power\\n\\n| DSL type | Description |\\n|---|---|\\n| `voltage_source` | Circle + polarity (also: `vsource`) |\\n| `current_source` | Circle + arrow (also: `isource`) |\\n| `ac_source` | Circle + sine symbol (also: `acsource`) |\\n| `battery` | Alternating long/short terminal lines |\\n| `vcc` | Power rail arrow (pointing up) |\\n| `ground` | Earth ground — 3 decreasing lines (also: `gnd`) |\\n| `gnd_signal` | Signal ground — solid triangle |\\n| `gnd_chassis` | Chassis ground |\\n| `gnd_digital` | Digital ground |\\n\\n```\\ncircuit \\\"Sources and power gallery\\\"\\n# voltage source with ground\\nV1: voltage_source down value=\\\"5V\\\"\\nwire down\\nground\\nat: V1.start\\nwire right\\nwire right\\n# battery\\nB1: battery down value=\\\"9V\\\"\\nwire down\\nground\\nat: B1.start\\nwire right\\nwire right\\n# ac source\\nA1: ac_source down value=\\\"120V\\\"\\nwire down\\nground\\nat: A1.start\\nwire right\\nwire right\\n# vcc rail\\nvcc up\\nwire down\\ngnd_signal down\\n```\\n\\n### 2.5 Semiconductors — diodes\\n\\n| DSL type | Description |\\n|---|---|\\n| `diode` | Triangle + cathode bar |\\n| `zener` | Diode + bent cathode bar |\\n| `schottky` | Diode + S-bar |\\n| `led` | Diode + outward emission arrows |\\n| `photodiode` | Diode + inward light arrows |\\n| `varactor` | Diode + variable capacitor |\\n| `tvs_diode` | Bidirectional TVS (two bent bars) |\\n| `bridge_rectifier` | 4-diode bridge, 4-pin |\\n\\n```\\ncircuit \\\"Diode types gallery\\\"\\nD1: diode right\\nwire right\\nD2: zener right\\nwire right\\nD3: led right\\nwire right\\nD4: schottky right\\nwire right\\nD5: photodiode right\\nwire right\\nground\\nat: D1.start\\nwire left\\nground\\n```\\n\\n### 2.6 Semiconductors — transistors\\n\\n| DSL type | Description |\\n|---|---|\\n| `npn` | NPN BJT (also: `transistor`, `bjt_npn`) |\\n| `pnp` | PNP BJT (also: `bjt_pnp`) |\\n| `darlington_npn` | NPN Darlington pair |\\n| `darlington_pnp` | PNP Darlington pair |\\n| `nmos` | N-channel MOSFET enhancement (also: `mosfet_n`) |\\n| `pmos` | P-channel MOSFET enhancement (also: `mosfet_p`) |\\n| `nmos_depletion` | N-channel MOSFET depletion |\\n| `jfet_n` | N-channel JFET |\\n| `jfet_p` | P-channel JFET |\\n| `igbt` | IGBT |\\n| `scr` | SCR / thyristor |\\n| `triac` | TRIAC |\\n| `diac` | DIAC |\\n| `phototransistor` | NPN with light arrows |\\n| `optocoupler` | LED + phototransistor in isolation box |\\n\\n```\\ncircuit \\\"Transistor types gallery\\\"\\n# NPN BJT\\nQ1: npn right\\nwire right\\nwire right\\n# PNP BJT\\nQ2: pnp right\\nwire right\\nwire right\\n# N-channel MOSFET\\nQ3: nmos right\\nwire right\\nwire right\\n# P-channel MOSFET\\nQ4: pmos right\\n```\\n\\n### 2.7 Analog ICs and op-amps\\n\\n| DSL type | Description |\\n|---|---|\\n| `opamp` | Triangle: +/− inputs, output |\\n| `comparator` | Same shape, open-collector output |\\n| `schmitt_buffer` | Buffer + hysteresis symbol |\\n| `tri_state_buffer` | Buffer + enable pin |\\n| `instrumentation_amp` | Three-op-amp INA block |\\n| `generic_ic` | Configurable rect with labeled pins (also: `ic`) |\\n| `voltage_regulator` | 3-terminal block: IN/GND/OUT (also: `reg`) |\\n| `dc_dc_converter` | 2-port block with DC/DC label |\\n| `555_timer` | 8-pin 555 pinout block (also: `timer555`) |\\n\\n```\\ncircuit \\\"Analog IC gallery\\\"\\n# op-amp with input/output wires\\nwire right\\nU1: opamp right\\nwire right\\nwire right\\nwire right\\n# comparator\\nU2: comparator right\\nwire right\\nwire right\\nwire right\\n# generic IC block\\nU3: generic_ic right\\n```\\n\\n### 2.8 Switches and relays\\n\\n| DSL type | Description |\\n|---|---|\\n| `switch_spst` | Single-pole single-throw |\\n| `switch_spdt` | Single-pole double-throw |\\n| `switch_dpdt` | Double-pole double-throw |\\n| `push_no` | Push button normally-open |\\n| `push_nc` | Push button normally-closed |\\n| `relay_coil` | Relay coil (2-pin rect) |\\n| `relay_no` | Relay contact normally-open |\\n| `relay_nc` | Relay contact normally-closed |\\n\\n```\\ncircuit \\\"Switch and relay gallery\\\"\\n# SPST switch\\nS1: switch_spst right\\nwire right\\nwire right\\n# SPDT switch\\nS2: switch_spdt right\\nwire right\\nwire right\\n# normally-open push button\\nS3: push_no right\\nwire right\\nwire right\\n# relay coil + contact pair\\nK1: relay_coil right\\nwire right\\nK2: relay_no right\\n```\\n\\n### 2.9 Electromechanical and measurement\\n\\n| DSL type | Description |\\n|---|---|\\n| `motor` | Circle + M |\\n| `speaker` | Cone + box |\\n| `microphone` | Capsule symbol |\\n| `buzzer` | Piezo buzzer |\\n| `ammeter` | Circle + A |\\n| `voltmeter` | Circle + V |\\n| `wattmeter` | Circle + W |\\n| `oscilloscope` | Circle + waveform |\\n\\n### 2.10 Connectors and annotations\\n\\n| DSL type | Description |\\n|---|---|\\n| `wire` | Plain wire segment |\\n| `dot` | Junction dot (T-junction marker) |\\n| `label` | Net label / flag |\\n| `port` | Named port (hollow circle) |\\n| `test_point` | TP marker |\\n| `no_connect` | X — intentionally unconnected pin |\\n| `antenna` | Antenna stub |\\n\\n```\\ncircuit \\\"Passive components\\\"\\nR1: resistor right value=\\\"1k\\\" label=\\\"R1\\\"\\nwire right\\nC1: capacitor down value=\\\"100n\\\" label=\\\"C1\\\"\\nwire down\\nground\\nat: R1.start\\nwire up\\nbattery up label=\\\"9V\\\"\\n```\\n\\n---\\n\\n## 3. Wiring and branching\\n\\n### 3.1 Wire segments\\n\\n`wire direction [N]` draws a bare wire from the current cursor in the given direction. An optional number sets the length in pixels.\\n\\n```\\nwire right\\nwire down 40\\nwire left 20\\n```\\n\\n### 3.2 Jumping the cursor with `at:`\\n\\n`at: id.end` moves the cursor to a named anchor without drawing anything. Use it to branch from a previously placed component.\\n\\n```\\nR1: resistor right value=\\\"10k\\\"\\nat: R1.end\\nC1: capacitor down value=\\\"100n\\\"\\n```\\n\\nNamed anchor suffixes: `end`, `start`. Components retain their ID across the whole diagram, so you can jump back to any previously placed component.\\n\\n### 3.3 Junction dots\\n\\nPlace a `dot` (or use `net NAME: dot`) to mark a T-junction — a point where three or more wires meet. Without a dot, crossed wires are drawn as a crossover (no connection).\\n\\n```\\nR1: resistor right\\ndot\\nwire right # continues from R1.end\\nat: R1.end\\nC1: capacitor down # branches down from the same point\\n```\\n\\n### 3.4 Named nets\\n\\n`net NAME` declares a named net. `net NAME: dot` declares the net and places a junction dot at the current cursor, remembering that location. Later, `at: NAME` jumps back to that net's anchor.\\n\\n```\\nnet VOUT: dot\\nR2: resistor right value=\\\"10k\\\"\\nat: VOUT\\nC1: capacitor down value=\\\"470n\\\"\\n```\\n\\n### 3.5 Net labels\\n\\n`label \\\"text\\\" direction?` places a text label at the current cursor position. Labels do not advance the cursor. They are useful for naming power rails or inter-sheet connections.\\n\\n```\\nlabel \\\"VCC\\\" up\\nlabel \\\"GND\\\" down\\n```\\n\\n```\\ncircuit \\\"RC filter\\\"\\nV1: voltage_source down value=\\\"5V\\\"\\nwire right\\nR1: resistor right value=\\\"1k\\\" label=\\\"R1\\\"\\nnet OUT: dot\\nwire right\\nlabel \\\"Vout\\\" right\\nat: OUT\\nC1: capacitor down value=\\\"100n\\\" label=\\\"C1\\\"\\nwire down\\nground\\n```\\n\\n---\\n\\n## 4. Netlist mode\\n\\nAdd `netlist` after the title on the header line to switch to SPICE-style netlist parsing. The auto-layout engine computes component positions from the net connectivity.\\n\\n```\\ncircuit \\\"Low-pass filter\\\" netlist\\n```\\n\\n### 4.1 Netlist line format\\n\\nEach line is: `ID net1 net2 [net3…] [value] [key=value…]`\\n\\n- **ID** — component identifier. The first letter determines the default type (SPICE prefix convention).\\n- **net1, net2, …** — net names the pins connect to. Net names matching `0`, `gnd`, `ground`, `earth`, `pe`, `agnd`, `dgnd`, `gnda`, `gndd`, `vss`, or `com` (case-insensitive, with optional `_<word>` or numeric suffix — e.g. `gnd_ref`, `AGND_DIG`, `EARTH1`) all canonicalize to the ground net.\\n- **value** (optional bare token) — component value or model name.\\n- **key=value** (optional) — `label=`, `value=`, `type=` overrides.\\n\\n### 4.2 SPICE prefix → component type\\n\\n| Prefix | Default type | Pin order |\\n|---|---|---|\\n| `R` | `resistor` | p1, p2 |\\n| `C` | `capacitor` | p1, p2 |\\n| `L` | `inductor` | p1, p2 |\\n| `D` | `diode` | anode (start), cathode (end) |\\n| `V` | `voltage_source` | plus, minus |\\n| `I` | `current_source` | plus, minus |\\n| `Q` | `npn` | c, b, e |\\n| `M` | `nmos` | d, g, s |\\n| `J` | `jfet_n` | d, g, s |\\n| `S` | `switch_spst` | p1, p2 |\\n| `F` | `fuse` | p1, p2 |\\n| `B` | `battery` | plus, minus |\\n| `K` | `relay_coil` | p1, p2 |\\n| `U`, `X` | `generic_ic` | custom via `pins=` |\\n| `W` | `wire` | start, end |\\n| `T` | `terminal_block` | custom via `pins=` (also `type=junction_box`) |\\n\\n> **Scope:** schematex circuit covers **electrical schematics only** (IEEE 315 / IEC 60617). Hydraulic and pneumatic schematics (ISO 1219) use a fundamentally different visual grammar — directional valve envelopes, cylinder symbols, line styles for pressure/return/drain — and are not supported by this engine. Hydraulic prefixes such as `EV*` (electrovalve), `BOMBA*` (pump), `TANK*`, `DIPOSIT*` will be rejected with a \\\"cannot infer type\\\" error.\\n\\n### 4.3 Transistor model override\\n\\nFor `Q` lines, a trailing model name overrides the type:\\n\\n```\\nQ1 c b e npn # NPN BJT\\nQ2 c b e pnp # PNP BJT\\nM1 d g s nmos # N-channel MOSFET\\nM2 d g s pmos # P-channel MOSFET\\n```\\n\\nFor `D` lines, similarly:\\n\\n```\\nD1 anode cathode zener\\nD2 anode cathode led\\nD3 anode cathode schottky\\nD4 anode cathode photodiode\\n```\\n\\n### 4.4 Netlist example\\n\\n```\\ncircuit \\\"CE Amp (netlist)\\\" netlist\\nV1 vcc 0 9V\\nRc vcc c 2.2k\\nRb vcc b 100k\\nQ1 c b e npn\\nRe e 0 1k\\n```\\n\\n---\\n\\n## 5. Attributes\\n\\nBoth positional and netlist modes accept these key=value attributes:\\n\\n| Attribute | Accepted by | Effect |\\n|---|---|---|\\n| `label=\\\"…\\\"` | all components | Display label (reference designator) |\\n| `value=\\\"…\\\"` | all components | Value annotation (1kΩ, 100nF, 5V) |\\n| `at=id.end` | positional components | Start this component at a named anchor |\\n| `length=N` | `wire`, some passives | Length in pixels |\\n\\nIn positional mode, `at=` inside the component line is equivalent to a preceding `at:` line:\\n\\n```\\nC1: capacitor down at=R1.end value=\\\"100n\\\"\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Diagram title:** `circuit \\\"RC Filter\\\"` — first line only.\\n- **Component label:** `label=\\\"R1\\\"` attribute — reference designator shown beside the symbol.\\n- **Value annotation:** `value=\\\"4.7k\\\"` — shown beside or below the component.\\n- **Net label:** `label \\\"VOUT\\\" right` — standalone net flag at the current cursor.\\n- **Comments:** `#` at the start of a line (after leading whitespace).\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start (positional):** `circuit` (header), `at:`, `net`, `wire`, `label`.\\n\\n**Reserved in netlist mode:** same header rules apply; all other lines are SPICE component lines.\\n\\n**Ground net aliases (netlist only):** `0`, `gnd`, `GND`, `Gnd`, `ground`, `Ground` — all treated as the same node.\\n\\n**Component IDs** must match `[a-zA-Z_][a-zA-Z0-9_]*`. Spaces in values must be quoted: `value=\\\"10 kΩ\\\"`.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `resistor right 1k` (bare value without `value=`) | `1k` is parsed as an unknown attribute flag and ignored | Use `value=\\\"1k\\\"`: `resistor right value=\\\"1k\\\"` |\\n| `at: R1.center` | `center` is not a recognized anchor suffix — cursor stays at current position | Use `at: R1.end` or `at: R1.start` |\\n| `wire 40` (no direction) | Direction defaults to `right`; length `40` is accepted | Explicit direction recommended: `wire right 40` |\\n| `R1 vcc out 10k` in positional mode | Line matches the bare-type pattern; `R1` is read as a type name, fails lookup | In positional mode, use `R1: resistor right value=\\\"10k\\\"` |\\n| `Q1 c b e` (netlist, no model) | Type defaults to `npn` from `Q` prefix — correct | OK; add `npn` explicitly for clarity |\\n| `net OUT` then `at: OUT` without `net OUT: dot` | `OUT` net exists but has no anchor; jump has no destination | Use `net OUT: dot` to register the cursor position |\\n| `label VCC up` (unquoted label) | `VCC` is parsed as a direction token, then `up` — the label text is lost | Quote the text: `label \\\"VCC\\\" up` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header statement*\\n\\n-- Positional mode --\\nheader = \\\"circuit\\\" ( WS quoted-string )? NEWLINE\\nstatement = blank | comment | component | wire | at | net-decl | label-stmt\\n\\ncomponent = ( id \\\":\\\" WS )? type WS direction? attrs* NEWLINE\\nwire = \\\"wire\\\" ( WS direction )? ( WS integer )? NEWLINE\\nat = \\\"at:\\\" WS anchor NEWLINE\\nanchor = id \\\".\\\" ( \\\"start\\\" | \\\"end\\\" )\\n | id // net name anchor\\n\\nnet-decl = \\\"net\\\" WS id NEWLINE // declare net only\\n | \\\"net\\\" WS id \\\":\\\" WS \\\"dot\\\" NEWLINE // declare + place dot\\n\\nlabel-stmt = \\\"label\\\" WS quoted-string ( WS direction )? NEWLINE\\n\\ncomponent-attr = \\\"value=\\\" quoted-string\\n | \\\"label=\\\" quoted-string\\n | \\\"at=\\\" anchor\\n | \\\"length=\\\" integer\\n\\ndirection = \\\"right\\\" | \\\"left\\\" | \\\"up\\\" | \\\"down\\\"\\ntype = // any value from §2 component tables\\n\\n-- Netlist mode --\\nnetlist-header = \\\"circuit\\\" ( WS quoted-string )? WS \\\"netlist\\\" NEWLINE\\nnetlist-stmt = id WS net-ref+ ( WS kv-pair )* NEWLINE\\n | comment\\nnet-ref = id | \\\"0\\\" // net name or ground alias\\nkv-pair = id \\\"=\\\" ( quoted-string | bare-value )\\n\\nid = [a-zA-Z_] [a-zA-Z0-9_]*\\ninteger = [0-9]+\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/circuit/parser.ts` and `src/diagrams/circuit/netlist.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"block\": {\n \"title\": \"Block diagram\",\n \"content\": \"## 1. Your first block diagram\\n\\nThe smallest useful block diagram: one controller, one plant, one feedback loop.\\n\\n```\\nblockdiagram \\\"Temperature control\\\"\\nctrl = block(\\\"PID\\\") [role: controller]\\nplant = block(\\\"Heater\\\") [role: plant]\\nsensor = block(\\\"Thermocouple\\\") [role: sensor]\\nerr = sum(+ref, -measured)\\nref = signal(\\\"Setpoint\\\")\\nmeasured = signal(\\\"T_measured\\\")\\nin -> ref\\nref -> err\\nerr -> ctrl\\nctrl -> plant\\nplant -> measured\\nmeasured -> sensor\\nsensor -> err\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `blockdiagram`, optionally followed by a quoted title.\\n2. Declare each component with `ID = block(\\\"label\\\")`, each summing junction with `ID = sum(+a, -b)`, and each named signal with `ID = signal(\\\"label\\\")`.\\n3. Connect components with `->`. Chain multiple hops on one line: `A -> B -> C`.\\n4. Optionally annotate connections with a trailing label: `A -> B [\\\"E(s)\\\"]`.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Blocks\\n\\nA block represents any functional element — controller, plant, filter, actuator, sensor. The label is typically a transfer function or a descriptive name.\\n\\n**Syntax:** `ID = block(\\\"label\\\") [role: X]`\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| `role: plant` | `plant`, `controller`, `sensor`, `actuator`, `reference`, `disturbance`, `generic` | Visual color coding; `generic` is the default |\\n| `route: above` | `above`, `below` | Routing hint for feedback and feedforward blocks |\\n\\n**ID rules.** Must start with a letter or underscore, followed by letters, digits, or underscores: `[A-Za-z_]\\\\w*`.\\n\\n```\\nblockdiagram \\\"Block roles\\\"\\nref_block = block(\\\"r(t)\\\") [role: reference]\\nctrl = block(\\\"C(s)\\\") [role: controller]\\nact = block(\\\"Actuator\\\") [role: actuator]\\nplant = block(\\\"G(s)\\\") [role: plant]\\nsensor = block(\\\"H(s)\\\") [role: sensor]\\ndist = block(\\\"d(t)\\\") [role: disturbance]\\nref_block -> ctrl\\nctrl -> act\\nact -> plant\\nplant -> sensor\\ndist -> plant\\n```\\n\\n---\\n\\n## 3. Summing junctions\\n\\nA summing junction combines multiple signals into one, with explicit polarity for each input. It renders as a circle with `+`/`−` signs — the standard control-systems symbol.\\n\\n**Syntax:** `ID = sum(+a, -b, +c, …)`\\n\\n- Each input is a signed ID: `+x` adds signal `x`, `-y` subtracts signal `y`.\\n- An input without a sign is treated as positive.\\n- The summing junction ID is then used as the target of connection lines, just like a block ID.\\n\\n```\\nblockdiagram \\\"Error with disturbance rejection\\\"\\nctrl = block(\\\"PI C(s)\\\") [role: controller]\\nplant = block(\\\"G(s)\\\") [role: plant]\\nsensor = block(\\\"H(s)\\\") [role: sensor]\\n# Main error junction: add reference, subtract feedback\\nerr = sum(+r, -ym)\\n# Disturbance junction: add plant input, add disturbance\\ndisturb = sum(+ctrl_out, +d)\\nr = signal(\\\"r (setpoint)\\\")\\nym = signal(\\\"y_m\\\")\\nctrl_out = signal(\\\"u(t)\\\")\\nin -> r\\nr -> err\\nerr -> ctrl\\nctrl -> ctrl_out\\nctrl_out -> disturb\\ndisturb -> plant\\nplant -> ym\\nym -> sensor\\nsensor -> err\\n```\\n\\n---\\n\\n## 4. Signals\\n\\nA signal declaration creates a named signal node that the parser inlines as an edge label. Signals are pass-through: when the parser sees `A -> sig` and `sig -> B`, it merges them into a single edge from `A` to `B`, labeling it with the signal's display text.\\n\\n**Syntax:** `ID = signal(\\\"label\\\") [discrete]`\\n\\n- Omit `[discrete]` for continuous signals (solid line).\\n- Add `[discrete]` for sampled-data signals (dashed line).\\n\\n```\\ne_sig = signal(\\\"E(s)\\\")\\nu_sig = signal(\\\"U(s)\\\") [discrete]\\n```\\n\\nSignals are purely a labeling convenience — you can also label edges directly with a trailing attribute (see §5).\\n\\n---\\n\\n## 5. Connections\\n\\nA connection line is `from -> to`. The `->` operator always produces a directed, arrowed line.\\n\\n**Single hop:** `A -> B`\\n\\n**Chain:** `A -> B -> C` — equivalent to `A -> B` and `B -> C`. Both are written in one line.\\n\\n**With a signal label:** append `[\\\"label text\\\"]` at the end of the chain. The label applies to the last hop only.\\n\\n```\\nctrl -> plant [\\\"U(s)\\\"]\\n```\\n\\n**With a discrete flag:** append `[discrete]` to make the last-hop arrow dashed.\\n\\n```\\nplant -> adc [\\\"y\\\"] [discrete]\\n```\\n\\n**Both label and discrete:** use `[label: \\\"Y(s)\\\", discrete]` (comma-separated).\\n\\n```\\nadc -> ctrl [label: \\\"y[k]\\\", discrete]\\n```\\n\\n```\\nblockdiagram \\\"Mixed continuous/discrete\\\"\\nctrl = block(\\\"Digital PID\\\") [role: controller]\\ndac = block(\\\"DAC\\\") [role: actuator]\\nplant = block(\\\"G(s)\\\") [role: plant]\\nadc = block(\\\"ADC\\\") [role: sensor]\\nerr = sum(+r, -yk)\\nr = signal(\\\"r[k]\\\") [discrete]\\nyk = signal(\\\"y[k]\\\") [discrete]\\nin -> r\\nr -> err\\nerr -> ctrl\\nctrl -> dac [label: \\\"u[k]\\\", discrete]\\ndac -> plant [\\\"u(t)\\\"]\\nplant -> adc [\\\"y(t)\\\"]\\nadc -> yk [discrete]\\nyk -> err\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `blockdiagram \\\"My System\\\"` — first line, quoted.\\n- **Block label:** the quoted string inside `block(\\\"…\\\")` — appears inside the box.\\n- **Signal label:** the quoted string inside `signal(\\\"…\\\")` — appears on the merged edge.\\n- **Edge label:** trailing `[\\\"text\\\"]` or `[label: \\\"text\\\"]` on a connection line — appears on that arrow.\\n- **Comments:** `#` at the start of a line (after leading whitespace). Inline trailing comments are not supported.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `blockdiagram` (header).\\n\\n**Structural keywords** (avoid as block/signal/sum IDs to prevent ambiguity): `block`, `signal`, `sum`.\\n\\n**`in` and `out`** are conventional IDs for the external boundary of a diagram — the parser treats them as ordinary identifiers, but the renderer uses them as implicit source/sink nodes. Using `in -> r` and `plant -> out` is idiomatic.\\n\\n**Strings with spaces** must be double-quoted in `block(\\\"…\\\")` and `signal(\\\"…\\\")` labels.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `G = block(G(s))` (no quotes) | Parse fails — label must be quoted | `G = block(\\\"G(s)\\\")` |\\n| `err = sum(r, -ym)` (no `+`) | `r` treated as `+r` — works, but ambiguous | Write `sum(+r, -ym)` for clarity |\\n| `ctrl -> plant, plant -> out` (comma on one line) | `,` is not a separator — parse fails | One connection per line or use chain: `ctrl -> plant -> out` |\\n| `s1 = signal(\\\"E(s)\\\") [label: \\\"E\\\"]` | `label:` not valid on signal; use it on connections | Drop `label:` from signal declaration |\\n| `role: filter` | Unknown role — silently defaults to `generic` | Use `plant`, `controller`, `sensor`, `actuator`, `reference`, `disturbance`, or `generic` |\\n| `A -> B [discrete, label: \\\"e\\\"]` — label first fails | Order of attrs inside `[…]` doesn't matter, but bare `\\\"text\\\"` shorthand only works when it's the only item | Use `[label: \\\"e\\\", discrete]` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | block-def | sum-def | signal-def | connection)*\\n\\nheader = \\\"blockdiagram\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nblock-def = id WS \\\"=\\\" WS \\\"block\\\" \\\"(\\\" quoted-string \\\")\\\" ( \\\"[\\\" block-attrs \\\"]\\\" )? NEWLINE\\nblock-attrs = block-attr (\\\",\\\" block-attr)*\\nblock-attr = \\\"role:\\\" role | \\\"route:\\\" (\\\"above\\\" | \\\"below\\\")\\nrole = \\\"plant\\\" | \\\"controller\\\" | \\\"sensor\\\" | \\\"actuator\\\"\\n | \\\"reference\\\" | \\\"disturbance\\\" | \\\"generic\\\"\\n\\nsum-def = id WS \\\"=\\\" WS \\\"sum\\\" \\\"(\\\" sum-inputs \\\")\\\" NEWLINE\\nsum-inputs = sum-input (\\\",\\\" sum-input)*\\nsum-input = (\\\"+\\\" | \\\"-\\\")? id\\n\\nsignal-def = id WS \\\"=\\\" WS \\\"signal\\\" \\\"(\\\" quoted-string \\\")\\\" ( \\\"[\\\" \\\"discrete\\\" \\\"]\\\" )? NEWLINE\\n\\nconnection = id (\\\"->\\\" id)+ ( \\\"[\\\" conn-attrs \\\"]\\\" )? NEWLINE\\nconn-attrs = quoted-string # shorthand: bare label only\\n | conn-attr (\\\",\\\" conn-attr)*\\nconn-attr = \\\"label:\\\" quoted-string | \\\"discrete\\\"\\n\\nid = [A-Za-z_] \\\\w*\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/blockdiagram/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"ladder\": {\n \"title\": \"Ladder logic\",\n \"content\": \"## 1. Your first ladder diagram\\n\\nThe smallest useful ladder program: one rung, two contacts, one coil.\\n\\n```\\nladder \\\"First Rung\\\"\\nrung 1 \\\"Start when button pressed, stop on fault\\\":\\n XIC(START_PB)\\n XIO(FAULT)\\n OTE(MOTOR_RUN)\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `ladder`, optionally followed by a quoted title.\\n2. Each **rung** begins with `rung N \\\"optional comment\\\":` on its own line. The trailing colon is optional.\\n3. Elements are listed one per line, indented under the rung — left to right means series (AND logic).\\n4. A `parallel:` / `branch:` block introduces OR logic. Every branch holds its own element list.\\n\\n> Comments may start with `#`, `//`, or Mermaid-style `%%` on their own line.\\n\\n---\\n\\n## 2. Contacts\\n\\nContacts represent input conditions — they pass power when the associated bit matches the contact type.\\n\\n| Type | Name | Passes power when… |\\n|---|---|---|\\n| `XIC` | Examine If Closed | Tag bit = 1 (normally open) |\\n| `XIO` | Examine If Open | Tag bit = 0 (normally closed) |\\n| `ONS` | One-Shot Rising | Tag transitions 0 → 1 (rising edge, one scan) |\\n| `OSF` | One-Shot Falling | Tag transitions 1 → 0 (falling edge, one scan) |\\n\\n**Syntax:**\\n\\n```\\nXIC(tag)\\nXIC(tag, \\\"address\\\")\\nXIC(tag, \\\"address\\\", name=\\\"Description\\\")\\nXIC(tag, address=\\\"address\\\", name=\\\"Description\\\")\\n```\\n\\n- `tag` — required. The PLC tag name (displayed below the contact symbol).\\n- `\\\"address\\\"` — optional positional second argument. The I/O address (e.g. `\\\"IN 1.0\\\"`, `\\\"BIT 3.1\\\"`).\\n- `name=\\\"…\\\"` — optional key-value. Human-readable description (displayed above the symbol).\\n\\n```\\nladder \\\"Contact types\\\"\\nrung 1 \\\"All four contact types\\\":\\n XIC(START_PB, \\\"IN 1.0\\\", name=\\\"Start Button\\\")\\n XIO(E_STOP, \\\"IN 1.5\\\", name=\\\"Emergency Stop NC\\\")\\n ONS(PULSE_IN, \\\"BIT 5.0\\\", name=\\\"One-Shot Rising\\\")\\n OSF(RESET_SIG, \\\"BIT 5.1\\\", name=\\\"One-Shot Falling\\\")\\n OTE(OUT_RLY, \\\"OUT 2.0\\\", name=\\\"Output Relay\\\")\\n```\\n\\n---\\n\\n## 3. Coils\\n\\nCoils represent output actions — they act on a tag bit when the rung has power flow.\\n\\n| Type | Name | Effect on tag bit |\\n|---|---|---|\\n| `OTE` | Output Energize | Sets bit = 1 while rung is true; clears to 0 when rung is false |\\n| `OTL` | Output Latch | Sets bit = 1; **retains** even after rung goes false (latches) |\\n| `OTU` | Output Unlatch | Clears bit = 0; retains even after rung goes false |\\n| `OTN` | Output Negate | Sets bit = 0 while rung is true; sets to 1 when rung is false |\\n| `RES` | Reset | Rockwell / Allen-Bradley counter or timer reset coil |\\n\\n**Syntax:** identical to contacts — `OTE(tag)`, `OTE(tag, \\\"address\\\")`, `OTE(tag, \\\"address\\\", name=\\\"…\\\")`.\\n\\n`OTL` and `OTU` are used in pairs to build Set/Reset flip-flops. The last rung to write wins.\\n\\n```\\nladder \\\"Set-Reset latch\\\"\\nrung 1 \\\"Set on start\\\":\\n XIC(START_PB, \\\"IN 1.0\\\", name=\\\"Start\\\")\\n OTL(MOTOR_ON, \\\"BIT 3.0\\\", name=\\\"Motor Latch\\\")\\nrung 2 \\\"Reset on stop or fault\\\":\\n parallel:\\n branch:\\n XIC(STOP_PB, \\\"IN 1.1\\\", name=\\\"Stop\\\")\\n branch:\\n XIC(E_STOP, \\\"IN 1.5\\\", name=\\\"E-Stop\\\")\\n OTU(MOTOR_ON, \\\"BIT 3.0\\\", name=\\\"Motor Latch\\\")\\n```\\n\\n---\\n\\n## 4. Function blocks\\n\\nFunction blocks perform timer, counter, math, and comparison operations. They appear inline in a rung and have keyword parameters after the mandatory tag argument.\\n\\n### 4.1 Timers\\n\\n| Type | Name | Key parameters |\\n|---|---|---|\\n| `TON` | Timer On-Delay | `PT=` preset time in milliseconds |\\n| `TOFF` | Timer Off-Delay | `PT=` preset time in milliseconds |\\n| `TP` | Timer Pulse | `PT=` preset time in milliseconds |\\n\\n```\\nTON(timer_tag, PT=5000)\\n```\\n\\nThe timer tag stores elapsed time. The timer's `Q` bit (done output) is accessed by tag name in downstream contacts.\\n\\n### 4.2 Counters\\n\\n| Type | Name | Key parameters |\\n|---|---|---|\\n| `CTU` | Count Up | `PV=` preset value (integer) |\\n| `CTD` | Count Down | `PV=` preset value |\\n| `CTUD` | Count Up/Down | `PV=` preset value |\\n\\n```\\nCTU(cycle_counter, PV=100)\\n```\\n\\n### 4.3 Math\\n\\n| Type | Operation |\\n|---|---|\\n| `ADD` | Add |\\n| `SUB` | Subtract |\\n| `MUL` | Multiply |\\n| `DIV` | Divide |\\n| `MOV` | Move (copy) |\\n\\n```\\nADD(result_tag, IN1=setpoint, IN2=offset)\\nMOV(dest_tag, IN1=source_tag)\\n```\\n\\n### 4.4 Comparisons\\n\\n| Type | Meaning |\\n|---|---|\\n| `EQU` | Equal |\\n| `NEQ` | Not equal |\\n| `GRT` | Greater than |\\n| `LES` | Less than |\\n| `GEQ` | Greater than or equal |\\n| `LEQ` | Less than or equal |\\n\\n```\\nEQU(compare_tag, IN1=speed_actual, IN2=speed_setpoint)\\n```\\n\\n```\\nladder \\\"Timer and counter\\\"\\nrung 1 \\\"Start run timer\\\":\\n XIC(MOTOR_CMD, \\\"BIT 3.0\\\", name=\\\"Motor Running\\\")\\n TON(RUN_TIMER, PT=10000)\\nrung 2 \\\"Count completed cycles\\\":\\n XIC(CYCLE_SENSOR, \\\"IN 2.0\\\", name=\\\"Cycle Sensor\\\")\\n CTU(PART_COUNT, PV=500)\\nrung 3 \\\"Alarm when batch complete\\\":\\n XIC(PART_COUNT, name=\\\"Count Done\\\")\\n OTE(BATCH_ALARM, \\\"OUT 3.0\\\", name=\\\"Batch Complete Alarm\\\")\\n```\\n\\n---\\n\\n## 5. Parallel branches\\n\\nA `parallel:` block introduces OR logic — the rung has power if **any** branch conducts. Each branch is a `branch:` sub-block with its elements indented below it.\\n\\n```\\nparallel:\\n branch:\\n XIC(LOCAL_START)\\n branch:\\n XIC(REMOTE_START)\\n```\\n\\nBranches in a `parallel:` are evaluated simultaneously. The block closes when indentation returns to the level before `parallel:`.\\n\\n**Rules:**\\n- `parallel:` must appear inside a rung.\\n- `branch:` must appear inside a `parallel:` — using it alone throws `LadderParseError`.\\n- Each branch holds one or more elements.\\n- Elements after the `parallel:` block are series with it (AND logic).\\n\\n```\\nladder \\\"Parallel OR logic\\\"\\nrung 1 \\\"Start from either local or remote\\\":\\n parallel:\\n branch:\\n XIC(LOCAL_START, \\\"IN 1.0\\\", name=\\\"Local Start\\\")\\n branch:\\n XIC(REMOTE_START, \\\"BIT 5.2\\\", name=\\\"Remote Start\\\")\\n XIO(STOP_ALL, \\\"IN 1.5\\\", name=\\\"Stop All\\\")\\n OTE(CONVEYOR, \\\"OUT 2.0\\\", name=\\\"Conveyor Run\\\")\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `ladder \\\"Motor Control\\\"` — first line only, quoted string.\\n- **Rung number:** required integer after `rung`.\\n- **Rung comment:** optional quoted string after the rung number, before the optional colon: `rung 3 \\\"Run indicator\\\":` or `rung 3 \\\"Run indicator\\\"`.\\n- **Tag:** first argument inside the parentheses — displayed below the symbol.\\n- **Address:** second positional argument (quoted): `XIC(START_PB, \\\"IN 1.0\\\")`.\\n- **Name:** `name=\\\"…\\\"` keyword argument — human-readable description displayed above the symbol.\\n- **Line comments:** `#`, `//`, or `%%` at the start of a line (after leading whitespace). The same markers also start trailing comments.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start (case-insensitive):** `ladder`, `rung`, `parallel:`, `branch:`.\\n\\n**Element names** are all uppercase ASCII: `XIC`, `XIO`, `ONS`, `OSF`, `OTE`, `OTL`, `OTU`, `OTN`, `TON`, `TOFF`, `TP`, `CTU`, `CTD`, `CTUD`, `ADD`, `SUB`, `MUL`, `DIV`, `MOV`, `EQU`, `NEQ`, `GRT`, `LES`, `GEQ`, `LEQ`.\\n\\n**Tag IDs** — must match `[A-Z][A-Z0-9_]*` (the parser matches `[A-Z][A-Z0-9_]*` for the element name prefix). Lowercase tags are accepted inside the parentheses.\\n\\n**Quoted strings** in address or name arguments must use double quotes `\\\"…\\\"`.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `rung 1` (no colon) | Parsed correctly | The trailing colon is optional |\\n| `ONF(TAG)` | `LadderParseError: unknown element type \\\"ONF\\\"` | Falling-edge contact is `OSF`, not `ONF` |\\n| `parallel:` without `branch:` | Empty parallel block — rung has no element | Add at least one `branch:` inside the `parallel:` |\\n| `branch:` before `parallel:` | `LadderParseError: branch: without parallel:` | Always open `parallel:` first |\\n| `OTE()` — no tag | `LadderParseError: element missing tag` | Tag is required: `OTE(MY_TAG)` |\\n| `var StartBtn: bool` (variable declaration) | `LadderParseError: invalid element syntax` | No variable declarations — tags are used directly |\\n| Empty rung (no elements after `rung N:`) | `LadderParseError: Rung N: empty rung` | Add at least one element to each rung |\\n| `TON(T1, T#5s)` | `LadderParseError: invalid element syntax` (T# not a valid number) | Use milliseconds integer: `TON(T1, PT=5000)` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header NEWLINE rung+\\n\\nheader = \\\"ladder\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nrung = \\\"rung\\\" WS integer ( WS quoted-string )? \\\":\\\"? NEWLINE\\n element+\\n\\nelement = contact-line\\n | coil-line\\n | fb-line\\n | parallel-block\\n\\ncontact-line = contact-type \\\"(\\\" tag ( \\\",\\\" arg )* \\\")\\\" NEWLINE\\ncontact-type = \\\"XIC\\\" | \\\"XIO\\\" | \\\"ONS\\\" | \\\"OSF\\\"\\n\\ncoil-line = coil-type \\\"(\\\" tag ( \\\",\\\" arg )* \\\")\\\" NEWLINE\\ncoil-type = \\\"OTE\\\" | \\\"OTL\\\" | \\\"OTU\\\" | \\\"OTN\\\" | \\\"RES\\\"\\n\\nfb-line = fb-type \\\"(\\\" tag ( \\\",\\\" arg )* \\\")\\\" NEWLINE\\nfb-type = \\\"TON\\\" | \\\"TOFF\\\" | \\\"TP\\\"\\n | \\\"CTU\\\" | \\\"CTD\\\" | \\\"CTUD\\\"\\n | \\\"ADD\\\" | \\\"SUB\\\" | \\\"MUL\\\" | \\\"DIV\\\" | \\\"MOV\\\"\\n | \\\"EQU\\\" | \\\"NEQ\\\" | \\\"GRT\\\" | \\\"LES\\\" | \\\"GEQ\\\" | \\\"LEQ\\\"\\n\\narg = quoted-string // positional (address)\\n | key \\\"=\\\" quoted-string // keyword (e.g. name=\\\"…\\\")\\n | key \\\"=\\\" number // keyword (e.g. PT=5000)\\n\\nparallel-block = INDENT≥2 \\\"parallel:\\\" NEWLINE\\n ( INDENT branch-block )+\\n\\nbranch-block = \\\"branch:\\\" NEWLINE\\n ( INDENT element )+\\n\\ntag = [A-Za-z][A-Za-z0-9_]*\\nkey = [A-Za-z][A-Za-z0-9_]*\\ninteger = [0-9]+\\nnumber = [0-9]+ ( \\\".\\\" [0-9]+ )?\\ncomment = ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/ladder/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"sld\": {\n \"title\": \"Single-line diagram (SLD)\",\n \"content\": \"## 1. Your first single-line diagram\\n\\nThe simplest SLD: a utility source, a transformer, a breaker, and a load.\\n\\n```\\nsld \\\"Simple feeder\\\"\\nutil = utility [label: \\\"Utility 13.8kV\\\"]\\nxfmr = transformer [rating: \\\"500 kVA\\\", voltage: \\\"13.8kV/480V\\\"]\\nbus1 = bus [voltage: \\\"480V\\\", label: \\\"480V Bus\\\"]\\ncb1 = breaker [rating: \\\"200A\\\"]\\nload1 = load [label: \\\"Panel LP-1\\\"]\\nutil -> xfmr\\nxfmr -> bus1\\nbus1 -> cb1\\ncb1 -> load1\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `sld`, optionally followed by a quoted title.\\n2. Declare each equipment item as `id = nodeType [attributes]` — one per line.\\n3. Connect items with `from -> to`, optionally adding `[cable: \\\"…\\\", label: \\\"…\\\"]`.\\n4. IDs may contain letters, digits, underscores, and hyphens — but must start with a letter.\\n\\n> Comments may start with `#`, `//`, or Mermaid-style `%%` on their own line.\\n\\n---\\n\\n## 2. Node types\\n\\nA node line is `id = nodeType [attr: value, …]`. The node type determines the symbol drawn.\\n\\n### 2.1 Sources\\n\\n| Type | Symbol | Typical use |\\n|---|---|---|\\n| `utility` | Utility source arrow | Infinite bus / grid connection |\\n| `generator` | Circle with `G` | Diesel, gas, or hydro genset |\\n| `solar` | PV panel symbol | Photovoltaic array |\\n| `wind` | Turbine symbol | Wind turbine |\\n| `ups` | Block with battery | Uninterruptible power supply |\\n\\n```\\nsld \\\"Generation sources\\\"\\nutil = utility [label: \\\"Grid 115 kV\\\"]\\ngen = generator [rating: \\\"2 MW\\\", label: \\\"Diesel Gen\\\"]\\nsol = solar [rating: \\\"500 kW\\\", label: \\\"PV Array\\\"]\\nwnd = wind [rating: \\\"1 MW\\\", label: \\\"Wind Turbine\\\"]\\nups = ups [rating: \\\"100 kVA\\\", label: \\\"UPS System\\\"]\\nutil -> gen\\nutil -> sol\\nutil -> wnd\\nutil -> ups\\n```\\n\\n### 2.2 Transformers\\n\\n| Type | Winding configuration | Notes |\\n|---|---|---|\\n| `transformer` | Generic two-winding | No winding spec |\\n| `transformer_dy` | Delta → Wye grounded (Δ-Yg) | Most common distribution |\\n| `transformer_yd` | Wye grounded → Delta (Yg-Δ) | |\\n| `transformer_yy` | Wye-Wye (both grounded) | |\\n| `transformer_dd` | Delta-Delta | |\\n| `autotransformer` | Single-winding with tap | Zigzag coil symbol |\\n| `transformer_3winding` | Three-winding | HV / MV / LV taps |\\n\\n```\\nsld \\\"Transformer configurations\\\"\\nsrc = utility [label: \\\"138kV Grid\\\"]\\nt_dy = transformer_dy [rating: \\\"30 MVA\\\", voltage: \\\"138kV/13.8kV\\\", label: \\\"Δ-Yg (most common)\\\"]\\nt_yy = transformer_yy [rating: \\\"10 MVA\\\", voltage: \\\"138kV/13.8kV\\\", label: \\\"Yg-Yg\\\"]\\nt_auto = autotransformer [rating: \\\"50 MVA\\\", voltage: \\\"138kV/69kV\\\", label: \\\"Autotransformer\\\"]\\nt_3w = transformer_3winding [rating: \\\"40 MVA\\\", voltage: \\\"138/13.8/4.16kV\\\", label: \\\"3-Winding\\\"]\\nsrc -> t_dy\\nsrc -> t_yy\\nsrc -> t_auto\\nsrc -> t_3w\\n```\\n\\n### 2.3 Buses and nodes\\n\\n| Type | Symbol | Typical use |\\n|---|---|---|\\n| `bus` | Thick horizontal line | Main voltage bus bar |\\n| `bus_tie` | Bus-tie breaker | Links two parallel buses at the same voltage |\\n| `hub` | Wide rectangle | Multi-feeder combining point |\\n\\n### 2.4 Switching and protection\\n\\n| Type | Symbol | Device number |\\n|---|---|---|\\n| `breaker` | Diagonal + arc | 52 (AC circuit breaker) |\\n| `breaker_vacuum` | Diagonal + V-oval | 52 vacuum type |\\n| `switch` | Diagonal (no arc) | 89 (disconnect / isolator) |\\n| `switch_load` | Load interrupter switch | — |\\n| `ground_switch` | Diagonal + ground symbol | Grounding disconnect |\\n| `ats` | Transfer switch symbol | Automatic transfer switch |\\n| `recloser` | Diagonal + arc + arrow | Auto-reclosing breaker |\\n| `sectionalizer` | Diagonal + S | Distribution sectionalizer |\\n| `fuse` | Oval with diagonal | Expulsion fuse cutout |\\n| `fuse_cl` | Rectangle with diagonal | Current-limiting fuse |\\n\\n```\\nsld \\\"Switching and protection\\\"\\nsrc = utility [label: \\\"Source\\\"]\\nrclsr = recloser [label: \\\"Recloser\\\"]\\nsect = sectionalizer [label: \\\"Sectionalizer\\\"]\\nfuse1 = fuse [label: \\\"Fuse\\\"]\\nsw = switch [label: \\\"Disconnect\\\"]\\ngnd_sw = ground_switch [label: \\\"Ground SW\\\"]\\nsrc -> rclsr\\nrclsr -> sect\\nsect -> fuse1\\nsect -> sw\\nsw -> gnd_sw\\n```\\n\\n### 2.5 Protection and monitoring\\n\\n| Type | Symbol | Typical use |\\n|---|---|---|\\n| `ct` | Small circle with line through | Current transformer |\\n| `pt` | Small circle | Potential / voltage transformer |\\n| `relay` | Small circle with device number | Protection relay (ANSI number via `device:`) |\\n| `surge_arrester` | Arrow + ground | Lightning arrester |\\n| `ground_fault` | GFI symbol | Ground-fault detector |\\n\\n### 2.6 Loads and equipment\\n\\n| Type | Symbol | Typical use |\\n|---|---|---|\\n| `motor` | Circle with `M` | Three-phase motor |\\n| `load` | Rectangle | Generic load or feeder |\\n| `capacitor_bank` | Two plates + switch | Power factor correction |\\n| `harmonic_filter` | LC symbol | Passive harmonic filter |\\n| `vfd` | Rectangle with VFD | Variable-frequency drive |\\n\\n### 2.7 Metering\\n\\n| Type | Symbol | Typical use |\\n|---|---|---|\\n| `watthour_meter` | Circle with `Wh` | Energy meter |\\n| `demand_meter` | Circle with `D` | Demand meter |\\n\\n```\\nsld \\\"Equipment types\\\"\\nsrc = utility [label: \\\"Grid 13.8kV\\\"]\\ntx = transformer_dy [rating: \\\"1000 kVA\\\", voltage: \\\"13.8kV/480V\\\", label: \\\"Main TX\\\"]\\nbk = breaker [rating: \\\"2000A\\\", label: \\\"Main Breaker\\\"]\\nbus = bus [voltage: \\\"480V\\\", label: \\\"480V MV Bus\\\"]\\nct1 = ct [label: \\\"CT-1\\\"]\\nrly = relay [device: \\\"51\\\", label: \\\"Overcurrent Relay\\\"]\\ncap = capacitor_bank [rating: \\\"150 kVAR\\\", label: \\\"PF Cap\\\"]\\nmtr = motor [rating: \\\"100HP\\\", label: \\\"Pump Motor\\\"]\\ngen = generator [rating: \\\"500kW\\\", label: \\\"Emergency Gen\\\"]\\nats = ats [rating: \\\"800A\\\", label: \\\"ATS-1\\\"]\\nsrc -> tx\\ntx -> bk\\nbk -> bus\\nbus -> ct1\\nct1 -> rly\\nbus -> cap\\nbus -> mtr\\ngen -> ats\\nats -> bus\\n```\\n\\n---\\n\\n## 3. Node attributes\\n\\nAttributes are written inside `[…]` after the node type, comma-separated.\\n\\n| Attribute | Values | Effect |\\n|---|---|---|\\n| `label: \\\"…\\\"` | quoted string | Display name on the diagram |\\n| `voltage: \\\"…\\\"` | quoted string, e.g. `\\\"13.8kV\\\"`, `\\\"480V\\\"` | Voltage level annotation |\\n| `rating: \\\"…\\\"` | quoted string, e.g. `\\\"1000 kVA\\\"`, `\\\"200A\\\"` | Equipment rating annotation |\\n| `device: \\\"…\\\"` | ANSI device number, e.g. `\\\"51\\\"`, `\\\"87\\\"` | Used with `relay` nodes |\\n| any other key | quoted string | Stored as nameplate data (transformer kVA, %Z, etc.) |\\n\\n**Example with all common attributes:**\\n\\n```\\nxfmr = transformer_dy [\\n label: \\\"Main Transformer\\\",\\n voltage: \\\"13.8kV/480V\\\",\\n rating: \\\"1000 kVA\\\",\\n impedance: \\\"5.75%Z\\\"\\n]\\n```\\n\\nThe attribute block may span multiple lines — the parser joins lines until the `]` is balanced.\\n\\n---\\n\\n## 4. Connections\\n\\nA connection line is `fromId -> toId`, optionally followed by `[cable: \\\"…\\\", label: \\\"…\\\"]`.\\n\\n```\\nbus1 -> cb1\\nbus1 -> cb1 [cable: \\\"3#2/0 AWG\\\"]\\nbus1 -> cb1 [cable: \\\"3#2/0 AWG\\\", label: \\\"Feeder A\\\"]\\n```\\n\\n**Rules:**\\n- Both IDs must be declared before or after the connection — all connections are validated at end of parse.\\n- Only `->` (directed, source-to-load) is accepted. The connection direction is used for layout.\\n- An unknown node ID throws `SLDParseError: Connection references unknown node \\\"…\\\"`.\\n\\n```\\nsld \\\"ATS backup with cable labels\\\"\\nUTIL = utility [label: \\\"Utility 480V\\\"]\\nGEN = generator [rating: \\\"500 kW\\\", label: \\\"Emergency Gen\\\"]\\nATS1 = ats [rating: \\\"800A\\\", label: \\\"ATS-1\\\"]\\nBUS1 = bus [voltage: \\\"480V\\\", label: \\\"Critical Bus\\\"]\\nCB1 = breaker [rating: \\\"200A\\\", label: \\\"CB-1\\\"]\\nCB2 = breaker [rating: \\\"200A\\\", label: \\\"CB-2\\\"]\\nL1 = load [label: \\\"Server Room\\\"]\\nL2 = load [label: \\\"Life Safety\\\"]\\nUTIL -> ATS1 [label: \\\"Normal source\\\"]\\nGEN -> ATS1 [label: \\\"Emergency source\\\"]\\nATS1 -> BUS1 [cable: \\\"3#2/0 AWG\\\"]\\nBUS1 -> CB1\\nBUS1 -> CB2\\nCB1 -> L1 [cable: \\\"3#4 AWG\\\"]\\nCB2 -> L2 [cable: \\\"3#4 AWG\\\"]\\n```\\n\\n---\\n\\n## 5. Labels & comments\\n\\n- **Title:** `sld \\\"Substation One-Line\\\"` — first line only.\\n- **Node label:** `id = type [label: \\\"…\\\"]` — the display name.\\n- **Connection label:** `A -> B [label: \\\"…\\\"]` — appears alongside the connecting line.\\n- **Cable annotation:** `A -> B [cable: \\\"3#2/0 AWG, 200ft\\\"]` — conductor specification.\\n- **Comments:** `#` at the start of a line. Inline `#` on the same line as a node or connection is also stripped.\\n- **Residential aliases:** IEC / REBT vocabulary such as `mcb`, `rcd`, `rcbo`, `rccb`, `pia`, `iga`, `main_switch`, `consumer_unit`, `distribution_board`, `panel`, and `panelboard` is accepted as input and mapped to existing SLD primitives.\\n\\n---\\n\\n## 6. Reserved words & escaping\\n\\n**Reserved at line start:** `sld` (header).\\n\\n**Operator token** — avoid `->` inside node IDs. IDs may contain `[A-Za-z][A-Za-z0-9_-]*` — hyphens are valid (e.g. `CB-101` is a legal ID).\\n\\n**Attribute block** — `[…]` brackets may span multiple physical lines. The parser joins continuation lines until the bracket depth reaches zero.\\n\\n**Duplicate IDs** throw `SLDParseError: Duplicate node id \\\"…\\\"`.\\n\\n---\\n\\n## 7. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `xfmr1 [type: transformer]` | `SLDParseError: Cannot parse line` | Use `=` assignment: `xfmr1 = transformer [...]` |\\n| `id = battery [...]` | `SLDParseError: Unknown node type \\\"battery\\\"` | No `battery` type — use `ups` or `generator` |\\n| `id = breakerz` | `SLDParseError: Unknown node type ... (did you mean 'breaker'?)` | Use the suggested canonical type or alias |\\n| `A -- B` (bidirectional) | `SLDParseError: Cannot parse line` | Only `->` is accepted; use two `->` lines if needed |\\n| `A -> B -> C` (chained) | `SLDParseError: Cannot parse line` | Each connection is one `->` per line |\\n| `relay [label: \\\"OC\\\"]` (no device number) | Relay renders with blank number | Add `device: \\\"51\\\"` for the ANSI device number |\\n| `voltage: 480V` (unquoted) | Attribute value not recognized | Quote all values: `voltage: \\\"480V\\\"` |\\n| Node ID starting with digit: `2BUS` | `SLDParseError: Cannot parse line` | IDs must start with a letter: `BUS2` |\\n| Connection before node declared | `SLDParseError: Connection references unknown node \\\"…\\\"` | Declare nodes before or after connections — validated at end of parse, so order is flexible |\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = header NEWLINE ( blank | comment | node-def | connection )*\\n\\nheader = \\\"sld\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nnode-def = id WS \\\"=\\\" WS node-type ( WS \\\"[\\\" attr-list \\\"]\\\" )? NEWLINE\\nnode-type = \\\"utility\\\" | \\\"generator\\\" | \\\"solar\\\" | \\\"wind\\\" | \\\"ups\\\"\\n | \\\"transformer\\\" | \\\"transformer_dy\\\" | \\\"transformer_yd\\\"\\n | \\\"transformer_yy\\\" | \\\"transformer_dd\\\"\\n | \\\"autotransformer\\\" | \\\"transformer_3winding\\\"\\n | \\\"bus\\\" | \\\"bus_tie\\\" | \\\"hub\\\"\\n | \\\"breaker\\\" | \\\"breaker_vacuum\\\" | \\\"switch\\\" | \\\"switch_load\\\"\\n | \\\"ground_switch\\\" | \\\"ats\\\" | \\\"recloser\\\" | \\\"sectionalizer\\\"\\n | \\\"fuse\\\" | \\\"fuse_cl\\\"\\n | \\\"ct\\\" | \\\"pt\\\" | \\\"relay\\\" | \\\"surge_arrester\\\" | \\\"ground_fault\\\"\\n | \\\"motor\\\" | \\\"load\\\" | \\\"capacitor_bank\\\" | \\\"harmonic_filter\\\" | \\\"vfd\\\"\\n | \\\"watthour_meter\\\" | \\\"demand_meter\\\"\\n | residential-alias\\n\\nresidential-alias\\n = \\\"mcb\\\" | \\\"mccb\\\" | \\\"rcd\\\" | \\\"rcbo\\\" | \\\"rccb\\\"\\n | \\\"differential\\\" | \\\"diferencial\\\" | \\\"pia\\\" | \\\"iga\\\"\\n | \\\"main_switch\\\" | \\\"isolator\\\" | \\\"disconnector\\\"\\n | \\\"consumer_unit\\\" | \\\"distribution_board\\\" | \\\"panel\\\" | \\\"panelboard\\\"\\n\\nattr-list = attr ( \\\",\\\" attr )*\\nattr = key \\\":\\\" WS quoted-string\\n\\nconnection = id WS \\\"->\\\" WS id ( WS \\\"[\\\" conn-attrs \\\"]\\\" )? NEWLINE\\nconn-attrs = conn-attr ( \\\",\\\" conn-attr )*\\nconn-attr = \\\"cable\\\" \\\":\\\" WS quoted-string\\n | \\\"label\\\" \\\":\\\" WS quoted-string\\n\\nid = [A-Za-z] [A-Za-z0-9_-]*\\nkey = [A-Za-z] [A-Za-z0-9_]*\\ncomment = ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\n```\\n\\nThe attribute block `[…]` may span multiple physical lines — the parser joins continuation lines until the bracket depth returns to zero.\\n\\nAuthoritative source: `src/diagrams/sld/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"entity\": {\n \"title\": \"Entity structure diagram\",\n \"content\": \"## 1. Your first entity structure\\n\\nThe smallest useful entity structure: a parent owning two subsidiaries.\\n\\n```\\nentity-structure \\\"Simple holding\\\"\\nentity holdco \\\"Holdco LLC\\\" llc@DE\\nentity opco \\\"OpCo Inc.\\\" corp@DE\\nentity sub_uk \\\"UK Sub Ltd.\\\" llc@UK\\nholdco -> opco : 100%\\nholdco -> sub_uk : 100%\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `entity-structure`, optionally followed by a quoted title.\\n2. Each legal entity is a node: `entity ID \\\"Display Name\\\" type` — the type determines the shape.\\n3. Connect entities with `->`. Append `: pct` to label ownership percentage: `parent -> child : 60%`.\\n4. Add `@jurisdiction` after the type to show a jurisdiction badge: `corp@DE`.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Entity types\\n\\nThe entity type determines the shape rendered for that node. Schematex maps several common aliases to a canonical type.\\n\\n| Canonical type | Aliases accepted | Rendered shape | Typical use |\\n|---|---|---|---|\\n| `corp` | `corporation`, `inc` | Rectangle (sharp corners) | C-corp, S-corp, Ltd., SA, AG |\\n| `llc` | `llp`, `gmbh`, `bv` | Rounded rectangle | LLC, LLP, GmbH, BV |\\n| `lp` | `lllp`, `fund` | Notched rectangle | LP, LLLP, investment fund |\\n| `trust` | — | Ellipse | Family trust, statutory trust |\\n| `individual` | `person` | Circle | Founder, grantor, natural person |\\n| `foundation` | `npo` | Pentagon (shield) | Non-profit, charitable foundation |\\n| `disregarded` | `branch` | Dashed rectangle | Disregarded entity, foreign branch |\\n| `pool` | — | Dashed rounded rectangle | Option pool, ESOP, unissued shares |\\n| `placeholder` | `tbf` | Dashed rectangle (faded) | To-be-formed entity, acquisition target |\\n\\n**Entity syntax:**\\n\\n```\\nentity ID \\\"Display Name\\\" type\\nentity ID \\\"Display Name\\\" type@JURISDICTION\\nentity ID \\\"Display Name\\\" type@JURISDICTION [properties]\\n```\\n\\n**ID rules.** Must start with a letter, followed by letters, digits, underscores, or hyphens: `[A-Za-z][A-Za-z0-9_-]*`.\\n\\n```\\nentity-structure \\\"Entity type shapes\\\"\\nentity c1 \\\"Delaware C-Corp\\\" corp@DE\\nentity l1 \\\"California LLC\\\" llc@CA\\nentity p1 \\\"Cayman Fund LP\\\" lp@KY\\nentity t1 \\\"Family Trust\\\" trust@SD\\nentity i1 \\\"Jane Smith\\\" individual\\nentity f1 \\\"Acme Foundation\\\" foundation\\nentity d1 \\\"Irish Branch\\\" disregarded@IE\\nentity pool1 \\\"ESOP Pool\\\" pool\\nentity tbf1 \\\"Acquisition Target\\\" placeholder\\nc1 -> l1 : 100%\\nc1 -> p1 : 80%\\nc1 -> f1\\ni1 -> t1\\nt1 -> c1 : 100%\\n```\\n\\n---\\n\\n## 3. Node properties\\n\\nOptional properties inside `[…]` annotate the entity with additional context visible in the rendered node.\\n\\n| Property | Syntax | Effect |\\n|---|---|---|\\n| `status: new` | `new`, `eliminated`, `modified`, `normal` | Visual badge for transaction-step diagrams |\\n| `tax: ccorp` | quoted string | Tax classification label below entity name |\\n| `role: \\\"Grantor\\\"` | quoted string | Role label (for individuals and trustees) |\\n| `note: \\\"…\\\"` | quoted string | Small note displayed inside the node |\\n| `est: \\\"2024-03-15\\\"` | quoted string | Formation date |\\n\\nAny key not in the reserved set (`status`, `tax`, `role`, `note`, `est`) is stored as a custom property.\\n\\n```\\nentity alice \\\"Alice Chen\\\" individual [role: \\\"Founder & CEO\\\"]\\nentity trust1 \\\"Smith Irrevocable Trust\\\" trust@SD [est: \\\"2019-06-01\\\", note: \\\"Spendthrift provisions\\\"]\\nentity opco \\\"OpCo, Inc.\\\" corp@DE [status: new, tax: ccorp]\\n```\\n\\n---\\n\\n## 4. Jurisdiction\\n\\nAppend `@CODE` after the entity type to display a jurisdiction badge on the node. The code is a 2–3 letter string — ISO 3166-1 alpha-2 country codes and US state abbreviations are both accepted.\\n\\n```\\nentity parent \\\"Parent Corp\\\" corp@US\\nentity ie_sub \\\"Ireland Sub\\\" corp@IE\\nentity ky_fund \\\"Cayman Fund\\\" lp@KY\\nentity de_llc \\\"Delaware LLC\\\" llc@DE\\n```\\n\\nCommon codes: `US` United States · `DE` Delaware · `CA` California · `NY` New York · `UK` United Kingdom · `IE` Ireland · `NL` Netherlands · `KY` Cayman Islands · `SG` Singapore · `HK` Hong Kong · `JP` Japan · `BM` Bermuda · `VG` British Virgin Islands · `CH` Switzerland · `LU` Luxembourg · `SD` South Dakota.\\n\\n`@DE` resolves as Delaware by default (most common in US legal contexts).\\n\\n### Jurisdiction clusters\\n\\nDeclare a jurisdiction with `jurisdiction CODE \\\"Name\\\" [color: \\\"#hex\\\"]` to group all entities sharing that code into a labeled, dashed-border cluster region on the diagram.\\n\\n```\\njurisdiction US \\\"United States\\\" [color: \\\"#3b82f6\\\"]\\njurisdiction IE \\\"Ireland\\\" [color: \\\"#059669\\\"]\\n```\\n\\nWhen an entity's `@CODE` matches a declared `jurisdiction`, it is automatically placed inside that cluster. If `jurisdiction` is not declared, the badge still appears but no cluster region is drawn.\\n\\n```\\nentity-structure \\\"IP holding structure\\\"\\njurisdiction US \\\"United States\\\" [color: \\\"#3b82f6\\\"]\\njurisdiction IE \\\"Ireland\\\" [color: \\\"#059669\\\"]\\njurisdiction KY \\\"Cayman Islands\\\" [color: \\\"#d97706\\\"]\\nentity parent \\\"TopCo, Inc.\\\" corp@US\\nentity ie_hold \\\"Ireland Holdings\\\" corp@IE\\nentity ie_ip \\\"IP HoldCo\\\" corp@KY [note: \\\"Group IP\\\"]\\nentity ie_op \\\"EU Opco\\\" llc@IE\\nparent -> ie_hold : 100%\\nie_hold -> ie_ip : 100%\\nie_hold -> ie_op : 100%\\nie_ip -~-> ie_op [label: \\\"IP License\\\"]\\n```\\n\\n### Manual clusters\\n\\nUse `cluster \\\"Label\\\" [members: [id1, id2], color: \\\"#hex\\\"]` to group entities that don't share a single jurisdiction code.\\n\\n```\\ncluster \\\"Ireland / Cayman IP\\\" [members: [ie_ip, nl_bv], color: \\\"#059669\\\"]\\n```\\n\\n---\\n\\n## 5. Ownership edges\\n\\nAn edge line connects two entity IDs with an operator. The operator determines the line style and visual semantics.\\n\\n| Operator | Renders as | Meaning |\\n|---|---|---|\\n| `->` | Solid arrow | Equity ownership (default) |\\n| `==>` | Double line arrow | Voting-only control (no economic interest) |\\n| `-.->` | Dashed grey arrow | Option pool / conditional ownership |\\n| `-~->` | Dashed purple arrow | IP license, management agreement, intercompany service |\\n| `-->` | Dashed green arrow | Distribution (trust to beneficiaries) |\\n\\n**Ownership percentage:** append `: pct` after the target ID.\\n\\n```\\nparent -> subsidiary : 60%\\n```\\n\\n**Share class:** add `[class: \\\"Series A Pref\\\"]` to label the share class on the edge.\\n\\n```\\nvc -> startup : 22% [class: \\\"Series A Pref\\\"]\\n```\\n\\n**Non-equity label:** use `[label: \\\"…\\\"]` for descriptive edge text on license or distribution edges.\\n\\n```\\nip_co -~-> opco [label: \\\"IP License · royalty\\\"]\\ntrust --> beneficiary [label: \\\"Discretionary distributions\\\"]\\n```\\n\\n**Combining:** `class:` and `label:` can appear together.\\n\\n```\\nfund -> portfolio : 35% [class: \\\"Common\\\", label: \\\"Post-Series B\\\"]\\n```\\n\\n```\\nentity-structure \\\"Mixed edge types\\\"\\nentity holdco \\\"HoldCo LLC\\\" llc@DE\\nentity opco \\\"OpCo Inc.\\\" corp@DE\\nentity ip_co \\\"IP Ltd\\\" corp@KY\\nentity fund \\\"Growth Fund\\\" lp@DE\\nentity esop \\\"ESOP Pool\\\" pool\\nentity trust1 \\\"Family Trust\\\" trust@SD\\nentity founder \\\"J. Smith\\\" individual\\n# Equity ownership\\nholdco -> opco : 100%\\nholdco -> ip_co : 100%\\n# IP license (non-equity)\\nip_co -~-> opco [label: \\\"Exclusive license\\\"]\\n# Option pool (dashed)\\nesop -.-> opco : 10%\\n# Voting control\\nfund ==> holdco\\n# Trust distribution\\ntrust1 --> founder [label: \\\"Income distributions\\\"]\\nfounder -> trust1 : 100%\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `entity-structure \\\"Acme Holdings\\\"` — first line, quoted.\\n- **Entity display name:** the quoted string in `entity ID \\\"Name\\\" type` — appears inside the node.\\n- **Jurisdiction badge:** `@CODE` after type — 2–3 letter code shown in the node corner.\\n- **Node properties:** `[note: \\\"…\\\", role: \\\"…\\\", status: new, …]` — annotations inside the node.\\n- **Edge percentage:** `: pct` after the target ID — appears on the ownership arrow.\\n- **Edge class:** `[class: \\\"…\\\"]` — share class label on the arrow.\\n- **Edge label:** `[label: \\\"…\\\"]` — descriptive text on the arrow.\\n- **Comments:** `#` at the start of a line (after leading whitespace). Inline trailing `#` comments inside bracket blocks are also stripped.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `entity-structure` (header), `entity`, `jurisdiction`, `cluster`.\\n\\n**Entity type keywords** — these strings are parsed as entity types and must not be used as entity IDs: `corp`, `corporation`, `inc`, `llc`, `llp`, `gmbh`, `bv`, `lp`, `lllp`, `fund`, `trust`, `individual`, `person`, `foundation`, `npo`, `disregarded`, `branch`, `pool`, `placeholder`, `tbf`.\\n\\n**Edge operator tokens** — avoid these sequences inside IDs: `->`, `==>`, `-.->`, `-~->`, `-->`.\\n\\n**Strings with spaces** must be double-quoted in display names, notes, role labels, and color values.\\n\\n**Jurisdiction codes** are case-insensitive in the source but normalized to uppercase: `@de` and `@DE` are equivalent.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `entity acme Acme Inc. corp@DE` (name unquoted) | Parse fails — name must be quoted | `entity acme \\\"Acme Inc.\\\" corp@DE` |\\n| `acme -> sub [50%]` (percent inside brackets) | `50%` not recognized as a property key | `acme -> sub : 50%` (colon before percent, outside brackets) |\\n| `entity acme \\\"Acme\\\" Ltd@DE` | `Ltd` is not a recognized type keyword | Use `corp` or `llc`; `Ltd` is not in the alias table |\\n| `acme -> unknown_id : 100%` | `EntityParseError: Edge references unknown entity \\\"unknown_id\\\"` | Declare every entity before using it in an edge |\\n| `cluster \\\"US entities\\\" [ids: [a, b]]` | `ids:` not recognized; property is silently ignored | Use `members: [a, b]` |\\n| `jurisdiction DE \\\"Delaware\\\"` then `entity co \\\"Co\\\" corp@DE` | Cluster draws around `co` — correct. But `@DE` in a US context is Delaware, not Germany | Use `@DE` for Delaware, `@DEU` is not valid — there is no ambiguity workaround; document the intent in a `note:` |\\n| `entity x \\\"X\\\" corp [status: pending]` | `pending` is not a valid status — property silently stored as custom prop | Use `new`, `eliminated`, `modified`, or `normal` |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | jurisdiction-def | cluster-def | entity-def | edge)*\\n\\nheader = \\\"entity-structure\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\njurisdiction-def = \\\"jurisdiction\\\" CODE WS quoted-string ( \\\"[\\\" jur-attrs \\\"]\\\" )? NEWLINE\\njur-attrs = jur-attr (\\\",\\\" jur-attr)*\\njur-attr = \\\"color:\\\" quoted-string\\n\\ncluster-def = \\\"cluster\\\" WS quoted-string ( \\\"[\\\" cluster-attrs \\\"]\\\" )? NEWLINE\\ncluster-attrs = cluster-attr (\\\",\\\" cluster-attr)*\\ncluster-attr = \\\"members:\\\" \\\"[\\\" id (\\\",\\\" id)* \\\"]\\\"\\n | \\\"color:\\\" quoted-string\\n\\nentity-def = \\\"entity\\\" WS id WS quoted-string WS entity-type ( \\\"@\\\" CODE )?\\n ( \\\"[\\\" entity-attrs \\\"]\\\" )? NEWLINE\\nentity-attrs = entity-attr (\\\",\\\" entity-attr)*\\nentity-attr = \\\"status:\\\" status\\n | \\\"tax:\\\" quoted-string\\n | \\\"role:\\\" quoted-string\\n | \\\"note:\\\" quoted-string\\n | \\\"est:\\\" quoted-string\\n | key \\\":\\\" quoted-string # custom property\\n\\nentity-type = \\\"corp\\\" | \\\"corporation\\\" | \\\"inc\\\"\\n | \\\"llc\\\" | \\\"llp\\\" | \\\"gmbh\\\" | \\\"bv\\\"\\n | \\\"lp\\\" | \\\"lllp\\\" | \\\"fund\\\"\\n | \\\"trust\\\"\\n | \\\"individual\\\" | \\\"person\\\"\\n | \\\"foundation\\\" | \\\"npo\\\"\\n | \\\"disregarded\\\" | \\\"branch\\\"\\n | \\\"pool\\\"\\n | \\\"placeholder\\\" | \\\"tbf\\\"\\n\\nedge = id WS op WS id ( \\\":\\\" WS pct-text )? ( \\\"[\\\" edge-attrs \\\"]\\\" )? NEWLINE\\nop = \\\"->\\\" | \\\"==>\\\" | \\\"-.->\\\" | \\\"-~->\\\" | \\\"-->\\\"\\npct-text = any text up to \\\"[\\\" or end of line # e.g. \\\"100%\\\" or \\\"V 75% / E 50%\\\"\\n\\nedge-attrs = edge-attr (\\\",\\\" edge-attr)*\\nedge-attr = \\\"class:\\\" quoted-string\\n | \\\"label:\\\" quoted-string\\n\\nstatus = \\\"new\\\" | \\\"eliminated\\\" | \\\"modified\\\" | \\\"normal\\\"\\nCODE = [A-Za-z]{2,3}\\nid = [A-Za-z] [A-Za-z0-9_-]*\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/entity/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"fishbone\": {\n \"title\": \"Fishbone diagram\",\n \"content\": \"## 1. Your first fishbone\\n\\nThe smallest useful fishbone: three categories, one cause each, one with a sub-cause.\\n\\n```\\nfishbone \\\"API latency spike\\\"\\neffect \\\"P99 > 2 s after deploy\\\"\\ncategory code \\\"Code\\\"\\ncategory infra \\\"Infra\\\"\\ncategory data \\\"Data\\\"\\ncode : \\\"N+1 query in new endpoint\\\"\\n - \\\"Missing eager-load on orders\\\"\\ninfra : \\\"DB connection pool exhausted\\\"\\ndata : \\\"Index missing on accounts table\\\"\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `fishbone`, optionally followed by a quoted title.\\n2. Declare each branch with `category id \\\"Label\\\"` — the `id` is a short internal key, `\\\"Label\\\"` is what prints on the diagram.\\n3. Add causes with `id : \\\"cause text\\\"` on their own lines.\\n4. Indent a line by at least 2 spaces and start it with `-` to create a sub-cause (second-order branch) under the preceding cause.\\n\\n> Comments may start with `#`, `//`, or Mermaid-style `%%` on their own line.\\n\\n---\\n\\n## 2. Building blocks\\n\\n### The spine and effect\\n\\n`effect \\\"Problem statement\\\"` places text in the fish's head. If `effect` is omitted the parser falls back to the diagram title.\\n\\n```\\nfishbone \\\"Title\\\"\\neffect \\\"Specific problem statement\\\"\\n```\\n\\nThe head sits on the right by default (`config direction = right`). Use `config direction = left` to flip it.\\n\\n### Categories (major bones)\\n\\n`category id \\\"Label\\\"` declares a branch. The `id` is used internally to assign causes; the quoted `\\\"Label\\\"` appears on the diagram.\\n\\nCategories also accept optional properties in `[…]`:\\n\\n| Property | Values | Effect |\\n|---|---|---|\\n| `color: \\\"#hex\\\"` | hex color string | Branch and label color |\\n| `side: top` / `side: bottom` | `top`, `bottom` | Forces this branch to the top or bottom rail (default: alternating) |\\n| `order: N` | integer | Position within its rail — lower numbers sit closer to the tail |\\n\\n```\\ncategory rework \\\"Rework\\\" [color: \\\"#E53935\\\", side: top, order: 1]\\n```\\n\\n### Causes (minor bones)\\n\\nTwo styles are accepted and can be mixed in one diagram:\\n\\n**Style A — structured.** Declare categories first, then assign causes with `id : \\\"text\\\"`:\\n\\n```\\ncategory code \\\"Code\\\"\\ncategory infra \\\"Infra\\\"\\ncode : \\\"N+1 query in endpoint\\\"\\ncode : \\\"Missing cache layer\\\"\\ninfra : \\\"Auto-scaling lag\\\"\\n```\\n\\n**Style B — compact.** Category label and causes in one line, separated by `;` or `,`:\\n\\n```\\ncategory Code: N+1 query; Missing cache; Synchronous call\\ncategory Infra: Auto-scaling lag; CDN misconfigured\\n```\\n\\nIn compact style the `id` is auto-derived from the label text (lowercased, spaces → hyphens). Quotes are optional for cause text.\\n\\n```\\nfishbone \\\"Conversion rate drop\\\"\\neffect \\\"Checkout conversion -12% MoM\\\"\\n# Style A — structured\\ncategory ux \\\"UX\\\"\\ncategory trust \\\"Trust\\\"\\nux : \\\"Confusing multi-step form\\\"\\nux : \\\"Slow page on mobile\\\"\\ntrust : \\\"No payment security badge\\\"\\n# Style B — compact\\ncategory Pricing: Price-anchoring missing; No annual discount shown; Coupon field too prominent\\n```\\n\\n**Style C — Mermaid-mindmap shorthand.** A top-level bare line becomes a category,\\nand indented `-` items become sibling Level-1 causes under that category:\\n\\n```txt\\nfishbone \\\"Why is the site slow?\\\"\\neffect \\\"Page LCP > 4s\\\"\\nContent\\n - heavy hero image\\n - too much above-the-fold text\\nTech\\n - JS bundle too large\\n - render-blocking CSS\\n```\\n\\n---\\n\\n## 3. Sub-causes (second-order branches)\\n\\nIndent a `-` line by at least 2 spaces after a Level-1 cause to attach a sub-cause to it. The `-` dash is part of the syntax; the text follows it.\\n\\n```\\nmethod : \\\"Stencil aperture undersized\\\"\\n - \\\"Tolerance spec from 2018 board revision\\\"\\n - \\\"No re-validation after material change\\\"\\nmethod : \\\"Pick-and-place speed too high\\\"\\n - \\\"Speed limit lifted during overtime run\\\"\\n```\\n\\nSub-causes appear as shorter, narrower twigs branching off their parent rib.\\n\\n```\\nfishbone \\\"Medication error increase\\\"\\neffect \\\"Errors up 18% in Q3\\\"\\ncategory process \\\"Process\\\"\\ncategory people \\\"People\\\"\\nprocess : \\\"CPOE alert fatigue\\\"\\n - \\\"47 non-critical alerts per shift\\\"\\n - \\\"Override too easy — one click\\\"\\nprocess : \\\"5-Rights verification skipped\\\"\\n - \\\"No barcode scanner at bedside\\\"\\npeople : \\\"Float staff unfamiliar with unit\\\"\\n - \\\"No unit-specific orientation checklist\\\"\\npeople : \\\"Handoff communication gaps\\\"\\n```\\n\\n---\\n\\n## 4. Config options\\n\\n`config key = value` lines can appear anywhere after the header. Unknown keys and values are silently ignored.\\n\\n| Config key | Values | Default | Effect |\\n|---|---|---|---|\\n| `direction` | `right` / `left` (also `ltr` / `rtl`) | `right` | Which side the effect head appears on |\\n| `sides` | `both`, `top`, `bottom` | `both` | Which half of the spine hosts branches |\\n| `density` | `compact`, `normal`, `spacious` | `normal` | Spacing between ribs — affects how many branches fit before overlap |\\n| `slope` (or `ribslope`) | `gentle`, `normal`, `steep`, or a number (0–3) | `normal` (0.6) | Rib angle — shallow vs. steep diagonal |\\n| `causeside` (or `cause-side`) | `head`, `tail`, `both` | `head` | Which side of a rib sub-causes branch off from |\\n| `width` | integer px | auto | Override canvas width |\\n| `height` | integer px | auto | Override canvas height |\\n\\n```\\nconfig direction = left\\nconfig density = compact\\nconfig slope = gentle\\nconfig sides = top\\n```\\n\\n---\\n\\n## 5. Labels & comments\\n\\n- **Diagram title:** `fishbone \\\"Website Traffic Drop\\\"` — first line, optional.\\n- **Effect label:** `effect \\\"30% organic traffic decline\\\"` — the problem at the fish's head.\\n- **Category label:** `category id \\\"Human-readable name\\\"` — printed on the branch.\\n- **Cause text:** quoted `\\\"like this\\\"` or unquoted (spaces allowed in compact style).\\n- **Sub-cause text:** after the leading `-`, quoted or unquoted.\\n- **Comments:** `#`, `//`, or `%%` at the start of a line (after optional leading whitespace). The same markers also start trailing comments outside double-quoted strings.\\n\\n---\\n\\n## 6. Reserved words & escaping\\n\\n**Reserved at line start:** `fishbone` (header), `effect`, `category`, `config`.\\n\\n**The `-` prefix** on an indented line is reserved as the sub-cause marker. To include a literal hyphen-dash at the start of cause text, quote it: `code : \\\"- old deprecated path\\\"`.\\n\\n**Strings with spaces** in structured-style cause text should be double-quoted: `code : \\\"N+1 query\\\"`. In compact style (`category Label: ...`) the text runs to the `;` or `,` separator and quoting is optional.\\n\\n**Comment markers** (`#`, `//`, `%%`) start a comment unless inside a double-quoted string.\\n\\n| Reserved sequence | Context | Alternative |\\n|---|---|---|\\n| `#` at line start | Comment marker | Quote the text if `#` is part of content |\\n| `-` at start after ≥2-space indent | Sub-cause marker | Quote: `- \\\"- text with dash\\\"` |\\n| `category`, `effect`, `config`, `fishbone` | Line-start keywords | Cannot be used as category IDs |\\n\\n---\\n\\n## 7. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `cause1 : \\\"text\\\"` with no prior `category cause1` | `FishboneParseError: Unknown category \\\"cause1\\\"` | Declare `category cause1 \\\"Label\\\"` before assigning causes |\\n| `- \\\"sub-cause\\\"` at the start of the file (no preceding Level-1 cause) | `FishboneParseError: Sub-cause … has no preceding Level-1 cause` | Place the sub-cause line immediately after a `id : \\\"cause\\\"` line |\\n| `- \\\"sub-cause\\\"` with only 1-space indent | Treated as a cause line, not a sub-cause | Indent with at least 2 spaces |\\n| `category Code: cause one, cause two` | Parsed as compact style — `,` and `;` are both separators | Intended behavior; both separators work |\\n| `config direction = center` | Unknown value — silently ignored, stays `right` | Use `right` or `left` |\\n| `config slope = 45` | Out of range (must be 0–3 exclusive); silently ignored | Use a preset (`gentle`, `normal`, `steep`) or a value like `0.5` |\\n| `fishbone: \\\"Title\\\"` | Parsed correctly — colon after keyword is optional | Both `fishbone \\\"Title\\\"` and `fishbone: \\\"Title\\\"` work |\\n| Mermaid mindmap-style bare category | Parsed as an implicit category | `Content` followed by indented `- item` lines works without `category` |\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | effect | category | config | cause | sub-cause | implicit-category)*\\n\\nheader = \\\"fishbone\\\" \\\":\\\"? ( WS quoted-string )? NEWLINE\\neffect = \\\"effect\\\" \\\":\\\"? WS quoted-string NEWLINE\\nconfig = \\\"config\\\" WS config-key WS \\\"=\\\" WS config-value NEWLINE\\nconfig-key = \\\"direction\\\" | \\\"width\\\" | \\\"height\\\" | \\\"sides\\\"\\n | \\\"slope\\\" | \\\"ribslope\\\" | \\\"density\\\" | \\\"causeside\\\" | \\\"cause-side\\\"\\nconfig-value = bare-word | number | quoted-string\\n\\ncategory = \\\"category\\\" WS id WS label-or-compact ( \\\"[\\\" category-attrs \\\"]\\\" )? NEWLINE\\nimplicit-category\\n = bare-text NEWLINE # top-level, no \\\":\\\"\\n\\nlabel-or-compact\\n = quoted-string # structured form: category id \\\"Label\\\"\\n | id WS \\\":\\\" WS compact-causes # compact form: category Label: cause; cause\\n\\ncategory-attrs = category-attr (\\\",\\\" category-attr)*\\ncategory-attr = \\\"color:\\\" quoted-string\\n | \\\"side:\\\" ( \\\"top\\\" | \\\"bottom\\\" )\\n | \\\"order:\\\" integer\\n\\ncause = id WS \\\":\\\" WS cause-text NEWLINE # structured form\\ncause-text = quoted-string | bare-text\\n\\nsub-cause = INDENT≥2 \\\"-\\\" WS cause-text NEWLINE\\n\\ncompact-causes = compact-cause ( (\\\";\\\" | \\\",\\\") compact-cause )*\\ncompact-cause = quoted-string | bare-text\\n\\ncomment = ( \\\"#\\\" | \\\"//\\\" | \\\"%%\\\" ) any NEWLINE\\nid = [a-zA-Z] [a-zA-Z0-9_-]*\\nquoted-string = '\\\"' any-char-but-unescaped-quote* '\\\"'\\n```\\n\\nAuthoritative source: `src/diagrams/fishbone/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"venn\": {\n \"title\": \"Venn / Euler diagram\",\n \"content\": \"## 1. Your first Venn diagram\\n\\nThe smallest useful diagram: two sets, one overlap, two exclusive regions.\\n\\n```\\nvenn \\\"Support channels\\\"\\nset A \\\"Email support\\\" [color: \\\"#1E88E5\\\"]\\nset B \\\"Live chat\\\" [color: \\\"#E53935\\\"]\\nA & B : 320\\nA only : 1450\\nB only : 890\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `venn`, optionally followed by a quoted title.\\n2. Declare each **set** with `set ID \\\"Label\\\"` — the id is used internally, the label appears in the diagram.\\n3. Assign values to **regions** using `A & B : value` for intersections and `A only : value` for exclusive regions.\\n4. Configure appearance with `config:` lines; the diagram mode (`venn` vs `euler`) can be set explicitly or left as `auto`.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Sets\\n\\nA set declaration creates one circle in the diagram.\\n\\n```\\nset ID \\\"Label\\\" [color: \\\"#hex\\\"]\\n```\\n\\n| Part | Required | Notes |\\n|---|---|---|\\n| `ID` | Yes | Must match `[A-Za-z][A-Za-z0-9_-]*` |\\n| `\\\"Label\\\"` | Yes | Quoted string displayed on the circle |\\n| `[color: \\\"#hex\\\"]` | No | Override fill color for this set |\\n\\nSets must be declared before they are referenced in region or relation lines.\\n\\n```\\nvenn \\\"Programming paradigms\\\"\\nset oop \\\"Object-Oriented\\\" [color: \\\"#1E88E5\\\"]\\nset fp \\\"Functional\\\" [color: \\\"#E53935\\\"]\\nset logic \\\"Logic\\\" [color: \\\"#43A047\\\"]\\noop & fp : 180\\noop & logic : 45\\nfp & logic : 90\\noop & fp & logic : 12\\noop only : 620\\nfp only : 340\\nlogic only : 95\\n```\\n\\n---\\n\\n## 3. Regions\\n\\nA region assigns a value to an intersection or exclusive area. The four DSL modes can be mixed in one diagram.\\n\\n### 3.1 Declarative mode — counts and percentages\\n\\nAssign a number or percentage to a named region. The region key is either an `&`-separated list of set ids (for intersections) or `ID only` (for the part of that set not covered by any other set).\\n\\n```\\nA & B : 320 # integer count\\nA & B & C : 45 # three-way intersection\\nA only : 1450 # A minus all other sets\\nA & B : 18.5% # percentage value\\n```\\n\\n```\\nvenn \\\"Market research\\\"\\nset aware \\\"Awareness\\\" [color: \\\"#7B1FA2\\\"]\\nset consider \\\"Consideration\\\" [color: \\\"#0288D1\\\"]\\nset convert \\\"Conversion\\\" [color: \\\"#388E3C\\\"]\\naware & consider : 3400\\nconsider & convert : 890\\naware & convert : 210\\naware & consider & convert : 150\\naware only : 18200\\nconsider only : 2100\\nconvert only : 540\\n```\\n\\n### 3.2 Region labels (text)\\n\\nUse the `region` keyword prefix and assign a quoted string instead of a number. The string is rendered inside the region.\\n\\n```\\nregion A & B : \\\"Nurture\\\"\\nregion B & C : \\\"Convert\\\"\\nregion A & B & C : \\\"Loyal customer\\\"\\n```\\n\\n```\\nvenn \\\"Go-to-market funnel\\\"\\nset A \\\"Awareness\\\" [color: \\\"#7B1FA2\\\"]\\nset B \\\"Consideration\\\" [color: \\\"#0288D1\\\"]\\nset C \\\"Purchase\\\" [color: \\\"#388E3C\\\"]\\nregion A & B : \\\"Nurture\\\"\\nregion B & C : \\\"Convert\\\"\\nregion A only : \\\"Cold audience\\\"\\nregion A & B & C : \\\"Loyal\\\"\\nregion C only : \\\"Direct buyers\\\"\\n```\\n\\n### 3.3 Enumeration mode — element lists\\n\\nList the actual elements of each set. Schematex computes all intersections automatically.\\n\\n```\\nID = { element1, element2, element3 }\\n```\\n\\nElements are comma-separated bare words or quoted strings. Enumeration sets do not need an explicit `set` declaration — the declaration is implied.\\n\\n```\\nvenn \\\"Full-stack team skills\\\"\\nFrontend = { React, TypeScript, CSS, Jest, Webpack }\\nBackend = { TypeScript, Node.js, PostgreSQL, Jest, Redis }\\nDevOps = { Docker, Kubernetes, PostgreSQL, Terraform, Redis }\\n```\\n\\n---\\n\\n## 4. Euler relations\\n\\nEuler relations express structural containment or separation — that one set is a subset of another, that two sets are completely disjoint, or that they merely overlap. They must reference set ids already declared with `set`.\\n\\n```\\nfrom subset to # from is fully inside to (also: \\\"in\\\")\\nfrom in to # alias for subset\\nfrom disjoint to # from and to do not overlap\\nfrom overlap to # from and to partially overlap (explicit — the default for unrelated sets)\\n```\\n\\n```\\nvenn \\\"Biology taxonomy\\\"\\nset animals \\\"Animals\\\"\\nset vertebrates \\\"Vertebrates\\\"\\nset mammals \\\"Mammals\\\"\\nset birds \\\"Birds\\\"\\nset fish \\\"Fish\\\"\\nvertebrates subset animals\\nmammals subset vertebrates\\nbirds subset vertebrates\\nfish subset vertebrates\\nmammals disjoint birds\\nmammals disjoint fish\\nbirds disjoint fish\\n```\\n\\n| Keyword | Alias | Meaning |\\n|---|---|---|\\n| `subset` | `in` | `from` is fully contained within `to` |\\n| `disjoint` | — | `from` and `to` do not intersect |\\n| `overlap` | — | `from` and `to` intersect but neither contains the other |\\n\\n---\\n\\n## 5. Configuration\\n\\n`config:` lines tune diagram behavior. Each goes on its own line.\\n\\n| Config key | Values | Default | Effect |\\n|---|---|---|---|\\n| `diagram` | `venn`, `euler`, `auto` | `auto` | Force Venn (all circles fixed) or Euler (subset nesting). `auto` infers from the presence of Euler relations. |\\n| `proportional` | `true`, `false` | `false` | Scale circle area proportional to region count values |\\n| `showCounts` | `true`, `false` | `auto` | Always / never show count labels. `auto` shows them when counts are provided. |\\n| `showPercent` | `true`, `false` | `false` | Show each region value as a percentage of the grand total |\\n| `palette` | `default`, `brand`, `monochrome` | `default` | Color palette for sets (overridden by per-set `color:`) |\\n| `blendMode` | `multiply`, `screen`, `none` | `multiply` | How overlapping fill colors blend |\\n\\nConfig can also be written inline on the header line: `venn \\\"Title\\\" [proportional: true, showPercent: true]`.\\n\\n```\\nvenn \\\"Segment overlap\\\"\\nconfig: proportional = true\\nconfig: showPercent = true\\nconfig: blendMode = screen\\n```\\n\\n**Layout selection:**\\n\\n- `layout venn` — alternative form of `config: diagram = venn` (parses identically).\\n- `layout euler` — alternative form of `config: diagram = euler`.\\n- `layout auto` — alternative form of `config: diagram = auto`.\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `venn \\\"My diagram\\\"` — first line only.\\n- **Set label:** `set A \\\"Email subscribers\\\"` — quoted string on the `set` line.\\n- **Region value:** integer, percentage, quoted string, or element list assigned after the `:`.\\n- **Comments:** `#` at the start of a line (after leading whitespace).\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `venn` (header), `set`, `config:`, `layout`, `region`.\\n\\n**Reserved operators in region keys:** `&` (intersection), `only` (exclusive region).\\n\\n**Euler relation keywords:** `subset`, `in`, `disjoint`, `overlap` — cannot be used as set ids.\\n\\n**ID rules:** must match `[A-Za-z][A-Za-z0-9_-]*`. Labels with spaces go in the quoted `\\\"Label\\\"` field.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `A & B : 320` before `set A …` and `set B …` | `VennParseError: unknown set id \\\"A\\\" in region key` | Declare sets with `set` before referencing them in region lines |\\n| `dogs subset mammals` before `set dogs …` | `VennParseError: unknown set \\\"dogs\\\" in relation` | Declare sets first, then write Euler relations |\\n| `set A Email subscribers` (unquoted label with space) | Parser error — label is expected to be a quoted string | Quote it: `set A \\\"Email subscribers\\\"` |\\n| `A & B = 320` (equals instead of colon) | Line doesn't match region pattern; parse error | Use colon: `A & B : 320` |\\n| `Frontend = { React TypeScript }` (no commas) | `React TypeScript` treated as one element | Comma-separate: `Frontend = { React, TypeScript }` |\\n| `config: mode = venn` | `mode` is not a recognized key (key is `diagram`) | Use `config: diagram = venn` |\\n| Mixing enumeration sets with explicit `A & B :` regions | Enumeration auto-derive only runs when `regions.length === 0` | Use one style per diagram or add all regions explicitly |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | config | layout-stmt | set-decl | enum-decl | euler-rel | region)*\\n\\nheader = \\\"venn\\\" ( \\\":\\\"? WS quoted-string )? ( WS \\\"[\\\" config-props \\\"]\\\" )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nconfig = \\\"config\\\" WS \\\":\\\" WS config-key WS \\\"=\\\" WS config-value NEWLINE\\nconfig-key = \\\"diagram\\\" | \\\"proportional\\\" | \\\"palette\\\" | \\\"blendMode\\\" | \\\"showCounts\\\" | \\\"showPercent\\\"\\n\\nlayout-stmt = \\\"layout\\\" WS ( \\\"venn\\\" | \\\"euler\\\" | \\\"auto\\\" ) NEWLINE\\n\\nset-decl = \\\"set\\\" WS id WS quoted-string ( WS \\\"[\\\" set-props \\\"]\\\" )? NEWLINE\\nset-props = \\\"color:\\\" quoted-hex | \\\"fill:\\\" quoted-hex\\n\\nenum-decl = id WS \\\"=\\\" WS \\\"{\\\" element-list \\\"}\\\" NEWLINE\\nelement-list = element ( \\\",\\\" element )*\\nelement = quoted-string | bare-word\\n\\neuler-rel = id WS euler-op WS id NEWLINE\\neuler-op = \\\"subset\\\" | \\\"in\\\" | \\\"disjoint\\\" | \\\"overlap\\\"\\n\\nregion = \\\"region\\\"? WS region-key WS \\\":\\\" WS region-value NEWLINE\\nregion-key = id WS \\\"only\\\"\\n | id ( WS \\\"&\\\" WS id )+\\nregion-value = integer | percent | quoted-string | \\\"[\\\" element-list \\\"]\\\"\\n\\npercent = number \\\"%\\\"\\nid = [A-Za-z] [A-Za-z0-9_-]*\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/venn/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"decisiontree\": {\n \"title\": \"Decision tree diagram\",\n \"content\": \"## 1. Your first decision tree\\n\\nThe smallest useful decision tree: a root question with two branches.\\n\\n```\\n\\n decisiontree \\\"Laptop troubleshoot\\\"\\n\\n question \\\"Does it power on?\\\"\\n yes: answer \\\"Check display — connect external monitor\\\"\\n no: question \\\"Is the charger light on?\\\"\\n yes: answer \\\"Hold power button 10 s — try again\\\"\\n no: answer \\\"Check outlet and charging cable\\\"\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `decisiontree`, optionally with `:mode` and a quoted title.\\n2. Each question node uses `question \\\"text\\\"` (or shorthand `q \\\"text\\\"`).\\n3. Each answer/leaf uses `answer \\\"text\\\"` (or `a \\\"text\\\"` or `leaf \\\"text\\\"`).\\n4. Branch labels — `yes:`, `no:`, or a custom `label \\\"X\\\":` — prefix the child node on the same line.\\n\\nIndentation controls nesting: each level adds 2 spaces. The parser computes parent-child relationships from indent depth.\\n\\n> Comments must start with `#` or `//` on their own line.\\n\\n---\\n\\n## 2. Modes\\n\\nThe mode is set in the header line:\\n\\n| Header | Mode | Used for |\\n|---|---|---|\\n| `decisiontree` | taxonomy | Yes/no question flows, troubleshooting guides, clinical decision support |\\n| `decisiontree:decision` (or `decisiontree:da`) | decision analysis | Investment decisions, risk analysis, expected value calculation |\\n| `decisiontree:influence` (or `mode: influence`) | influence diagram | Compact DAG view of a decision problem — structure before unrolling to a tree |\\n| `decisiontree:ml` | machine learning | Visualizing trained CART classifiers (scikit-learn, XGBoost, etc.) |\\n\\nDefault direction is `top-down` for taxonomy and ML, `left-right` for decision analysis.\\n\\n---\\n\\n## 3. Taxonomy mode\\n\\nBest for: troubleshooting guides, FAQs, clinical protocols, product recommendation flows.\\n\\n### Node keywords\\n\\n| Keyword | Aliases | Meaning |\\n|---|---|---|\\n| `question \\\"…\\\"` | `q \\\"…\\\"` | Internal node — a question with children |\\n| `answer \\\"…\\\"` | `a \\\"…\\\"`, `leaf \\\"…\\\"` | Leaf node — a terminal outcome |\\n\\n### Branch labels\\n\\n| Syntax | Meaning |\\n|---|---|\\n| `yes: question \\\"…\\\"` | Branch labeled \\\"yes\\\" |\\n| `no: answer \\\"…\\\"` | Branch labeled \\\"no\\\" |\\n| `label \\\"Custom text\\\": answer \\\"…\\\"` | Branch with any custom label |\\n\\nCustom labels let you go beyond yes/no for multi-way decisions from one question.\\n\\n```\\n\\n decisiontree \\\"Triage — chest pain onset\\\"\\n\\n q \\\"Onset sudden?\\\"\\n yes: q \\\"ECG changes present?\\\"\\n yes: a \\\"ACS protocol — cardiology consult\\\"\\n no: q \\\"D-dimer elevated?\\\"\\n yes: a \\\"PE workup — CT pulmonary angiography\\\"\\n no: a \\\"Aortic dissection — CT angiography\\\"\\n no: q \\\"Pain reproducible on palpation?\\\"\\n yes: a \\\"Musculoskeletal — NSAIDs, follow-up PCP\\\"\\n no: a \\\"GI / anxiety — further history\\\"\\n```\\n\\n```\\n\\n decisiontree \\\"Pain level triage\\\"\\n\\n question \\\"Reported pain level?\\\"\\n label \\\"Severe (8-10)\\\": answer \\\"Emergency — send to ER immediately\\\"\\n label \\\"Moderate (4-7)\\\": answer \\\"Urgent care — within 2 hours\\\"\\n label \\\"Mild (1-3)\\\": answer \\\"Schedule next available — OTC care\\\"\\n label \\\"None\\\": answer \\\"Monitor — patient may be post-medication\\\"\\n```\\n\\n---\\n\\n## 4. Decision analysis mode\\n\\nBest for: investment decisions, build-vs-buy analysis, risk-weighted strategy evaluation.\\n\\n### Node keywords\\n\\n| Keyword | Aliases | Meaning |\\n|---|---|---|\\n| `decision \\\"…\\\"` | — | Decision node — the actor chooses a branch |\\n| `chance \\\"…\\\"` | — | Chance node — an uncertain outcome |\\n| `end \\\"…\\\"` | `outcome \\\"…\\\"` | Terminal node — final payoff |\\n\\n### Branch keywords\\n\\n| Keyword | Meaning |\\n|---|---|\\n| `choice \\\"label\\\"` | Names the incoming branch from a decision node |\\n| `prob N` | Sets the probability (0–1) on the incoming branch from a chance node |\\n\\n### Payoff attribute\\n\\n`payoff=N` on any node sets the payoff value. On `end` / `outcome` nodes it defines the terminal value. The parser runs expected-value rollback automatically: each `chance` node's EV is the probability-weighted sum of its children's EVs; each `decision` node's EV is the maximum child EV, and the optimal branch is flagged.\\n\\n**Constraint:** probabilities on all direct children of a `chance` node must sum to 1.0 (±0.01). The parser throws a `DTreeParseError` if they do not.\\n\\n```\\n\\n decisiontree:decision \\\"Cloud vendor selection\\\"\\n\\n decision \\\"Which vendor?\\\"\\n choice \\\"Build in-house\\\"\\n chance \\\"Project outcome\\\"\\n prob 0.6 end \\\"On-time delivery\\\" payoff=900000\\n prob 0.4 end \\\"Over budget / delayed\\\" payoff=150000\\n choice \\\"Managed SaaS vendor\\\"\\n end \\\"Predictable cost\\\" payoff=500000\\n choice \\\"Hybrid approach\\\"\\n chance \\\"Integration complexity\\\"\\n prob 0.5 end \\\"Smooth integration\\\" payoff=700000\\n prob 0.5 end \\\"Integration rework\\\" payoff=300000\\n```\\n\\n---\\n\\n## 5. Influence diagram mode\\n\\nBest for: framing a decision problem **compactly** before you unroll it. Where decision-analysis mode draws every branch of every outcome as an explicit tree, an **influence diagram** ([Howard & Matheson, 1981](https://en.wikipedia.org/wiki/Influence_diagram)) draws the *same* problem as a directed acyclic graph (DAG) of variables and the dependencies between them — one node per decision, uncertainty, and objective, no matter how many states each can take. It is the diagram decision analysts reach for first, because it shows the structure (what informs what, what affects the payoff) without the combinatorial blow-up of a tree.\\n\\nThis mode is **structural, not computational.** Unlike decision-analysis mode, it does not solve for expected value — the compact graph deliberately omits the probability and payoff tables that an EV rollback would need. Use it to communicate and validate the shape of the problem; use decision-analysis mode (section 4) when you want the numbers folded back.\\n\\n### Header forms\\n\\nTwo equivalent ways to select the mode:\\n\\n```\\ndecisiontree:influence \\\"Oil Wildcatter\\\"\\n```\\n\\nor, as a directive on its own line after the header:\\n\\n```\\ndecisiontree \\\"Market Entry\\\"\\n mode: influence\\n```\\n\\n### Node keywords\\n\\nEach node is declared as `kind Id \\\"label\\\"` — an id (used to wire arcs) followed by a quoted display label.\\n\\n| Keyword | Shape | Meaning |\\n|---|---|---|\\n| `decision Id \\\"…\\\"` | **rectangle** | A choice the decision-maker controls |\\n| `chance Id \\\"…\\\"` | **oval** | An uncertain variable (a state of the world) |\\n| `value Id \\\"…\\\"` | **octagon** | The objective / payoff being optimized |\\n\\nThe shapes follow the standard influence-diagram convention: decisions are rectangles, uncertainties are ovals, and the value node is an octagon. Add `utility=N` to a value node to annotate the payoff it represents (`value Profit \\\"Net profit\\\" utility=42`).\\n\\n### Arcs and their semantics\\n\\nArcs are written `Source -> Target` on their own lines, by node id. **An arc's meaning is read from its destination**, exactly as in the published standard:\\n\\n| Arc into a… | Meaning | Drawn as |\\n|---|---|---|\\n| `decision` | **Informational** — this is known *before* the decision is made | dashed line |\\n| `chance` | **Relevance / conditioning** — the source conditions this uncertainty | solid line |\\n| `value` | **Functional** — the source is an argument of the payoff function | solid line |\\n\\nThe dashed informational arc is the one to watch: `Seismic -> Drill` means \\\"the seismic test result is observed before choosing whether to drill,\\\" which is precisely what makes the decision worth modelling.\\n\\n### Validation rules\\n\\n- The graph must be **acyclic** — a cycle (e.g. `A -> B` and `B -> A`) is rejected.\\n- At least **one `value` node** is required; an influence diagram with no objective is not a decision problem.\\n- Arcs reference node ids that must be declared.\\n\\n### Examples\\n\\nThe Oil Wildcatter — the canonical teaching problem. The seismic test result is observed before the drill decision (dashed informational arc `Seismic -> Drill`), the test is relevant to whether oil is actually present (`Seismic -> Oil`), and both the oil state and the drill choice feed the profit (`Oil -> Profit`, `Drill -> Profit`).\\n\\n```\\n\\n decisiontree:influence \\\"Oil Wildcatter\\\"\\n decision Drill \\\"Drill?\\\"\\n chance Oil \\\"Oil present\\\"\\n chance Seismic \\\"Seismic test\\\"\\n value Profit \\\"Net profit\\\" utility=42\\n Seismic -> Oil\\n Seismic -> Drill\\n Oil -> Profit\\n Drill -> Profit\\n```\\n\\nA market-entry decision using the `mode: influence` directive form. Demand is observed before entering (`Demand -> Enter`, informational/dashed) and also drives profit directly, while the competitor's response feeds only the payoff.\\n\\n```\\n\\n decisiontree \\\"Market Entry\\\"\\n mode: influence\\n decision Enter \\\"Enter market?\\\"\\n chance Demand \\\"Market demand\\\"\\n chance Competition \\\"Competitor response\\\"\\n value V \\\"Profit\\\" utility=120\\n Demand -> Enter\\n Demand -> V\\n Competition -> V\\n Enter -> V\\n```\\n\\n---\\n\\n## 6. Machine learning mode\\n\\nBest for: explaining trained CART classifiers, model transparency reports, feature importance analysis.\\n\\n### Node keywords\\n\\n| Keyword | Meaning |\\n|---|---|\\n| `split \\\"…\\\"` | Internal split node — contains a feature test |\\n| `leaf \\\"…\\\"` | Leaf node — class or regression value |\\n\\n### Branch prefixes\\n\\n`true` and `false` prefix child nodes to mark which branch each child represents.\\n\\n### Properties (key=value, no colon, no quotes around values)\\n\\n| Property | Applies to | Meaning |\\n|---|---|---|\\n| `feature=name` | split | Feature name used at the split |\\n| `op=\\\"<=\\\"` | split | Comparison operator (quote if contains special chars) |\\n| `threshold=5.9` | split | Split threshold value |\\n| `samples=150` | split, leaf | Sample count at this node |\\n| `gini=0.5` | split, leaf | Gini impurity |\\n| `entropy=0.5` | split, leaf | Entropy impurity |\\n| `mse=0.3` | split, leaf | Mean squared error (regression) |\\n| `gain=0.2` | split, leaf | Information gain |\\n| `class=name` | leaf | Predicted class name |\\n| `value=50` | leaf | Sample count; use `value=[50,30,20]` for class distribution |\\n\\n```\\n\\n decisiontree:ml \\\"Iris classification (CART)\\\"\\n direction: top-down\\n impurity: gini\\n\\n split \\\"Petal length ≤ 2.45\\\" feature=petal_length op=\\\"<=\\\" threshold=2.45 samples=150 gini=0.667\\n true leaf \\\"Setosa\\\" class=Iris-setosa value=50 gini=0.0\\n false split \\\"Petal width ≤ 1.75\\\" feature=petal_width op=\\\"<=\\\" threshold=1.75 samples=100 gini=0.5\\n true leaf \\\"Versicolor\\\" class=Iris-versicolor value=50 gini=0.0\\n false leaf \\\"Virginica\\\" class=Iris-virginica value=50 gini=0.0\\n```\\n\\n---\\n\\n## 7. Config options\\n\\nConfig lines appear between the header and the first node. Each is `key: value` (colon, no `config` keyword).\\n\\n### Shared config (all modes)\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `direction:` | `top-down`, `left-right` | `top-down` (taxonomy/ML), `left-right` (decision) | Layout direction |\\n| `edgeStyle:` (or `edge-style:`) | `diagonal`, `orthogonal`, `bracket` | mode-dependent | Edge drawing style |\\n\\n### Taxonomy config\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `branchLabels:` (or `branch-labels:`) | `boolean`, `relation` | `boolean` | Branch label style |\\n\\n### Decision analysis config\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `branchLength:` (or `branch-length:`) | `probability` | off | Scale branch length proportional to probability |\\n\\n### ML config\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `impurity:` | `gini`, `entropy`, `mse`, `gain` | `gini` | Impurity metric shown on nodes |\\n| `classes:` | comma-separated list | — | Class label names for display |\\n\\n```\\ndecisiontree:ml \\\"Loan classifier\\\"\\ndirection: top-down\\nimpurity: gini\\nclasses: Approved, Denied, Review\\n```\\n\\n---\\n\\n## 8. Labels & comments\\n\\n- **Diagram title:** `decisiontree \\\"Title\\\"` — the quoted string after the header keyword.\\n- **Node label:** the quoted string immediately after the node keyword — `question \\\"Is the fee waived?\\\"`.\\n- **Branch label:** `yes:`, `no:`, or `label \\\"Custom\\\":` before the child node — on the same line as the child.\\n- **Payoff:** `payoff=250000` at the end of a decision/end node line.\\n- **ML properties:** `key=value` tokens after the node's label string (no `[…]` brackets, no colons).\\n- **Comments:** `#` or `//` at the start of a line (after optional leading whitespace). Only full-line comments are supported — inline trailing comments are not.\\n\\n---\\n\\n## 9. Reserved words & escaping\\n\\n**Reserved node keywords:** `decision`, `chance`, `end`, `outcome`, `choice`, `prob`, `split`, `leaf`, `question`, `q`, `answer`, `a`.\\n\\n**Reserved branch prefixes:** `yes:`, `no:`, `true`, `false`, `label`.\\n\\n**Reserved header forms:** `decisiontree`, `decisiontree:decision`, `decisiontree:da`, `decisiontree:ml`.\\n\\n**Strings with spaces** must be double-quoted: `question \\\"Annual revenue > $1M?\\\"`. Node labels, branch labels from `label \\\"…\\\":` syntax, and the diagram title all require double quotes.\\n\\n| Reserved token | Context | Notes |\\n|---|---|---|\\n| `yes:` / `no:` | Line start in taxonomy | Cannot be used as a label — use `label \\\"yes\\\":` if you need literal text \\\"yes\\\" |\\n| `true` / `false` | Line start in ML mode | Cannot be a node label |\\n| `choice` | Line start in decision mode | Acts as branch wrapper, not a node |\\n| `prob` | Line start in decision mode | Must be followed by a number |\\n\\n---\\n\\n## 10. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `yes: \\\"Approve\\\"` (no node keyword) | `DTreeParseError: Missing taxonomy node kind` | `yes: answer \\\"Approve\\\"` |\\n| Probabilities on `chance` children summing to 0.8 | `DTreeParseError: probabilities do not sum to 1.0` | Adjust so all `prob` values sum to exactly 1.0 (±0.01) |\\n| `question \\\"text\\\"` with a child at the same indent level | Child not parsed as a child — becomes a sibling | Indent children by 2 more spaces than the parent |\\n| `config direction = top-down` (using `config` keyword) | `config` is a fishbone keyword — not recognized here | Use `direction: top-down` (no `config` prefix) |\\n| `feature = petal_length` (spaces around `=`) | Parsed as separate tokens; property not recognized | No spaces: `feature=petal_length` |\\n| `[payoff: 500000]` bracket syntax | Not recognized — parser ignores brackets for payoff | Use `payoff=500000` (no brackets, no spaces around `=`) |\\n| `decisiontree:taxonomy` | `DTreeParseError: Invalid header` | Use `decisiontree` (no mode suffix for taxonomy) |\\n\\n---\\n\\n## 11. Grammar (EBNF)\\n\\n```text\\ndocument = header ( config-line )* node\\n\\nheader = \\\"decisiontree\\\" ( \\\":\\\" mode )? ( WS quoted-string )? NEWLINE\\nmode = \\\"decision\\\" | \\\"da\\\" | \\\"ml\\\"\\n // omitted → taxonomy\\n\\nconfig-line = config-key \\\":\\\" WS config-value NEWLINE\\nconfig-key = \\\"direction\\\" | \\\"edgeStyle\\\" | \\\"edge-style\\\"\\n | \\\"branchLabels\\\" | \\\"branch-labels\\\"\\n | \\\"branchLength\\\" | \\\"branch-length\\\"\\n | \\\"impurity\\\" | \\\"classes\\\"\\n\\n// ── Taxonomy mode ──────────────────────────────\\nnode = ( branch-prefix WS )? tax-node ( WS \\\"[\\\" tax-attrs \\\"]\\\" )? NEWLINE\\n INDENT child-node*\\ntax-node = ( \\\"question\\\" | \\\"q\\\" ) WS quoted-string\\n | ( \\\"answer\\\" | \\\"a\\\" | \\\"leaf\\\" ) WS quoted-string\\nbranch-prefix = \\\"yes:\\\" | \\\"no:\\\" | \\\"label\\\" WS quoted-string \\\":\\\"\\n\\n// ── Decision-analysis mode ─────────────────────\\nda-node = \\\"decision\\\" WS quoted-string NEWLINE INDENT da-child+\\n | \\\"chance\\\" WS quoted-string NEWLINE INDENT da-prob-child+\\n | ( \\\"end\\\" | \\\"outcome\\\" ) WS quoted-string ( WS \\\"payoff=\\\" number )? NEWLINE\\nda-child = \\\"choice\\\" WS quoted-string NEWLINE INDENT da-node\\nda-prob-child = \\\"prob\\\" WS number WS da-node // prob, value, and child all on one line\\n\\n// ── ML mode ───────────────────────────────────\\nml-node = ( \\\"true\\\" | \\\"false\\\" )? ml-kind WS quoted-string ml-prop* NEWLINE\\n INDENT ml-child*\\n // \\\"true\\\"/\\\"false\\\" and ml-kind must be on the same line\\nml-kind = \\\"split\\\" | \\\"leaf\\\"\\nml-prop = WS key \\\"=\\\" value // no spaces around \\\"=\\\"\\n\\ncomment = ( \\\"#\\\" | \\\"//\\\" ) any NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n```\\n\\nAuthoritative source: `src/diagrams/decisiontree/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"flowchart\": {\n \"title\": \"Flowchart\",\n \"content\": \"## 1. Your first flowchart\\n\\nThe smallest useful flowchart: a decision with two outcomes.\\n\\n```\\nflowchart TD\\n A([Start]) --> B{File exists?}\\n B -->|Yes| C[Read file]\\n B -->|No| D[Return error]\\n C --> E([Done])\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with `flowchart` followed by a direction: `TD`, `LR`, `BT`, or `RL`.\\n2. Each node is `ID[Label]` — the shape brackets determine the node type (see §2).\\n3. Connect nodes with `-->`. Add a label between pipe characters: `-->|Yes|`.\\n4. Nodes are created automatically when first referenced in an edge — but explicit declarations let you set shapes and labels independently.\\n\\n> Comments start with `%%` on their own line.\\n\\n---\\n\\n## 2. Node shapes\\n\\nEach node shape is written as `ID<brackets>Label<brackets>`. The ID must start with a letter and may contain letters, digits, `_`, and `-`.\\n\\n| Syntax | Shape | Typical use |\\n|---|---|---|\\n| `A[Label]` | Rectangle | Process step, operation |\\n| `A(Label)` | Rounded rectangle | Subprocess, soft step |\\n| `A([Label])` | Stadium (pill) | Start / end terminal |\\n| `A{Label}` | Diamond | Decision / condition |\\n| `A{{Label}}` | Hexagon | Preparation, configuration |\\n| `A[[Label]]` | Subroutine | Predefined process |\\n| `A[(Label)]` | Cylinder | Database, storage |\\n| `A((Label))` | Circle | Connector, junction |\\n| `A(((Label)))` | Double circle | End state |\\n| `A[/Label/]` | Parallelogram | Input / output |\\n| `A[\\\\Label\\\\]` | Parallelogram (alt) | Manual operation |\\n| `A[/Label\\\\]` | Trapezoid | Manual input |\\n| `A[\\\\Label/]` | Trapezoid (alt) | Off-page connector |\\n| `A>Label]` | Asymmetric | Tag, annotation |\\n\\n```\\nflowchart TD\\n t([Terminal / stadium])\\n r[Rectangle process]\\n d{Diamond decision}\\n p[/Parallelogram input/]\\n db[(Cylinder database)]\\n sub[[Subroutine]]\\n t --> r --> d\\n d -->|branch A| p\\n d -->|branch B| db\\n p --> sub\\n db --> sub\\n```\\n\\n---\\n\\n## 3. Edges\\n\\nAn edge connects two nodes. The connector symbol determines the visual style and whether a label or arrowhead is present.\\n\\n### 3.1 Edge types\\n\\n```\\nflowchart TD\\n A --> B\\n C --- D\\n E -.-> F\\n G ==> H\\n I <--> J\\n K --x L\\n M --o N\\n```\\n\\n| Syntax | Style | Arrow | Typical use |\\n|---|---|---|---|\\n| `A --> B` | Solid | Arrow | Normal flow |\\n| `A --- B` | Solid | None | Association, undirected link |\\n| `A -.-> B` | Dotted | Arrow | Optional / async path |\\n| `A ==> B` | Thick | Arrow | Critical / primary path |\\n| `A <--> B` | Solid | Both ends | Bidirectional flow |\\n| `A --x B` | Solid | Cross | Blocked / rejected path |\\n| `A --o B` | Solid | Circle | Aggregation / composition |\\n\\n### 3.2 Edge labels\\n\\nTwo syntaxes attach a label to an edge:\\n\\n**Pipe label** — placed between `|` characters directly after the arrow:\\n```\\nA -->|Yes| B\\nA -.->|optional| B\\nA ==>|critical| B\\n```\\n\\n**Inline label** — text placed between the dashes, before the arrow character:\\n```\\nA -- success --> B\\nA -- error --x C\\n```\\n\\nBoth produce identical results. Pipe label is more common when sharing a diagram with Mermaid tools.\\n\\n```\\nflowchart TD\\n req[Request received]\\n req -->|valid| proc[Process]\\n req -->|invalid| err[Return 400]\\n proc -- success --> ok([Done])\\n proc -.->|timeout| retry[Retry queue]\\n retry ==>|max retries| dead[(Dead letter)]\\n```\\n\\n### 3.3 Chains\\n\\nConnect three or more nodes in a single line:\\n\\n```\\nA --> B --> C --> D\\n```\\n\\nThis is equivalent to three separate edge statements.\\n\\n### 3.4 Fan-out with `&`\\n\\nUse `&` to include multiple nodes on either side of an arrow. The parser generates the full cross-product of edges:\\n\\n```\\nA & B --> C %% A→C and B→C\\nA --> B & C %% A→B and A→C\\nA & B --> C & D %% four edges: A→C, A→D, B→C, B→D\\n```\\n\\n```\\nflowchart LR\\n deploy[Deploy service]\\n smoke[Smoke test]\\n health[Health check]\\n notify_slack[Slack alert]\\n notify_email[Email alert]\\n deploy --> smoke & health\\n smoke & health -->|fail| notify_slack & notify_email\\n```\\n\\n---\\n\\n## 4. Subgraphs\\n\\nA `subgraph` groups related nodes into a labeled cluster with a visible border.\\n\\n```\\nsubgraph \\\"Title\\\"\\n A --> B\\nend\\n```\\n\\nThree subgraph header forms are accepted:\\n\\n| Form | ID | Label |\\n|---|---|---|\\n| `subgraph \\\"My Group\\\"` | auto-generated | `My Group` |\\n| `subgraph sg1 \\\"My Group\\\"` | `sg1` | `My Group` |\\n| `subgraph sg1 [My Group]` | `sg1` | `My Group` |\\n\\nSubgraphs can have their own `direction` override:\\n\\n```\\nsubgraph sg1 \\\"Frontend\\\"\\n direction LR\\n ui[React App] --> api[API Client]\\nend\\n```\\n\\n```\\nflowchart TB\\n subgraph ingestion [Ingestion]\\n raw[/Raw events/] --> parse[Parse & validate]\\n parse --> enrich[Enrich]\\n end\\n subgraph storage [Storage]\\n dw[(Data warehouse)]\\n cache[(Redis cache)]\\n end\\n enrich --> dw\\n enrich --> cache\\n dw --> report[Generate report]\\n```\\n\\n---\\n\\n## 5. Styling\\n\\n### 5.1 Semantic classes\\n\\nAssign CSS class names to nodes for theme-level visual grouping. Classes are defined with `classDef` and applied with `class`. Mermaid inline class syntax is also accepted: `A[Start]:::critical`.\\n\\n```\\nclassDef danger fill:#f9c,stroke:#c00\\nclassDef safe fill:#cfc,stroke:#090\\nclass errorNode danger\\nclass successNode safe\\nB[Review]:::danger\\n```\\n\\n### 5.2 Per-node style overrides\\n\\n```\\nstyle nodeId fill:#f9f,stroke:#333,stroke-width:4px\\n```\\n\\nAccepts standard CSS property names. Multiple properties are comma-separated.\\n\\n### 5.3 Per-edge style overrides\\n\\n`linkStyle` targets edges by their **declaration index** (0-based, in the order they appear in the source). Multiple comma-separated indices apply the same props to several edges:\\n\\n```\\nflowchart TD\\n A --> B\\n B ==> C\\n B -.-> D\\n C --> E\\n D --> E\\n linkStyle 1 stroke:#d32f2f,stroke-width:4px\\n linkStyle 2,4 stroke:#f57c00,stroke-dasharray:5 5\\n```\\n\\nUse this to highlight a critical path or distinguish an alternate flow.\\n\\n### 5.4 Inline label formatting\\n\\nNode labels accept three inline formatting tags:\\n\\n| Tag | Effect |\\n|---|---|\\n| `<br/>` or `<br>` | Line break |\\n| `<b>…</b>` | Bold |\\n| `<i>…</i>` | Italic |\\n\\n```\\nflowchart TD\\n M1[\\\"0 \\\\| 0<br/><b>START</b>\\\"]\\n M2[\\\"4 \\\\| 4<br/><b>Phase 1</b><br/><i>est. 4h</i>\\\"]\\n M1 --> M2\\n```\\n\\nTags can be nested and mixed mid-line (`Hello <b>world</b>!`). Edge labels are single-line and do not currently support these tags.\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Direction:** `flowchart TD` — first token after `flowchart` or `graph`. `TD` and `TB` are equivalent.\\n- **Title:** `flowchart LR \\\"My diagram\\\"` — optional quoted string after the direction.\\n- **Edge labels:** pipe syntax `-->|label|` or inline `-- label -->`.\\n- **Comments:** `%%` at the start of a line (after leading whitespace).\\n\\n```\\nflowchart LR\\n%% This is a comment — ignored by the parser\\nA[Step 1] --> B[Step 2] %% inline %% is NOT supported — only line-start %%\\n```\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `flowchart`, `graph` (header), `subgraph`, `end`, `direction`, `class`, `classDef`, `style`, `linkStyle`.\\n\\n**Reserved ID characters:** IDs match `[A-Za-z0-9_-]` starting with a letter. Do not use spaces or operator characters in node IDs.\\n\\n**Operator tokens to avoid inside IDs:** `-->`, `---`, `-.->`, `==>`, `<-->`, `--x`, `--o`, `|`, `&`.\\n\\n**Labels with special characters:** The label is everything inside the shape brackets. Special characters are supported inside labels as-is — brackets/braces that would be ambiguous are closed by the matching closing token.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `flowchart` with no direction | Direction defaults to `TB` | Add a direction: `flowchart TD` |\\n| `A --> B` before declaring shapes | Works — nodes created as rectangles with the ID as label | Declare explicitly when you need a non-rect shape: `A([Start])` |\\n| `A[Label with [brackets]]` | Inner `]` closes the shape early | Avoid nested brackets in labels |\\n| `subgraph My Group` (unquoted, with space) | Parser takes `My` as subgraph id, `Group` as unknown token | Quote: `subgraph \\\"My Group\\\"` |\\n| `%% comment` mid-line after code | Inline comments are not supported; `%%` must be at line start | Move comments to their own line |\\n| `A --> B --> C` mixed with `A --> B` | Chains are additive — duplicate edges may appear | Use chains OR separate lines, not both for the same pair |\\n| `direction LR` outside a subgraph | Silently ignored — `direction` override only applies inside `subgraph … end` | Set direction on the `flowchart` header line |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | subgraph-block | direction-stmt\\n | class-stmt | classdef-stmt | style-stmt\\n | linkstyle-stmt | chain-stmt)*\\n\\nheader = (\\\"flowchart\\\" | \\\"graph\\\") ( WS direction )? ( WS title )? NEWLINE\\ndirection = \\\"TD\\\" | \\\"TB\\\" | \\\"BT\\\" | \\\"LR\\\" | \\\"RL\\\"\\ntitle = '\\\"' any-char-but-quote* '\\\"' | bare-word\\n\\nsubgraph-block = \\\"subgraph\\\" ( WS subgraph-header )? NEWLINE\\n ( WS? \\\"direction\\\" WS direction NEWLINE )?\\n statement*\\n \\\"end\\\" NEWLINE\\nsubgraph-header = id WS \\\"[\\\" label \\\"]\\\"\\n | id WS quoted-string\\n | quoted-string\\n | id\\n\\nchain-stmt = node-group ( WS edge-op WS pipe-label? WS node-group )* NEWLINE\\nnode-group = node-ref ( WS \\\"&\\\" WS node-ref )*\\nnode-ref = id shape-suffix?\\nshape-suffix = \\\"[\\\" label \\\"]\\\" %% rect\\n | \\\"(\\\" label \\\")\\\" %% round\\n | \\\"([\\\" label \\\"])\\\" %% stadium\\n | \\\"{\\\" label \\\"}\\\" %% diamond\\n | \\\"{{\\\" label \\\"}}\\\" %% hexagon\\n | \\\"[[\\\" label \\\"]]\\\" %% subroutine\\n | \\\"[(\\\" label \\\")]\\\" %% cylinder\\n | \\\"((\\\" label \\\"))\\\" %% circle\\n | \\\"(((\\\" label \\\")))\\\" %% double-circle\\n | \\\"[/\\\" label \\\"/]\\\" %% parallelogram\\n | \\\"[\\\\\\\" label \\\"\\\\]\\\" %% parallelogram-alt\\n | \\\"[/\\\" label \\\"\\\\]\\\" %% trapezoid\\n | \\\"[\\\\\\\" label \\\"/]\\\" %% trapezoid-alt\\n | \\\">\\\" label \\\"]\\\" %% asymmetric\\n\\nedge-op = \\\"-->\\\" | \\\"---\\\" | \\\"-.\\\"-\\\".->\\\" | \\\"==>\\\" | \\\"<-->\\\" | \\\"--x\\\" | \\\"--o\\\"\\n | inline-label variants of the above\\npipe-label = \\\"|\\\" text \\\"|\\\"\\n\\nclass-stmt = \\\"class\\\" WS id-list WS class-name NEWLINE\\n | node-ref \\\":::\\\" class-name NEWLINE # Mermaid inline form\\nclassdef-stmt = \\\"classDef\\\" WS class-name WS css-props NEWLINE\\nstyle-stmt = \\\"style\\\" WS id WS css-props NEWLINE\\nlinkstyle-stmt = \\\"linkStyle\\\" WS index-list WS css-props NEWLINE\\nindex-list = NUMBER ( \\\",\\\" NUMBER )* | \\\"default\\\"\\n\\ncomment = \\\"%%\\\" any NEWLINE\\nid = [A-Za-z] [A-Za-z0-9_-]*\\n```\\n\\nAuthoritative source: `src/diagrams/flowchart/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"matrix\": {\n \"title\": \"Matrix / Quadrant diagram\",\n \"content\": \"## 1. Your first matrix\\n\\nThe smallest useful matrix: a custom 2×2 with two labeled axes and three points.\\n\\n```\\nmatrix \\\"Feature Prioritization\\\"\\nx-axis: Low Effort → High Effort\\ny-axis: Low Value → High Value\\n\\n\\\"Add search\\\" at (0.3, 0.8)\\n\\\"Rebuild pipeline\\\" at (0.85, 0.7)\\n\\\"Update footer\\\" at (0.2, 0.2)\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `matrix`, optionally followed by a template name or a quoted title.\\n2. Set the axes with `x-axis:` and `y-axis:` — or use a built-in template and skip this step entirely.\\n3. Each point is `\\\"Label\\\" at (x, y)` where `x` and `y` are decimal fractions from 0.0 (low/left/bottom) to 1.0 (high/right/top).\\n4. Add optional properties — `size:`, `category:`, `color:`, `shape:`, `highlight:` — after the coordinates.\\n\\n> Comments must start with `#` anywhere on a line (outside quoted strings).\\n\\n---\\n\\n## 2. Built-in templates\\n\\nA template pre-configures axes, quadrant labels, and grid size. Just use the template name as the second token on the header line.\\n\\n| Template | Grid | Use case |\\n|---|---|---|\\n| `eisenhower` | 2×2 | Urgency / Importance task prioritization |\\n| `impact-effort` | 2×2 | Feature prioritization by impact vs. effort |\\n| `rice` | 2×2 | RICE scoring — Reach × Impact vs. Effort |\\n| `bcg` | 2×2 | Portfolio — Market Share vs. Growth rate |\\n| `ansoff` | 2×2 | Product/market growth strategy |\\n| `johari` | 2×2 | Self-awareness — known-to-self vs. known-to-others |\\n| `9-box` | 3×3 | HR talent review — Performance vs. Potential |\\n| `risk-matrix` | 5×5 | Risk assessment — Likelihood vs. Severity (heatmap) |\\n\\n```\\nmatrix eisenhower \\\"This Week\\\"\\n\\\"Ship hotfix\\\" at (0.1, 0.9) size: 5 highlight: true\\n\\\"Team 1:1s\\\" at (0.1, 0.7) size: 3\\n\\\"Write Q3 OKRs\\\" at (0.8, 0.85) size: 4\\n\\\"Inbox zero\\\" at (0.1, 0.3) size: 2\\n\\\"Refactor auth\\\" at (0.75, 0.4) size: 3\\n```\\n\\nAxes and quadrant labels from a template can be overridden with explicit `x-axis:` / `y-axis:` / `quadrant` directives.\\n\\n---\\n\\n## 3. Axes\\n\\nAxis lines declare the semantic poles of each dimension.\\n\\n```\\nx-axis: Low Effort → High Effort\\ny-axis: Low Value → High Value\\n```\\n\\nThe arrow separates the low label (left / bottom) from the high label (right / top). All of these separators are equivalent:\\n\\n| Separator | Example |\\n|---|---|\\n| `→` (Unicode) | `x-axis: Rare → Certain` |\\n| `->` (ASCII) | `x-axis: Rare -> Certain` |\\n| `↑` | `y-axis: Cheap ↑ Expensive` |\\n| `←` / `<-` / `<` | Reversed axis — high label is on the left |\\n\\nA **reversed axis** is for conventions where the \\\"high\\\" value sits at the left or bottom:\\n\\n```\\nx-axis: High Market Share ← Low Market Share\\n```\\n\\n```\\nmatrix \\\"Product Portfolio\\\"\\nx-axis: High Market Share ← Low Market Share\\ny-axis: Low Growth → High Growth\\n\\nquadrant Q1 \\\"Question Marks\\\"\\nquadrant Q2 \\\"Stars\\\"\\nquadrant Q3 \\\"Cash Cows\\\"\\nquadrant Q4 \\\"Dogs\\\"\\n\\n\\\"Analytics Suite\\\" at (0.25, 0.35) size: 5\\n\\\"ChatBot Pro\\\" at (0.2, 0.8) size: 4 highlight: true\\n\\\"Legacy CRM\\\" at (0.75, 0.25) size: 6\\n\\\"Mobile App\\\" at (0.65, 0.75) size: 3\\n```\\n\\n---\\n\\n## 4. Points\\n\\nEach point is a bubble positioned by a normalized (x, y) coordinate pair.\\n\\n```\\n\\\"Label\\\" at (x, y)\\n\\\"Label\\\" at (x, y) size: 4 category: design color: #7B1FA2 highlight: true note: \\\"clarify spec\\\"\\n```\\n\\n| Property | Values | Meaning |\\n|---|---|---|\\n| `size:` | positive number | Bubble area weight (default: 3) |\\n| `category:` | bareword | Color group; drives the legend |\\n| `color:` | hex string | Override bubble color for this point |\\n| `shape:` | `circle` \\\\| `square` \\\\| `triangle` \\\\| `diamond` | Bubble shape (default: `circle`) |\\n| `highlight:` | `true` | Draws an emphasis ring around the bubble |\\n| `note:` | quoted string | Tooltip annotation |\\n| `label:` | quoted string | Replaces the display label (different from the ID) |\\n\\nCoordinates outside `[0, 1]` are clamped to the chart boundary and flagged with a badge — the original value is stored for tooltip display.\\n\\n```\\nmatrix \\\"Risk Register\\\"\\nx-axis: Low Impact → High Impact\\ny-axis: Rare → Certain\\n\\n\\\"Vendor delay\\\" at (0.45, 0.7) size: 4 category: schedule highlight: true\\n\\\"Security breach\\\" at (0.9, 0.3) size: 5 category: security shape: diamond\\n\\\"Budget overrun\\\" at (0.5, 0.65) size: 3 category: finance\\n\\\"Key hire falls through\\\" at (0.6, 0.55) size: 3 category: people\\n\\\"Scope creep\\\" at (0.4, 0.8) size: 4 category: schedule\\n```\\n\\n---\\n\\n## 5. Quadrant labels\\n\\nLabel each quadrant with a name and an optional subtitle.\\n\\n```\\nquadrant Q1 \\\"Do First\\\"\\nquadrant Q2 \\\"Schedule\\\"\\nquadrant Q3 \\\"Delete\\\"\\nquadrant Q4 \\\"Delegate\\\"\\n\\n# With an optional subtitle:\\nquadrant Q1 \\\"Do First\\\" description: \\\"High urgency, high importance\\\"\\n```\\n\\nQuadrant numbering follows the standard mathematical convention: **Q1 = top-right, Q2 = top-left, Q3 = bottom-left, Q4 = bottom-right**. The `Q` prefix is optional — `quadrant 1 \\\"Label\\\"` is equally valid.\\n\\n---\\n\\n## 6. Heatmap mode\\n\\nHeatmap mode fills N×M cells with color intensity instead of plotting bubble positions.\\n\\n```\\nmatrix heatmap 4x3 \\\"Skill Matrix\\\"\\nrows: [Strategy, Execution, Communication, Technical]\\ncols: [Junior, Mid, Senior]\\n\\ncell (0,0) level: weak\\ncell (1,0) level: medium\\ncell (2,0) level: strong\\ncell (0,1) value: 7\\ncell (1,2) label: \\\"Top 10%\\\"\\n```\\n\\n- `matrix heatmap COLxROW` — header sets the grid dimensions.\\n- `rows:` and `cols:` — comma-separated or bracket-list of axis labels.\\n- `cell (col, row)` — zero-indexed, column first, row second (row 0 = bottom).\\n- `level:` — `strong` (3), `medium` (2), or `weak` (1) — shorthand for heat intensity.\\n- `value:` — explicit numeric value (overrides `level:`).\\n- `label:` — quoted text placed inside the cell.\\n\\n```\\nmatrix heatmap 4x4 \\\"Competency Heat Map\\\"\\nrows: [Leadership, Execution, Communication, Technical]\\ncols: [Junior, Mid, Senior, Staff]\\n\\ncell (0,0) level: weak\\ncell (1,0) level: medium\\ncell (2,0) level: strong\\ncell (3,0) level: strong\\ncell (0,1) level: medium\\ncell (1,1) level: medium\\ncell (2,1) level: strong\\ncell (3,1) level: strong\\ncell (0,2) level: weak\\ncell (1,2) level: medium\\ncell (2,2) level: medium\\ncell (3,2) level: strong\\ncell (0,3) level: weak\\ncell (1,3) level: weak\\ncell (2,3) level: medium\\ncell (3,3) level: strong\\n```\\n\\n---\\n\\n## 7. Correlation mode\\n\\nCorrelation mode renders an N×M dot matrix where intensity represents the relationship strength between row and column variables.\\n\\n```\\nmatrix correlation 4x4 \\\"Product Metrics\\\"\\nrows: [DAU, Retention, Revenue, NPS]\\ncols: [DAU, Retention, Revenue, NPS]\\n\\ncell (0,0) value: 1\\ncell (1,0) value: 0.82\\ncell (2,0) value: 0.54\\ncell (3,0) value: 0.71\\n```\\n\\nThe same `cell` syntax applies. `level: strong | medium | weak` is also accepted in correlation mode.\\n\\n---\\n\\n## 8. SIPOC mode\\n\\nA **SIPOC** is the one-page scoping table that opens the *Define* phase of a Six Sigma DMAIC project. It names, in five fixed columns left to right, everyone and everything the process touches: **S**uppliers · **I**nputs · **P**rocess · **O**utputs · **C**ustomers. Before a team measures or improves anything, SIPOC pins down the boundary — \\\"where does this process start, where does it end, and who hands work in and out of it.\\\"\\n\\n```\\nmatrix sipoc \\\"Order fulfilment\\\"\\nsuppliers: \\\"Vendor\\\", \\\"Warehouse\\\"\\ninputs: \\\"PO\\\", \\\"Stock levels\\\"\\nprocess: \\\"Receive order\\\", \\\"Pick\\\", \\\"Pack\\\", \\\"Ship\\\"\\noutputs: \\\"Shipped package\\\", \\\"Invoice\\\"\\ncustomers: \\\"End customer\\\", \\\"Finance\\\"\\n```\\n\\n- Start with `matrix sipoc`, optionally followed by a quoted title.\\n- Each of the five columns is its own directive: `suppliers:`, `inputs:`, `process:`, `outputs:`, `customers:`.\\n- After the colon, list the entries as **comma-separated quoted strings**. A column may have any number of entries; the rows simply stack top-down inside that column.\\n- The `process:` column is the high-level step sequence (typically 4–7 steps) — keep it to the major stages, not a detailed flowchart.\\n\\nThe five columns always render in the canonical S-I-P-O-C order regardless of the order you declare them, so the diagram reads correctly even if an LLM emits the blocks out of sequence.\\n\\n```\\nmatrix sipoc \\\"Order fulfilment\\\"\\nsuppliers: \\\"Vendor\\\", \\\"Warehouse\\\"\\ninputs: \\\"PO\\\", \\\"Stock levels\\\"\\nprocess: \\\"Receive order\\\", \\\"Pick\\\", \\\"Pack\\\", \\\"Ship\\\"\\noutputs: \\\"Shipped package\\\", \\\"Invoice\\\"\\ncustomers: \\\"End customer\\\", \\\"Finance\\\"\\n```\\n\\n---\\n\\n## 9. QFD mode (House of Quality)\\n\\n**Quality Function Deployment (QFD)** — the *House of Quality*, introduced by Yoji Akao — translates what customers want into the engineering characteristics that deliver it. Rows are the **WHATs** (customer requirements, each with an importance weight); columns are the **HOWs** (the measurable engineering characteristics the team controls). The body of the grid records how strongly each HOW serves each WHAT.\\n\\nThe differentiator: the engine **computes** the bottom row for you. Each HOW's *technical importance* is the sum down its column of `weight × relationship strength` — a ranked answer to \\\"which engineering characteristic moves the most customer value, and is therefore worth the most effort.\\\" And the roof of the house — a half-matrix of diamond cells above the columns — records whether two HOWs help or fight each other.\\n\\n```\\nmatrix qfd \\\"Coffee maker\\\"\\nwhat: \\\"Quiet operation\\\" weight: 5\\nwhat: \\\"Brews fast\\\" weight: 3\\nwhat: \\\"Energy efficient\\\" weight: 4\\nhow: \\\"Fan RPM\\\" dir: down\\nhow: \\\"Heater watts\\\" dir: up\\nhow: \\\"Insulation\\\" dir: up\\nrel (0,0): 9\\nrel (0,2): 3\\nrel (1,1): 9\\nrel (2,1): 3\\nrel (2,2): 9\\nroof (0,1): --\\nroof (1,2): +\\n```\\n\\n### WHATs and HOWs\\n\\n| Directive | Form | Meaning |\\n|---|---|---|\\n| `what:` | `what: \\\"Label\\\" weight: N` | A customer requirement (one row). `weight:` is its importance, conventionally 1–5. Declaration order is the row order, indexed from 0. |\\n| `how:` | `how: \\\"Label\\\" dir: up\\\\|down` | An engineering characteristic (one column). Declaration order is the column order, indexed from 0. `dir:` is the optimization target — `up` = more is better, `down` = less is better. |\\n\\n### Relationship cells\\n\\n`rel (i, j): strength` records how strongly column-`j` HOW serves row-`i` WHAT. The index is **(row, column)**, both zero-based.\\n\\n| Strength | Meaning |\\n|---|---|\\n| `9` | Strong relationship |\\n| `3` | Medium relationship |\\n| `1` | Weak relationship |\\n| *(omitted)* | No relationship — leave the cell out |\\n\\nThis 9 / 3 / 1 scale is the QFD convention: it is deliberately non-linear so that one strong link outweighs several weak ones when the importance row is summed.\\n\\n### Computed technical-importance row\\n\\nThe engine sums each column to produce the technical-importance row at the foot of the house:\\n\\n```\\nimportance(j) = Σ over rows i ( weight(i) × strength(i, j) )\\n```\\n\\nFor the coffee-maker example above the row computes to **45 / 39 / 51** — Insulation (51) is the highest-leverage characteristic, Heater watts (39) the lowest. This ranking is the deliverable: it tells the team where to spend engineering effort.\\n\\nAdd `normalize: true` (its own line, anywhere in the block) to show each column as a **percentage of the total** instead of a raw sum — for this example, **33% / 29% / 38%**. Percentages make the relative priorities easier to read across very different weight scales.\\n\\n### The roof — HOW × HOW correlations\\n\\nThe **roof** is the triangular half-matrix sitting above the columns. `roof (i, j): glyph` records whether HOW `i` and HOW `j` reinforce or conflict with each other — the synergies and trade-offs a team must reconcile.\\n\\n| Glyph | Correlation |\\n|---|---|\\n| `++` | Strong positive — improving one strongly helps the other |\\n| `+` | Positive |\\n| `-` | Negative |\\n| `--` | Strong negative — improving one hurts the other (a trade-off) |\\n| *(omitted)* | No correlation — leave the cell out |\\n\\nEach roof entry renders as a diamond cell in the standard QFD pitched-roof grid. In the example, `roof (0,1): --` flags that pushing Fan RPM down while pushing Heater watts up is a trade-off, and `roof (1,2): +` flags that Heater watts and Insulation reinforce each other.\\n\\n```\\nmatrix qfd \\\"Coffee maker\\\"\\nwhat: \\\"Quiet operation\\\" weight: 5\\nwhat: \\\"Brews fast\\\" weight: 3\\nwhat: \\\"Energy efficient\\\" weight: 4\\nhow: \\\"Fan RPM\\\" dir: down\\nhow: \\\"Heater watts\\\" dir: up\\nhow: \\\"Insulation\\\" dir: up\\nrel (0,0): 9\\nrel (0,2): 3\\nrel (1,1): 9\\nrel (2,1): 3\\nrel (2,2): 9\\nroof (0,1): --\\nroof (1,2): +\\n```\\n\\n---\\n\\n## 10. Config options\\n\\nA `config:` block tunes visual rendering. Each option goes on its own indented line below the `config:` header.\\n\\n```\\nconfig:\\n quadrantBg: true\\n gridLines: true\\n axisArrows: true\\n bubbleScale: area\\n legendPosition: bottom-right\\n```\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `quadrantBg` | `true` \\\\| `false` | `true` | Colored quadrant background fills |\\n| `gridLines` | `true` \\\\| `false` | `true` | Grid lines overlay |\\n| `axisArrows` | `true` \\\\| `false` | `true` | Arrows at axis ends |\\n| `bubbleScale` | `area` \\\\| `radius` | `area` | Whether `size:` scales bubble area or radius |\\n| `quadrantAnnotations` | `true` \\\\| `false` | `true` | Show quadrant label text in corners |\\n| `legendPosition` | `bottom-right` \\\\| `right` \\\\| `bottom-center` \\\\| `none` | `bottom-right` | Category legend placement |\\n| `labelCollision` | `auto` \\\\| `offset-only` \\\\| `leader-only` \\\\| `off` | `auto` | Overlap avoidance strategy for point labels |\\n| `offChartPolicy` | `clamp-badge` \\\\| `drop` | `clamp-badge` | What to do with points outside [0,1] |\\n\\nTwo shorthand directives also work at the top level (not inside the `config:` block):\\n\\n```\\naxis: off # off | on | auto — show or hide the axis lines\\nmargins: true # true | false — show Score + Rank margins (correlation mode)\\n```\\n\\n---\\n\\n## 11. Labels & comments\\n\\n- **Title:** `matrix \\\"My Title\\\"` or `title: My Title` as a standalone line.\\n- **Point label:** the quoted string before `at (…)`.\\n- **Axis labels:** `x-axis:` and `y-axis:` directives.\\n- **Quadrant labels:** `quadrant Q1 \\\"Name\\\"` directive.\\n- **Comments:** `#` anywhere on a line, outside quoted strings.\\n\\n```\\nmatrix \\\"Prioritization\\\"\\n# This is a comment\\nx-axis: Low Cost → High Cost # inline comment after a directive\\n\\\"Fix bug\\\" at (0.1, 0.9) size: 3 # comment after a point\\n```\\n\\n---\\n\\n## 12. Table mode (`style: table`)\\n\\nThe default matrix rendering is a **scatter / bubble chart** — points float at (x, y) coordinates. For frameworks where the output is a list of items grouped by quadrant (Eisenhower, Johari, Impact-Effort, 9-box), use `style: table` to switch to a **text-in-cell layout** instead.\\n\\n```\\nmatrix eisenhower \\\"This Week\\\"\\nstyle: table\\nQ2: \\\"Ship hotfix\\\"\\nQ2: \\\"Customer demo prep\\\"\\nQ1: \\\"Write Q3 OKRs\\\"\\nQ1: \\\"Refactor auth layer\\\"\\nQ4: \\\"LinkedIn updates\\\"\\nQ3: \\\"Reorganize Slack channels\\\"\\n```\\n\\n`style: table` applies these changes automatically:\\n\\n| Effect | Detail |\\n|---|---|\\n| Axes and arrows hidden | No axis lines, labels, or arrowheads |\\n| Grid lines hidden | Only the outer border and cell dividers remain |\\n| Quadrant titles move inside cells | Each title becomes a cell header instead of a corner overlay |\\n| Items stack as a bullet list | Multiple entries for the same quadrant stack top-down |\\n\\n### `Q1` … `Q4` shorthand (2×2 only)\\n\\nFor 2×2 templates, use `Qn: \\\"item\\\"` instead of the longer `cell (col, row) label: \\\"item\\\"` form. Mapping:\\n\\n| Shorthand | Cell | Eisenhower | Johari |\\n|---|---|---|---|\\n| `Q1:` | top-right | Schedule | Blind |\\n| `Q2:` | top-left | Do First | Open / Arena |\\n| `Q3:` | bottom-left | Delete | Hidden / Façade |\\n| `Q4:` | bottom-right | Delegate | Unknown |\\n\\nRepeat a shorthand key to add multiple items to the same cell:\\n\\n```\\nQ2: \\\"Ship hotfix\\\"\\nQ2: \\\"Customer demo prep\\\"\\n```\\n\\nFor 3×3 grids (9-box), use `cell (col, row) label: \\\"…\\\"` directly — the `Q` shorthand is 2×2 only.\\n\\n### When to use table vs scatter\\n\\n| Use `style: table` for | Use scatter (default) for |\\n|---|---|\\n| Eisenhower with task lists | Eisenhower with `size:` effort weights |\\n| Johari window coaching | Impact-Effort with bubble = revenue |\\n| Backlog grouping (no numeric third dimension) | RICE / BCG portfolio (third dimension IS the bubble size) |\\n| 9-box talent review | Risk heatmap (5×5 with numeric severity) |\\n\\n```\\nmatrix eisenhower \\\"This Week\\\"\\nstyle: table\\nQ2: \\\"Ship hotfix\\\"\\nQ2: \\\"Customer demo prep\\\"\\nQ1: \\\"Write Q3 OKRs\\\"\\nQ1: \\\"Refactor auth layer\\\"\\nQ4: \\\"LinkedIn updates\\\"\\nQ3: \\\"Reorganize Slack channels\\\"\\n```\\n\\n---\\n\\n## 13. Reserved words & escaping\\n\\n**Reserved at line start:** `matrix` (header), `x-axis:`, `y-axis:`, `quadrant`, `config:`, `title:`, `rows:`, `cols:`, `grid:`, `axis:`, `margins:`, `cell`. In **SIPOC** mode: `suppliers:`, `inputs:`, `process:`, `outputs:`, `customers:`. In **QFD** mode: `what:`, `how:`, `rel`, `roof`, `normalize:`.\\n\\n**Point lines must start with a quote character** (`\\\"` or `'`). A line that does not start with a quote is not treated as a point.\\n\\n**Strings with spaces** in axis labels do not need quoting — the text after the colon (and after the arrow) is taken verbatim. In `note:` and `label:` point properties, use double quotes.\\n\\n---\\n\\n## 14. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `\\\"Fix bug\\\" at (1, 2)` | Point parsed; x=1 clamped, y=1 clamped; off-chart badge shown | Keep coordinates in [0.0, 1.0] or accept the clamp-badge |\\n| `quadrant 1 \\\"Quick Wins\\\"` (no Q prefix) | Accepted — `Q` prefix is optional | Both `quadrant 1` and `quadrant Q1` work |\\n| `config: gridLines: false` (on same line) | Only `config:` keyword recognized; `gridLines: false` silently ignored | Put options on their own indented lines below `config:` |\\n| `x-axis: \\\"Low\\\" → \\\"High\\\"` (quoted labels) | Arrow not found inside quotes — treated as plain text | Remove quotes: `x-axis: Low → High` |\\n| `matrix heatmap` without dimensions | Defaults to 2×2; rows/cols directives set actual size | Specify dimensions on the header: `matrix heatmap 4x4` |\\n| `cell (0, 0) level: Strong` (capital S) | `level` match is case-insensitive — accepted | Both `strong` and `Strong` work |\\n| `shape: oval` | Unknown shape value — silently ignored | Use `circle`, `square`, `triangle`, or `diamond` |\\n| `\\\"Fix bug\\\" at (0.1, 0.9)` on an Eisenhower with a task list | Valid scatter point — but you probably wanted a list in a cell | Add `style: table` and use `Q2: \\\"Fix bug\\\"` instead |\\n| `Q1: \\\"item\\\"` on a 3×3 template | `Q` shorthand is parsed as a point line — silently dropped | Use `cell (col, row) label: \\\"item\\\"` for 3×3 grids |\\n\\n---\\n\\n## 15. Grammar (EBNF)\\n\\n```text\\ndocument = header directive*\\n\\nheader = \\\"matrix\\\" ( template-name | mode-header | title )? NEWLINE\\ntemplate-name = \\\"eisenhower\\\"|\\\"impact-effort\\\"|\\\"rice\\\"|\\\"bcg\\\"|\\\"ansoff\\\"|\\\"johari\\\"|\\\"9-box\\\"|\\\"risk-matrix\\\"\\nmode-header = ( \\\"heatmap\\\" | \\\"correlation\\\" ) ( number \\\"x\\\" number )? title?\\n | ( \\\"sipoc\\\" | \\\"qfd\\\" ) title?\\ntitle = quoted-string | bare-text\\n\\ndirective = x-axis | y-axis | quadrant-dir | config-block\\n | point | cell | q-short | rows-dir | cols-dir | grid-dir\\n | style-dir | title-dir | axis-dir | margins-dir\\n | sipoc-col | qfd-what | qfd-how | qfd-rel | qfd-roof | normalize-dir\\n | comment | blank\\n\\n# SIPOC mode\\nsipoc-col = ( \\\"suppliers:\\\" | \\\"inputs:\\\" | \\\"process:\\\" | \\\"outputs:\\\" | \\\"customers:\\\" )\\n WS quoted-string ( \\\",\\\" quoted-string )* NEWLINE\\n\\n# QFD / House of Quality mode\\nqfd-what = \\\"what:\\\" WS quoted-string WS \\\"weight:\\\" number NEWLINE\\nqfd-how = \\\"how:\\\" WS quoted-string ( WS \\\"dir:\\\" ( \\\"up\\\" | \\\"down\\\" ) )? NEWLINE\\nqfd-rel = \\\"rel\\\" WS \\\"(\\\" number \\\",\\\" number \\\")\\\" \\\":\\\" WS ( \\\"9\\\" | \\\"3\\\" | \\\"1\\\" ) NEWLINE # (row, col)\\nqfd-roof = \\\"roof\\\" WS \\\"(\\\" number \\\",\\\" number \\\")\\\" \\\":\\\" WS ( \\\"++\\\" | \\\"+\\\" | \\\"-\\\" | \\\"--\\\" ) NEWLINE # (how, how)\\nnormalize-dir = \\\"normalize:\\\" WS \\\"true\\\" NEWLINE\\n\\nx-axis = \\\"x-axis:\\\" WS axis-spec NEWLINE\\ny-axis = \\\"y-axis:\\\" WS axis-spec NEWLINE\\naxis-spec = text arrow text | text # plain text → high label only\\narrow = \\\"→\\\" | \\\"->\\\" | \\\"↑\\\" | \\\"←\\\" | \\\"<-\\\" | \\\"<\\\" | \\\"↓\\\"\\n\\nquadrant-dir = \\\"quadrant\\\" WS \\\"Q\\\"? digit WS quoted-string ( WS \\\"description:\\\" quoted-string )? NEWLINE\\n\\nconfig-block = \\\"config:\\\" NEWLINE ( INDENT key \\\":\\\" WS value NEWLINE )*\\n\\npoint = quoted-string WS \\\"at\\\" WS \\\"(\\\" number \\\",\\\" number \\\")\\\" ( WS point-prop )* NEWLINE\\npoint-prop = \\\"size:\\\" number\\n | \\\"category:\\\" bareword\\n | \\\"color:\\\" hex-color\\n | \\\"shape:\\\" ( \\\"circle\\\"|\\\"square\\\"|\\\"triangle\\\"|\\\"diamond\\\" )\\n | \\\"highlight:\\\" \\\"true\\\"\\n | \\\"note:\\\" quoted-string\\n | \\\"label:\\\" quoted-string\\n\\ncell = \\\"cell\\\" WS \\\"(\\\" digit \\\",\\\" digit \\\")\\\" ( WS cell-prop )* NEWLINE\\ncell-prop = \\\"value:\\\" number\\n | \\\"label:\\\" quoted-string\\n | \\\"level:\\\" ( \\\"strong\\\" | \\\"medium\\\" | \\\"weak\\\" )\\n\\nstyle-dir = \\\"style:\\\" WS \\\"table\\\" NEWLINE\\nq-short = \\\"Q\\\" ( \\\"1\\\" | \\\"2\\\" | \\\"3\\\" | \\\"4\\\" ) \\\":\\\" WS quoted-string NEWLINE # 2×2 only\\n\\nrows-dir = \\\"rows:\\\" WS label-list NEWLINE\\ncols-dir = \\\"cols:\\\" WS label-list NEWLINE\\ngrid-dir = \\\"grid:\\\" WS number \\\"x\\\" number NEWLINE\\naxis-dir = \\\"axis:\\\" WS ( \\\"off\\\" | \\\"on\\\" | \\\"auto\\\" ) NEWLINE\\nmargins-dir = \\\"margins:\\\" WS ( \\\"true\\\" | \\\"false\\\" | \\\"on\\\" | \\\"1\\\" ) NEWLINE\\n\\nlabel-list = \\\"[\\\" text (\\\",\\\" text)* \\\"]\\\" | text (\\\",\\\" text)*\\nquoted-string = '\\\"' any-char-but-quote* '\\\"' | \\\"'\\\" any-char-but-quote* \\\"'\\\"\\ncomment = \\\"#\\\" any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/matrix/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"orgchart\": {\n \"title\": \"Org chart\",\n \"content\": \"## 1. Your first org chart\\n\\nThe smallest useful org chart: a three-level hierarchy with one open role.\\n\\n```\\norgchart \\\"Engineering Team\\\"\\ncto: \\\"Wei Zhang\\\" | CTO [role: cto]\\n lead: \\\"Sam Obi\\\" | Engineering Lead [role: engineer]\\n eng: \\\"Ana Rossi\\\" | Engineer [role: engineer]\\n open1: open \\\"TBH\\\" | Engineer [role: engineer]\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `orgchart`, optionally followed by a quoted title.\\n2. Each person is a **node** — `id: \\\"Name\\\" | \\\"Title\\\" | \\\"Department\\\" [props]`. The `|` separates the name, title, and department fields.\\n3. **Indentation determines hierarchy** — each extra two (or more) spaces moves a node one level deeper under the nearest less-indented node above it.\\n4. Declare open roles with `open id:` or `draft id:`, and external advisors with `advisor id:`.\\n\\n> Comments must start with `#` on their own line (inline trailing `//` is also stripped).\\n\\n---\\n\\n## 2. Nodes\\n\\nA node line has the form `[kind] id: fields [props]`. The `id` must match `[A-Za-z][A-Za-z0-9_-]*`.\\n\\n### 2.1 Fields (pipe-separated)\\n\\nThe part after the `:` and before the optional `[props]` block is split on `|`:\\n\\n```\\nalice: \\\"Alice Zhang\\\" # name only\\nalice: \\\"Alice Zhang\\\" | \\\"VP Engineering\\\" # name + title\\nalice: \\\"Alice Zhang\\\" | \\\"VP Eng\\\" | \\\"Platform\\\" # name + title + department\\nalice: \\\"Alice Zhang\\\" | \\\"VP Eng\\\" | \\\"Platform\\\" | \\\"x@co.com\\\" # + info line\\n```\\n\\n| Position | Content | Notes |\\n|---|---|---|\\n| 1st | Name | Quoted or unquoted |\\n| 2nd | Title / job level | Optional |\\n| 3rd | Department | Optional |\\n| 4th | Info line | Optional; also settable via `note:`, `email:`, `phone:`, `location:` props |\\n\\n```\\norgchart \\\"Field count demo\\\"\\nalice: \\\"Alice\\\"\\n bob: \\\"Bob\\\" | \\\"CTO\\\"\\n carol: \\\"Carol\\\" | \\\"Engineer\\\" | \\\"Engineering\\\"\\n dave: \\\"Dave\\\" | \\\"VP Sales\\\" | \\\"Sales\\\" | \\\"dave@co.com\\\"\\n```\\n\\n### 2.2 Node kinds\\n\\nThe optional **kind keyword** before the id changes how the node is rendered:\\n\\n| Keyword(s) | Kind | Meaning |\\n|---|---|---|\\n| *(none)* | `person` | Regular person |\\n| `role`, `open` | `role` | Open / unfilled position |\\n| `draft`, `tbh` | `draft` | Planned position, not actively recruiting |\\n| `advisor`, `external` | `advisor` | External advisor, board member, or contractor |\\n\\n```\\norgchart \\\"Node kinds\\\"\\nceo: \\\"Jordan Kim\\\" | CEO [role: ceo]\\n eng_lead: \\\"Priya Nair\\\" | Engineering Lead [role: engineer]\\n open eng_open: \\\"TBH\\\" | Senior Engineer [role: engineer]\\n draft eng_draft: \\\"TBH\\\" | Staff Engineer [role: engineer]\\n advisor adv1: \\\"Dr. Lee\\\" | Board Advisor [role: advisor]\\n```\\n\\n### 2.3 Node properties\\n\\nProperties go in `[key: value, …]` at the end of a node line.\\n\\n| Property | Values | Effect |\\n|---|---|---|\\n| `role:` | see table below | Role icon displayed in the avatar |\\n| `icon:` | same as `role:` | Alias for `role:` |\\n| `department:` | text | Overrides the department field |\\n| `status:` | `new` \\\\| `leaving` \\\\| `on-leave` | Status pill on the card |\\n| `avatar-color:` | hex color (e.g. `\\\"#7B1FA2\\\"`) | Avatar background color |\\n| `gender:` | `male` \\\\| `female` | Avatar silhouette (used when no role icon is set) |\\n| `note:` | text | Info line (first one wins) |\\n| `email:` | text | Info line |\\n| `phone:` | text | Info line |\\n| `location:` | text | Info line |\\n| `assistant-of:` | node id | Renders this node as an assistant to the named node |\\n| `matrix:` | space- or comma-separated node ids | Adds dotted matrix lines from those nodes to this one |\\n| `reports:` | node id | Explicit parent override (instead of indentation) |\\n| `open` | *(bare flag)* | Marks node as open; equivalent to using `role` kind keyword |\\n| `draft` or `tbh` | *(bare flag)* | Marks node as draft; equivalent to `draft` kind keyword |\\n| `external` | *(bare flag)* | Marks node as external; equivalent to `advisor` kind keyword |\\n\\n**Role icons** — the `role:` value resolves to a display icon. Accepted keywords (case-insensitive):\\n\\n| Keywords | Icon |\\n|---|---|\\n| `ceo` | CEO |\\n| `cto` | CTO |\\n| `cfo` | CFO |\\n| `coo` | COO |\\n| `cmo` | CMO |\\n| `cpo` | CPO |\\n| `vp` | VP |\\n| `engineer`, `engineering` | Engineer |\\n| `designer`, `design` | Designer |\\n| `sales` | Sales |\\n| `hr` | HR |\\n| `legal` | Legal |\\n| `ops`, `operations` | Ops |\\n| `marketing` | Marketing |\\n| `product` | Product |\\n| `data` | Data |\\n| `advisor` | Advisor |\\n| `intern` | Intern |\\n| `vacant` | Vacant |\\n\\n```\\norgchart \\\"People directory\\\"\\nceo: \\\"Jamie Torres\\\" | CEO [role: ceo, avatar-color: \\\"#1E88E5\\\"]\\n cto: \\\"Raj Patel\\\" | CTO [role: cto]\\n eng1: \\\"Priya Nair\\\" | Staff Engineer [role: engineer, status: new]\\n eng2: \\\"Jordan Lee\\\" | Senior Engineer [role: engineer]\\n cfo: \\\"Maria Santos\\\" | CFO [role: cfo]\\n fin1: \\\"Nour Ahmed\\\" | Finance Manager [role: ops, status: on-leave]\\n advisor adv1: \\\"Dr. Alan Ford\\\" | Board Advisor [role: advisor]\\n draft draft1: \\\"TBH\\\" | General Counsel [role: legal]\\n```\\n\\n---\\n\\n## 3. Hierarchy\\n\\nHierarchy is expressed by **indentation** — the most common pattern. Each node becomes a child of the nearest node above it that has a smaller indent. Tabs are treated as two spaces.\\n\\n```\\nceo: \\\"CEO\\\"\\n cto: \\\"CTO\\\" # child of ceo (indent 2)\\n eng: \\\"Engineer\\\" # child of cto (indent 4)\\n cfo: \\\"CFO\\\" # child of ceo (indent 2, same level as cto)\\n```\\n\\nAlternatively, use the `reports:` property to set a parent explicitly regardless of indentation:\\n\\n```\\norgchart \\\"Flat file\\\"\\nceo: \\\"CEO\\\"\\ncto: \\\"CTO\\\" [reports: ceo]\\neng: \\\"Engineer\\\" [reports: cto]\\n```\\n\\n```\\norgchart \\\"Series A Startup\\\"\\nceo: \\\"Lena Brandt\\\" | CEO [role: ceo]\\n cto: \\\"James Osei\\\" | CTO [role: cto]\\n be: \\\"Platform Lead\\\" | Engineering [role: engineer]\\n be1: \\\"Fatima Al-Rashid\\\" | Backend Engineer [role: engineer]\\n be2: \\\"Marco Ricci\\\" | Backend Engineer [role: engineer]\\n fe: \\\"Frontend Lead\\\" | Engineering [role: engineer]\\n fe1: \\\"Yumi Tanaka\\\" | Frontend Engineer [role: engineer, status: new]\\n open_fe: open \\\"TBH\\\" | Frontend Engineer [role: engineer]\\n cpo: \\\"Diana Russo\\\" | CPO [role: cpo]\\n pm1: \\\"Chris Obi\\\" | Product Manager [role: product]\\n cmo: \\\"Kai Nakamura\\\" | CMO [role: cmo]\\n mkt1: draft \\\"TBH\\\" | Growth Marketer [role: marketing]\\n```\\n\\n---\\n\\n## 4. Edges\\n\\nTwo kinds of edges exist. Most reporting lines come from the indentation hierarchy automatically. You can also write them explicitly — or add matrix (dotted) lines.\\n\\n| Operator | Edge kind | Meaning |\\n|---|---|---|\\n| `from -> to` | `report` | Solid reporting line |\\n| `from -.-> to` | `matrix` | Dotted matrix (indirect) reporting line |\\n\\nExplicit edges require that both node ids are already declared. A `report` edge created explicitly is not duplicated if the same relationship is already implied by indentation.\\n\\nEdge labels are supported:\\n\\n```\\npm1 -.-> design [label: \\\"product partnership\\\"]\\n```\\n\\n```\\norgchart \\\"Matrix org\\\"\\nconfig: direction = LR\\ncpo: \\\"Ellen Wu\\\" | CPO [role: cpo]\\n pm_core: \\\"Core PM\\\" | Product Manager [role: product]\\n pm_growth: \\\"Growth PM\\\" | Product Manager [role: product]\\n design: \\\"Suki Ito\\\" | Design Lead [role: designer]\\n data_lead: \\\"Ben Park\\\" | Data Lead [role: data]\\npm_core -.-> design [label: \\\"design partner\\\"]\\npm_growth -.-> design\\npm_growth -.-> data_lead\\n```\\n\\n---\\n\\n## 5. Configuration\\n\\n`config:` lines adjust layout and orientation. Each goes on its own line.\\n\\n| Config key | Values | Default | Effect |\\n|---|---|---|---|\\n| `direction` | `TD`, `LR` | `TD` | Top-down or left-right flow |\\n| `layout` | `tree`, `list`, `directory`, `compact` | `tree` | Visual layout mode |\\n\\n**Layout notes:**\\n- `tree` — standard hierarchical tree with branching connectors. Best for most org charts.\\n- `list` / `directory` / `compact` — compact indented directory view. Good for large headcount lists where tree branching becomes unwieldy.\\n\\n**Tree layout** (default) — avatar cards with branching connectors and department color-coding. Best for teams up to ~30 people.\\n\\n```\\norgchart \\\"Acme Engineering — tree\\\"\\ncto: \\\"Wei Zhang\\\" | CTO [role: cto]\\n platform: \\\"Platform Lead\\\" | Engineering [role: engineer]\\n p1: \\\"Amara Diallo\\\" | Staff Engineer [role: engineer]\\n p2: \\\"Ben Novak\\\" | Senior Engineer [role: engineer]\\n p3: draft \\\"TBH\\\" | Engineer [role: engineer]\\n growth: \\\"Growth Lead\\\" | Engineering [role: engineer, status: new]\\n g1: \\\"Fatima Al-Rashid\\\" | Senior Engineer [role: engineer]\\n g2: \\\"Marco Ricci\\\" | Engineer [role: engineer]\\n```\\n\\n**List layout** — compact directory rows with indent guides. Best for large teams where tree branching becomes unwieldy.\\n\\n```\\norgchart \\\"Engineering Directory — list\\\"\\nconfig: layout = list\\ncto: \\\"Wei Zhang\\\" | CTO [role: cto]\\n platform: \\\"Platform Team\\\"\\n p1: \\\"Amara Diallo\\\" | Staff Eng [role: engineer]\\n p2: \\\"Ben Novak\\\" | Senior Eng [role: engineer]\\n p3: draft \\\"TBH\\\" | Engineer [role: engineer]\\n growth: \\\"Growth Team\\\"\\n g1: \\\"Fatima Al-Rashid\\\" | Senior Eng [role: engineer, status: new]\\n g2: \\\"Marco Ricci\\\" | Engineer [role: engineer, status: leaving]\\n```\\n\\n---\\n\\n## 6. Labels & comments\\n\\n- **Title:** `orgchart \\\"Acme Corp\\\"` — first line only.\\n- **Name field:** first pipe-delimited field after the colon; may be quoted (`\\\"Alice Zhang\\\"`) or unquoted (`Alice`).\\n- **Title/department fields:** second and third pipe-delimited fields.\\n- **Info line:** fourth pipe-delimited field, or set via `note:`, `email:`, `phone:`, or `location:` props. First one encountered wins.\\n- **Comments:** `#` at the start of a line (after leading whitespace). Inline `//` is also stripped.\\n\\n---\\n\\n## 7. Reserved words & escaping\\n\\n**Reserved at line start:** `orgchart` (header), `config:`, `role`, `open`, `draft`, `tbh`, `advisor`, `external`.\\n\\n**Reserved operator tokens** — avoid these sequences inside ids: `->`, `-.->`\\n\\n**ID rules:** must match `[A-Za-z][A-Za-z0-9_-]*`. Names with spaces go in the quoted name field, not the id.\\n\\n**Strings with spaces** in props values (e.g. `department: \\\"Platform Eng\\\"`) must be double-quoted.\\n\\n---\\n\\n## 8. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `alice: Alice Zhang` (unquoted name with space) | Parses `Alice` as the name, `Zhang` is lost or misread | Quote the name: `alice: \\\"Alice Zhang\\\"` |\\n| `open1 open: \\\"TBH\\\"` | `open` after the id is not a kind keyword; fails id regex | Kind keyword comes first: `open open1: \\\"TBH\\\"` |\\n| `alice -> bob` before either node is declared | `OrgchartParseError: Edge references unknown node` | Declare nodes first, then write edges at the end |\\n| `config: direction = top-down` | Unknown value ignored; direction stays `TD` | Use `TD` or `LR` |\\n| `config: layout = compact` | Accepted — maps to `list` layout | Correct; `compact`, `directory`, and `list` all work |\\n| `alice [matrix: bob charlie]` | Space-separated ids in `matrix:` — both are added | Also works with commas: `matrix: \\\"bob, charlie\\\"` |\\n| Node id with a space: `fe lead` | Parser takes `fe` as the id; `lead` fails | Use underscore: `fe_lead` |\\n| Duplicate id | `OrgchartParseError: Duplicate node id` | Each node needs a unique id |\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | config | edge | node)*\\n\\nheader = \\\"orgchart\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nconfig = \\\"config\\\" WS \\\":\\\" WS key WS \\\"=\\\" WS value NEWLINE\\nkey = \\\"direction\\\" | \\\"layout\\\"\\n\\nnode = INDENT* kind? id \\\":\\\" WS fields ( \\\"[\\\" node-attrs \\\"]\\\" )? NEWLINE\\nkind = \\\"role\\\" | \\\"open\\\" | \\\"draft\\\" | \\\"tbh\\\" | \\\"advisor\\\" | \\\"external\\\" | \\\"person\\\"\\nfields = field ( \\\"|\\\" field )*\\nfield = quoted-string | unquoted-text\\nnode-attrs = node-attr (\\\",\\\" node-attr)*\\nnode-attr = \\\"role:\\\" role-keyword\\n | \\\"icon:\\\" role-keyword\\n | \\\"department:\\\" text\\n | \\\"status:\\\" ( \\\"new\\\" | \\\"leaving\\\" | \\\"on-leave\\\" )\\n | \\\"avatar-color:\\\" quoted-hex\\n | \\\"gender:\\\" ( \\\"male\\\" | \\\"female\\\" )\\n | \\\"note:\\\" text\\n | \\\"email:\\\" text\\n | \\\"phone:\\\" text\\n | \\\"location:\\\" text\\n | \\\"assistant-of:\\\" id\\n | \\\"matrix:\\\" id-list\\n | \\\"reports:\\\" id\\n | bare-flag\\n\\nbare-flag = \\\"open\\\" | \\\"draft\\\" | \\\"tbh\\\" | \\\"external\\\"\\n\\nedge = id WS edge-op WS id ( \\\"[\\\" edge-attrs \\\"]\\\" )? NEWLINE\\nedge-op = \\\"->\\\" | \\\".->\\\" // -.-> for matrix\\nedge-attrs = \\\"label:\\\" quoted-string\\n\\nid = [A-Za-z] [A-Za-z0-9_-]*\\ncomment = ( \\\"#\\\" | \\\"//\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/orgchart/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"mindmap\": {\n \"title\": \"Mind map\",\n \"content\": \"## 1. Your first mind map\\n\\nThe smallest useful mind map: a central topic with two branches, one with a sub-item.\\n\\n```\\nmindmap\\n\\n# Team retrospective\\n\\n## What went well\\n- Clear sprint goals\\n- Good test coverage\\n\\n## What to improve\\n- Slower PR reviews\\n - Add a review SLA\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with an optional `mindmap` keyword on its own line, then a blank line.\\n2. The root is the single `#` heading — exactly one is allowed.\\n3. Use `##`, `###`, and deeper headings to set branch depth. Heading level equals tree depth.\\n4. Use `-`, `*`, or `+` bullets to add sub-items under any heading. Each 2-space indent adds one more depth level.\\n\\n> Comments are not supported. Use `%%` directives (before the `#` root) for configuration only.\\n\\n---\\n\\n## 2. Headings and depth\\n\\nHeading level maps directly to tree depth. `#` is always the root (depth 0). `##` is depth 1. `###` is depth 2, and so on up to `######` (depth 5).\\n\\n```\\nmindmap\\n\\n# Root\\n## Branch A ← depth 1\\n### Sub-branch ← depth 2\\n#### Leaf ← depth 3\\n## Branch B\\n```\\n\\nHeadings can jump levels — `####` after `##` is valid and produces a node at depth 3. The tree depth is relative to the root, not to the previous heading.\\n\\n---\\n\\n## 3. Bullets\\n\\nBullets extend a heading branch with further detail. Any of `-`, `*`, or `+` is accepted as the bullet marker. Each **2 spaces** of indentation adds one level of depth relative to the enclosing heading.\\n\\n```\\n## Risks\\n- Technical complexity ← depth 2 (one level under ## Risks)\\n - Legacy integrations ← depth 3 (2 spaces indent)\\n - Auth service ← depth 4 (4 spaces indent)\\n- Team availability ← depth 2 again\\n```\\n\\n```\\nmindmap\\n\\n# Book outline\\n\\n## Chapter 1 — Introduction\\n- Why this matters\\n - Historical context\\n - Current state\\n- What you will learn\\n\\n## Chapter 2 — Core concepts\\n- Concept A\\n - Definition\\n - Examples\\n- Concept B\\n - Definition\\n - Worked example\\n - Step-by-step walkthrough\\n```\\n\\n---\\n\\n## 4. Inline formatting\\n\\nNode labels support a subset of Markdown inline formatting. The parser tokenizes labels at parse time; the renderer uses the tokens to emit styled text.\\n\\n| Syntax | Effect | Example |\\n|---|---|---|\\n| `**text**` | Bold | `**Critical path**` |\\n| `*text*` | Italic | `*optional*` |\\n| `` `code` `` | Monospace code | `` `npm install` `` |\\n| `[text](url)` | Link | `[RFC 7519](https://tools.ietf.org/html/rfc7519)` |\\n| `[ ] item` | Unchecked task | `[ ] Write tests` |\\n| `[x] item` | Checked task | `[x] Design review` |\\n\\nThe checkbox must be at the very start of the label (before any other text). Inline formatting can be nested: `**[bold link](url)**`.\\n\\n```\\nmindmap\\n\\n# Sprint 24 review\\n\\n## Completed\\n- [x] **Auth redesign** — JWT + refresh tokens\\n- [x] API rate limiting \\\\`per-user\\\\`\\n- [x] [Error budget dashboard](https://metrics.example.com)\\n\\n## In progress\\n- [ ] *Mobile push notifications*\\n - [ ] iOS APNs integration\\n - [ ] Android FCM setup\\n\\n## Blocked\\n- [ ] **Payment webhook** — waiting on Stripe team\\n - *Escalated to account manager*\\n```\\n\\n---\\n\\n## 5. Layout styles\\n\\nThe `%% style:` directive selects the layout algorithm. Place it before the `#` root heading.\\n\\n| Style | Layout | Best for |\\n|---|---|---|\\n| `map` (default) | Radial — branches spread in all directions from the center | Brainstorming, concept maps, free-form exploration |\\n| `logic-right` | Horizontal tree — all branches extend to the right | Structured outlines, hierarchies, sequential breakdowns |\\n| `futureswheel` | Concentric rings — the root at the hub, each heading level on its own ring | Foresight, consequence mapping, structured brainstorming |\\n| `driver` | Horizontal tree — aim on the left flowing right through drivers to change ideas | Improvement programs, aim → driver → action breakdowns |\\n\\n```\\n%% style: map\\n%% style: logic-right\\n%% style: futureswheel\\n%% style: driver\\n```\\n\\n**`map`** (default) — radial layout, branches spread in all directions from the center. Best for brainstorming and concept maps.\\n\\n```\\nmindmap\\n\\n# Machine learning\\n\\n## Supervised\\n### Classification\\n- Decision tree\\n- SVM\\n- Neural net\\n### Regression\\n- Linear\\n- Gradient boosting\\n\\n## Unsupervised\\n### Clustering\\n- K-means\\n- DBSCAN\\n### Reduction\\n- PCA\\n- t-SNE\\n\\n## Reinforcement\\n- Q-learning\\n- Policy gradient\\n```\\n\\n**`logic-right`** — horizontal tree, all branches extend to the right. Best for structured outlines and sequential hierarchies.\\n\\n```\\nmindmap\\n%% style: logic-right\\n\\n# Machine learning\\n\\n## Supervised\\n### Classification\\n- Decision tree\\n- SVM\\n- Neural net\\n### Regression\\n- Linear\\n- Gradient boosting\\n\\n## Unsupervised\\n### Clustering\\n- K-means\\n- DBSCAN\\n### Reduction\\n- PCA\\n- t-SNE\\n\\n## Reinforcement\\n- Q-learning\\n- Policy gradient\\n```\\n\\n**`futureswheel`** — a [Futures Wheel](https://en.wikipedia.org/wiki/Futures_wheel) (Jerome Glenn, 1971/72), the classic structured-brainstorming format for thinking through consequences. The central event or trend sits at the hub; first-order consequences land on the inner ring, second-order consequences on the next ring out, and so on. Each child stays inside the angular sector of its parent, and every ring is color-coded by order, so a reader can see at a glance how far a ripple is from the original event. Depth maps to rings: `#` is the hub, `##` is the first ring (1st-order), `###` / bullets under a heading push out to the next ring (2nd-order), and deeper levels keep stepping outward.\\n\\n```\\nmindmap\\n%% style: futureswheel\\n\\n# Remote work becomes default\\n\\n## Less commuting\\n- Lower carbon emissions\\n- Cheaper city living\\n\\n## Distributed teams\\n- Async communication norms\\n- Global hiring pools\\n\\n## Empty offices\\n- Commercial real estate slump\\n- Repurposed to housing\\n```\\n\\n**`driver`** — a [Driver Diagram](https://www.ihi.org/resources/tools/driver-diagram), the planning tool from the IHI (Institute for Healthcare Improvement) model for improvement. It reads left to right as a tidy tree: the **aim** on the far left, the **primary drivers** (the few high-leverage areas that move the aim) in the next column, then **secondary drivers** and concrete **change ideas** branching further right. Tree levels map cleanly to the structure: `#` is the aim, `##` are primary drivers, and bullets / deeper headings under each become the secondary drivers and change ideas. Use it whenever you need to show *how* a goal will actually be reached.\\n\\n```\\nmindmap\\n%% style: driver\\n\\n# Reduce 30-day readmissions\\n\\n## Reliable discharge process\\n- Teach-back at bedside\\n- Med reconciliation\\n\\n## Timely follow-up\\n- Appointment within 7 days\\n- Post-discharge phone call\\n```\\n\\n---\\n\\n## 6. Directives\\n\\nDirectives are `%%` lines placed **before** the `#` root heading. They configure the diagram globally.\\n\\n| Directive | Values | Default | Effect |\\n|---|---|---|---|\\n| `%% style: …` | `map`, `logic-right`, `futureswheel`, `driver` | `map` | Layout algorithm |\\n| `%% theme: …` | any string | (none) | Theme override passed to renderer |\\n| `%% maxLabelWidth: …` | integer 80–1000 | `240` | Max pixel width before label wraps |\\n\\n```\\nmindmap\\n%% style: logic-right\\n%% maxLabelWidth: 320\\n\\n# Wide label root\\n```\\n\\n```\\nmindmap\\n%% style: logic-right\\n%% maxLabelWidth: 200\\n\\n# Schematex features\\n\\n## DSL-first design\\n- One keyword per diagram\\n- AI-friendly syntax\\n- CJK support\\n\\n## Zero dependencies\\n- Hand-written parser\\n- No D3, no dagre\\n- ~KB-level bundle\\n\\n## Standards-compliant\\n- IEEE for logic gates\\n- IEC for circuits\\n- McGoldrick for genograms\\n```\\n\\n---\\n\\n## 7. Labels & comments\\n\\n- **Root title:** the text after `#` on the root heading line.\\n- **Branch labels:** the text after `##`, `###`, etc.\\n- **Bullet labels:** the text after the `- ` / `* ` / `+ ` marker.\\n- **Inline formatting:** `**bold**`, `*italic*`, `` `code` ``, `[text](url)`, `[ ]` / `[x]`.\\n- **Comments:** not supported in the body. Use `%%` directives before the `#` root for configuration; `%%` lines in the body are treated as directives (silently ignored if unrecognized).\\n\\n---\\n\\n## 8. Reserved words & escaping\\n\\n**Reserved at document start:** `mindmap` (optional keyword) and `%%` (directive prefix).\\n\\n**Reserved as root:** exactly one `#` heading; a second `#` heading throws a parse error.\\n\\n**Bullet markers:** `-`, `*`, `+` followed by a space. A `*` that is not followed by a space is treated as an italic marker if it appears inside label text.\\n\\n**Inline conflicts:** a label beginning with `[ ]` or `[x] ` is parsed as a checkbox, not a Markdown link. If you need a label that literally starts with `[`, write `\\\\[` — the backslash escapes the bracket.\\n\\n---\\n\\n## 9. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| Two `#` headings | `Error: multiple # center nodes not allowed` | Use exactly one `#` heading as the root |\\n| `##Branch` (no space after `##`) | Line is not recognized as a heading; silently skipped | Always put a space: `## Branch` |\\n| Bullet indented 3 spaces | Depth = `lastHeadingDepth + 1 + floor(3/2) = lastHeadingDepth + 2` — may create an unexpected level | Use multiples of 2 spaces: 0, 2, 4, 6… |\\n| `%% style: radial` | Unknown value silently ignored; layout stays `map` | Use `map`, `logic-right`, `futureswheel`, or `driver` |\\n| `mindmap` keyword mid-document | Treated as a plain text line (the keyword is only recognized on the very first line) | Place `mindmap` on line 1, before any content |\\n| `[ ]text` (no space after bracket) | Checkbox not recognized; rendered as literal `[ ]text` | `[ ] text` — space required after the closing bracket |\\n\\n---\\n\\n## 10. Grammar (EBNF)\\n\\n```text\\ndocument = (\\\"mindmap\\\" NEWLINE)? (blank | directive)* node*\\n\\ndirective = \\\"%%\\\" WS key \\\":\\\" WS value NEWLINE\\nkey = \\\"style\\\" | \\\"theme\\\" | \\\"maxlabelwidth\\\"\\n\\nnode = heading | bullet\\nheading = INDENT? \\\"#\\\"+ SPACE label NEWLINE\\nbullet = SPACE* bullet-marker SPACE label NEWLINE\\nbullet-marker = \\\"-\\\" | \\\"*\\\" | \\\"+\\\"\\n\\nlabel = inline-token*\\ninline-token = checkbox\\n | \\\"**\\\" inline-token* \\\"**\\\"\\n | \\\"*\\\" inline-token* \\\"*\\\"\\n | \\\"`\\\" code-text \\\"`\\\"\\n | \\\"[\\\" inline-token* \\\"]\\\" \\\"(\\\" url \\\")\\\"\\n | plain-text\\n\\ncheckbox = \\\"[ ]\\\" SPACE | \\\"[x]\\\" SPACE | \\\"[X]\\\" SPACE\\n\\nINDENT = WS* %% headings may have leading whitespace (ignored)\\nSPACE = \\\" \\\" | \\\"\\\\t\\\"\\n```\\n\\n**Depth rules:**\\n- Heading `#` → depth 0 (root)\\n- Heading `##` → depth 1, `###` → depth 2, etc.\\n- Bullet at `n` leading spaces → depth = `lastHeadingDepth + 1 + floor(n / 2)`\\n\\nAuthoritative source: `src/diagrams/mindmap/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"timeline\": {\n \"title\": \"Timeline diagram\",\n \"content\": \"## 1. Your first timeline\\n\\nThe smallest useful timeline: a title, two ordinary events, and a milestone.\\n\\n```\\ntimeline \\\"Product Launch\\\"\\n2024-06-01: \\\"Development complete\\\"\\n2024-08-15: \\\"Closed beta\\\"\\n2024-09-01: milestone \\\"Public launch\\\"\\n```\\n\\nFour rules cover 80% of usage:\\n\\n1. Start with the keyword `timeline`, optionally followed by a quoted title.\\n2. Each event is `DATE: \\\"Label\\\"` — a date, a colon, then a quoted label. A `milestone` keyword before the label marks the event as a milestone.\\n3. Date ranges use `DATE - DATE:` or `DATE .. DATE:` (both are equivalent).\\n4. Add `[key: value]` properties after the quoted label to set color, side placement, shape, or category.\\n\\n> Comments must start with `#` or `//` on their own line.\\n\\n---\\n\\n## 2. Events\\n\\nAn event line places a labeled marker at a point in time (or a bar across a span).\\n\\n### 2.1 Point events\\n\\n```\\n2024-09-15: \\\"Conference keynote\\\"\\n```\\n\\n### 2.2 Range events\\n\\n```\\n2024-06-01 - 2024-08-31: \\\"Q3 development sprint\\\"\\n2024-06-01 .. 2024-08-31: \\\"Q3 development sprint\\\"\\n```\\n\\nBoth separators (`-` surrounded by spaces, or `..`) are equivalent.\\n\\n### 2.3 Milestones\\n\\n```\\n2024-09-01: milestone \\\"Public launch\\\"\\n```\\n\\nThe `milestone` keyword before the quoted label switches the marker to a diamond shape.\\n\\n### 2.4 Event properties\\n\\nProperties go in `[key: value, …]` after the quoted label, before the newline.\\n\\n| Property | Values | Meaning |\\n|---|---|---|\\n| `color:` | hex string | Custom color for this marker or bar |\\n| `side:` | `above` \\\\| `below` | Force placement above or below the axis (swimlane / lollipop) |\\n| `icon:` | any text (e.g. emoji) | Icon displayed with the event |\\n| `shape:` | `circle` \\\\| `square` \\\\| `diamond` \\\\| `star` \\\\| `flag` | Point marker shape |\\n| `category:` | quoted string | Group label — drives color in gantt legend |\\n\\n```\\n2024-09-01: milestone \\\"Launch day\\\" [color: #E53935, side: above]\\n2024-07-15: \\\"Beta ships\\\" [icon: 🚀, category: \\\"product\\\"]\\n```\\n\\n```\\ntimeline \\\"Engineering Milestones\\\"\\nconfig: style = lollipop\\n\\n2024-01-08: \\\"Sprint planning complete\\\"\\n2024-02-14: milestone \\\"Design system shipped\\\" [side: above, color: #1565C0]\\n2024-03-22: \\\"Incident — 4h outage\\\" [icon: ⚠️]\\n2024-04-01 - 2024-06-30: \\\"API v2 build\\\"\\n2024-07-01: milestone \\\"API v2 GA\\\" [side: above, color: #2E7D32]\\n```\\n\\n---\\n\\n## 3. Date formats\\n\\nAll date formats can appear anywhere a date is expected — in events, eras, and ranges.\\n\\n| Format | Example | Notes |\\n|---|---|---|\\n| Full date | `2024-09-15` | Day-precision; `YYYY-MM-DD` |\\n| Year-month | `2024-09` | Month-precision |\\n| Year | `2024` | Year-precision |\\n| Quarter | `2024-Q3` | Maps to start of that quarter |\\n| BC year (negative) | `-753` | 753 BC |\\n| BC year (suffix) | `753BC` or `753BCE` | Same as `-753` |\\n| Geological | `65Ma`, `4.6Ga`, `12ka` | Million / billion / thousand years ago |\\n\\n```\\ntimeline \\\"Age of Earth\\\"\\nconfig: style = lollipop\\nconfig: scale = log\\n\\n4600Ma: \\\"Earth forms\\\"\\n540Ma: \\\"Cambrian explosion\\\"\\n252Ma: milestone \\\"Permian extinction — 96% of species lost\\\"\\n66Ma: milestone \\\"K-Pg extinction — end of non-avian dinosaurs\\\"\\n3Ma: \\\"Earliest stone tools (Lomekwi)\\\"\\n0: \\\"Present day\\\"\\n```\\n\\n---\\n\\n## 4. Eras (background spans)\\n\\nAn `era` line draws a shaded background band across the time axis. It always requires a date range.\\n\\n```\\nera 2020 - 2022: \\\"Foundation Phase\\\"\\nera 2022 .. 2025: \\\"Growth Phase\\\" [color: #E8F5E9]\\n```\\n\\nThe `[color: …]` property is optional. Overlapping eras stack into separate bands automatically.\\n\\n```\\ntimeline \\\"Company History\\\"\\nconfig: style = swimlane\\n\\nera 2019..2021: \\\"Early Stage\\\" [color: #FFF8E1]\\nera 2021..2024: \\\"Series A & B\\\" [color: #E8F5E9]\\n\\n2019-03-01: \\\"Founded\\\"\\n2019-11-15: \\\"First paying customer\\\"\\n2020-05-01: milestone \\\"Product-market fit\\\" [side: above]\\n2021-02-10: \\\"Series A — $8M\\\"\\n2022-09-01: \\\"Series B — $30M\\\"\\n2023-06-15: milestone \\\"Profitability\\\" [color: #1B5E20]\\n```\\n\\n---\\n\\n## 5. Tracks (swimlane grouping)\\n\\nA `track` block groups related events into a named swimlane. Indented event lines (2 spaces) belong to the track.\\n\\n```\\ntrack \\\"Engineering\\\":\\n 2024-01-15 - 2024-03-31: \\\"API design\\\"\\n 2024-04-01 - 2024-07-31: \\\"Implementation\\\"\\n\\ntrack \\\"Marketing\\\":\\n 2024-06-01: \\\"Campaign kick-off\\\"\\n 2024-09-01: milestone \\\"Launch campaign\\\" [color: #1B5E20]\\n```\\n\\nTracks are most useful in `gantt` style, where each track becomes its own labeled row.\\n\\n```\\ntimeline \\\"Q3 Project Plan\\\"\\nconfig: style = gantt\\n\\ntrack \\\"Backend\\\":\\n 2024-07-01 - 2024-08-15: \\\"Database migration\\\"\\n 2024-08-16 - 2024-09-30: \\\"API hardening\\\"\\n\\ntrack \\\"Frontend\\\":\\n 2024-07-01 - 2024-08-31: \\\"New design system\\\"\\n 2024-09-01 - 2024-09-30: \\\"Integration & QA\\\"\\n\\ntrack \\\"DevOps\\\":\\n 2024-07-15 - 2024-08-01: \\\"Staging environment\\\"\\n 2024-09-30: milestone \\\"Go-live\\\" [color: #2E7D32]\\n```\\n\\n---\\n\\n## 6. Notes\\n\\nA `note:` line indented under an event attaches a tooltip annotation to it.\\n\\n```\\n2024-06-01: \\\"Beta launch\\\"\\n note: \\\"First external users; NPS target 40+\\\"\\n```\\n\\nNotes work both for flat events and for events inside tracks.\\n\\n---\\n\\n## 7. Configuration\\n\\n`config:` lines tune the layout and visual style. Each is its own line in the form `config: key = value`.\\n\\n| Key | Values | Default | Effect |\\n|---|---|---|---|\\n| `style` | `swimlane` \\\\| `gantt` \\\\| `lollipop` | `swimlane` | Visual rendering mode |\\n| `orientation` | `horizontal` \\\\| `vertical` | `horizontal` | Axis direction |\\n| `scale` | `proportional` \\\\| `equidistant` \\\\| `log` | `proportional` | How time maps to screen space |\\n| `axis` | `bottom` \\\\| `center` | `bottom` | Where the time axis is drawn |\\n\\n**Style notes:**\\n- `swimlane` — events alternate above and below a horizontal axis; `side:` controls per-event placement. Eras add colored background bands. Best for roadmaps and biographies.\\n- `gantt` — each named track becomes a horizontal bar lane; milestones become pins above the bars. `gantt-project` is an alias. Best for project scheduling.\\n- `lollipop` — a center axis with labeled cards on alternating stems. Best for historical retrospectives with sparse, memorable events.\\n\\n**Swimlane** — roadmaps, product timelines, biographies. Eras add color bands; events alternate above and below.\\n\\n```\\ntimeline \\\"SaaS Platform Roadmap\\\"\\nconfig: style = swimlane\\n\\nera 2024-Q1..2024-Q2: \\\"Foundation\\\" [color: #E3F2FD]\\nera 2024-Q3..2024-Q4: \\\"Growth\\\" [color: #E8F5E9]\\n\\n2024-01-15: \\\"Kick-off & team onboarding\\\"\\n2024-02-01: milestone \\\"Architecture sign-off\\\" [side: above]\\n2024-03-01 - 2024-05-31: \\\"API v2 build\\\"\\n2024-04-10: \\\"Security audit\\\" [color: #F9A825]\\n2024-06-30: milestone \\\"Beta launch\\\" [side: above]\\n2024-07-01 - 2024-09-30: \\\"Performance & scaling\\\"\\n2024-10-15: milestone \\\"General availability\\\" [color: #2E7D32]\\n```\\n\\n**Gantt** — parallel tracks with horizontal duration bars and milestone pins. Best for project scheduling.\\n\\n```\\ntimeline \\\"Product Launch — Q4\\\"\\nconfig: style = gantt\\n\\ntrack \\\"Engineering\\\":\\n 2024-10-01 - 2024-11-15: \\\"Feature freeze & hardening\\\"\\n 2024-11-16 - 2024-11-30: \\\"Load testing\\\"\\n\\ntrack \\\"Design\\\":\\n 2024-10-01 - 2024-10-31: \\\"Final UI polish\\\"\\n 2024-11-01 - 2024-11-14: \\\"Asset delivery\\\"\\n\\ntrack \\\"Marketing\\\":\\n 2024-10-15 - 2024-11-14: \\\"Campaign prep\\\"\\n 2024-11-15 - 2024-11-30: \\\"Launch campaign\\\"\\n 2024-12-01: milestone \\\"Launch day\\\" [color: #2E7D32]\\n```\\n\\n**Lollipop** — sparse milestones on a centered axis with alternating cards. Best for historical retrospectives and brand stories.\\n\\n```\\ntimeline \\\"History of Computing\\\"\\nconfig: style = lollipop\\nconfig: scale = equidistant\\n\\n1936: \\\"Turing — On Computable Numbers\\\"\\n1945: \\\"ENIAC — first general-purpose computer\\\"\\n1969: \\\"ARPANET\\\"\\n1971: milestone \\\"Intel 4004 microprocessor\\\" [side: above]\\n1976: \\\"Apple I\\\"\\n1991: \\\"World Wide Web (Berners-Lee)\\\"\\n2007: milestone \\\"iPhone\\\" [color: #1565C0, side: above]\\n```\\n\\n---\\n\\n## 8. Labels & comments\\n\\n- **Title:** `timeline \\\"My Title\\\"` — first line only.\\n- **Event label:** quoted string after the colon: `DATE: \\\"Label\\\"`.\\n- **Milestone label:** `DATE: milestone \\\"Label\\\"`.\\n- **Era label:** `era DATE - DATE: \\\"Label\\\"`.\\n- **Track name:** `track \\\"Name\\\":`.\\n- **Note:** `note: \\\"text\\\"` indented under an event.\\n- **Comments:** `#` or `//` at the start of a line (after leading whitespace).\\n\\n---\\n\\n## 9. Reserved words & escaping\\n\\n**Reserved at line start:** `timeline` (header), `config:`, `era`, `track`, `note:`.\\n\\n**Date range separators:** ` - ` (space-hyphen-space) and `..` — avoid these sequences inside label text that appears before the colon.\\n\\n**BC years as negative integers:** `-753` is the year 753 BC. The parser distinguishes the negative sign from a range separator by checking for surrounding whitespace — ` - ` (with spaces) is a range; `-753` (no leading space after a colon) is a BC year.\\n\\n**Property blocks:** `[key: value]` must appear *after* the quoted label on the same line. The closing `]` must be present; unclosed brackets produce a parse error.\\n\\n---\\n\\n## 10. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `2024-06-01: Launch day` (unquoted label) | Line not recognized as an event — `TimelineParseError` | Quote the label: `2024-06-01: \\\"Launch day\\\"` |\\n| `2024-06 - 2024-09: \\\"Q3\\\"` (year-month range) | Parsed correctly | This works — all date formats are valid in ranges |\\n| `era 2024: \\\"Whole year\\\"` (no range) | `TimelineParseError: era requires a date range` | Use a range: `era 2024 - 2024: \\\"Whole year\\\"` |\\n| `track \\\"Backend\\\"` (no colon) | `TimelineParseError: Expected ':' after track name` | Add the colon: `track \\\"Backend\\\":` |\\n| `2024-01-01: \\\"Event\\\" [side: left]` | `side: left` silently ignored; only `above` and `below` are valid | Use `side: above` or `side: below` |\\n| `config: style = Gantt` (capital G) | `TimelineParseError: Invalid style: Gantt` | Use lowercase: `config: style = gantt` |\\n| `2024-01-01-2024-03-31: \\\"Q1\\\"` (no spaces around `-`) | Parser reads `2024-01-01-2024` as a date — fails | Use spaces: `2024-01-01 - 2024-03-31:` or `..`: `2024-01-01..2024-03-31:` |\\n| Indented event without a track | Indented lines under the timeline header that aren't inside a `track` block — parsed as flat events | Only indent events that are inside a `track \\\"Name\\\":` block |\\n\\n---\\n\\n## 11. Grammar (EBNF)\\n\\n```text\\ndocument = header ( blank | comment | config | era | track | event )*\\n\\nheader = \\\"timeline\\\" ( WS quoted-string )? NEWLINE\\nquoted-string = '\\\"' any-char-but-quote* '\\\"'\\n\\nconfig = \\\"config:\\\" WS key WS \\\"=\\\" WS value NEWLINE\\nkey = \\\"style\\\" | \\\"orientation\\\" | \\\"scale\\\" | \\\"axis\\\"\\n\\nera = \\\"era\\\" WS date-range \\\":\\\" WS quoted-string ( WS props )? NEWLINE\\ntrack = \\\"track\\\" WS quoted-string \\\":\\\" NEWLINE\\n ( INDENT≥2 event | INDENT≥2 note )*\\n\\nevent = date-spec \\\":\\\" WS event-body ( WS props )? NEWLINE\\n ( INDENT note )?\\nevent-body = ( \\\"milestone\\\" WS )? quoted-string\\ndate-spec = date ( ( \\\" - \\\" | \\\"..\\\" ) date )?\\n\\nnote = \\\"note:\\\" WS quoted-string NEWLINE\\n\\nprops = \\\"[\\\" prop-list \\\"]\\\"\\nprop-list = prop ( \\\",\\\" prop )*\\nprop = key \\\":\\\" WS value\\n | key \\\":\\\" WS quoted-string\\n\\ndate = iso-date | year-month | year | quarter | bc-year | geological\\niso-date = digit{4} \\\"-\\\" digit{2} \\\"-\\\" digit{2}\\nyear-month = digit{4} \\\"-\\\" digit{2}\\nyear = \\\"-\\\"? digit{1,5}\\nquarter = digit{4} \\\"-\\\"? \\\"Q\\\" [1-4]\\nbc-year = digit+ ( \\\"BC\\\" | \\\"BCE\\\" )\\ngeological = number ( \\\"Ma\\\" | \\\"Ga\\\" | \\\"ka\\\" )\\n\\ncomment = ( \\\"#\\\" | \\\"//\\\" ) any NEWLINE\\n```\\n\\nAuthoritative source: `src/diagrams/timeline/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"state\": {\n \"title\": \"State diagram\",\n \"content\": \"## 1. Your first state diagram\\n\\nThe smallest useful state diagram has an initial state, a final state, and one transition.\\n\\n```\\nstateDiagram-v2\\n[*] --> Running\\nRunning --> [*] : done\\n```\\n\\nThree rules cover 80% of usage:\\n\\n1. Start with `stateDiagram-v2` (Mermaid-style) or `state` (Schematex-style) header.\\n2. Use `[*]` for the implicit start node (when on the left of `-->`) or end node (when on the right).\\n3. Connect states with `-->`. Add a label after `:` — full UML form is `trigger [guard] / action`.\\n\\nThe default direction is **TB** (top-to-bottom) to match Mermaid. Override with `direction LR` on its own line, or `[direction: LR]` on the header.\\n\\n> Comments use `%%` (Mermaid), `#`, or `//`.\\n\\n---\\n\\n## 2. State declarations\\n\\nStates are auto-created when first referenced in a transition, but explicit declarations let you control the label and shape.\\n\\n```\\nstate Authenticating\\nstate \\\"Awaiting Approval\\\" as Approval\\nIdle: Waiting for input\\n```\\n\\n| Form | Effect |\\n|---|---|\\n| `Idle` | Bare ID — created as a simple state with `Idle` as both id and label |\\n| `state Idle` | Explicit declaration; same effect |\\n| `state \\\"Awaiting Approval\\\" as Approval` | Aliased — display `Awaiting Approval`, refer to it by `Approval` in transitions |\\n| `Idle: Waiting for input` | Inline label — `Idle` is the id, `Waiting for input` is the visible label |\\n\\n---\\n\\n## 3. Pseudo-states\\n\\nPseudo-states control the flow of a state machine without representing a stable resting state.\\n\\n| Mermaid | Schematex | Symbol | Purpose |\\n|---|---|---|---|\\n| `[*]` (source) | `initial id` | Filled black circle | Entry point of a region |\\n| `[*]` (target) | `final id` | Filled circle inside outer ring | Successful exit |\\n| `state X <<choice>>` | `choice X` | Diamond | Dynamic branch (guards evaluated at runtime) |\\n| `state X <<fork>>` | `fork X` | Thick black bar | One-input → N parallel outputs |\\n| `state X <<join>>` | `join X` | Thick black bar | N inputs → one output |\\n| — | `junction X` | Small filled circle | Static merge point |\\n| — | `history X` | Circle with `H` | Re-enter at last visited sub-state |\\n| — | `dhistory X` | Circle with `H*` | Deep history (recursive) |\\n| — | `terminate X` | `×` mark | Abnormal termination (no cleanup) |\\n| — | `entry_point X` / `exit_point X` | Hollow circle on composite border | Named entry / exit points |\\n\\n`[*]` is the Mermaid alias and is always direction-resolved: on the **source** side of `-->` it's an `initial`, on the **target** side it's a `final`. Each composite scope gets its own pair.\\n\\n```\\nstateDiagram-v2\\n[*] --> Idle\\nstate Decide <<choice>>\\nstate Joiner <<join>>\\nIdle --> Decide : evaluate\\nDecide --> Authorized : [role == \\\"admin\\\"]\\nDecide --> Joiner : [role == \\\"user\\\"]\\nAuthorized --> Joiner\\nJoiner --> [*]\\n```\\n\\n---\\n\\n## 4. Transitions\\n\\nThe full UML 2.5 transition label has three optional parts:\\n\\n```\\ntrigger [guard] / action\\n```\\n\\n| Field | Meaning | Example |\\n|---|---|---|\\n| `trigger` | Event that fires the transition | `submit`, `tick`, `timeout(30s)` |\\n| `[guard]` | Boolean expression evaluated at trigger time | `[count > 0]`, `[role == \\\"admin\\\"]` |\\n| `/ action` | Action(s) executed when transition is taken | `/ log(); increment()` |\\n\\nAll three are optional — an unlabeled transition is anonymous (completion transition).\\n\\n```\\nA --> B %% anonymous completion\\nA --> B : tick %% trigger only\\nA --> B : [count > 0] %% guard only\\nA --> B : / clearErrors() %% action only\\nA --> B : tick [count > 0] / log() %% all three\\nA --> B : tick, tock [enabled] / handle() %% multi-trigger\\n```\\n\\nLong labels wrap automatically when they exceed the lane width.\\n\\n---\\n\\n## 5. Composite states\\n\\nA composite state contains a nested sub-statechart. The outer state acts as a container with its own initial / final pseudo-states.\\n\\n```\\nstate Playing {\\n [*] --> Buffering\\n Buffering --> Streaming : buffer_full\\n Streaming --> Buffering : underflow\\n}\\n```\\n\\nBoth Mermaid syntax (`state X { … }`) and the Schematex form (`composite X { … }`) are accepted. Activities can be declared inside the composite block:\\n\\n```\\nstate Playing {\\n entry / startBuffer()\\n exit / stopBuffer()\\n do / decodeFrames()\\n\\n [*] --> Buffering\\n Buffering --> Streaming : buffer_full\\n Streaming --> Buffering : underflow\\n}\\n```\\n\\nThe renderer draws composites as a styled cluster with title bar + activity compartment.\\n\\n```\\nstateDiagram-v2\\n\\n[*] --> Stopped\\n\\nStopped --> Playing : play / loadSource()\\nPlaying --> Paused : pause\\nPaused --> Playing : play\\nPlaying --> Stopped : stop / releaseSource()\\n\\nstate Playing {\\n entry / startBuffer()\\n exit / stopBuffer()\\n do / decodeFrames()\\n\\n [*] --> Buffering\\n Buffering --> Streaming : buffer_full\\n Streaming --> Buffering : underflow\\n}\\n```\\n\\nCross-boundary transitions (`Outside --> Inside`) are routed automatically — the Sugiyama layout pulls the source/target through the composite border.\\n\\n---\\n\\n## 6. Concurrent regions\\n\\nInside a composite, the `--` separator (Mermaid) or `---` (Schematex) splits the body into orthogonal regions that run concurrently.\\n\\n```\\nstate Active {\\n [*] --> r1_idle\\n r1_idle --> Connected : connect\\n --\\n [*] --> r2_idle\\n r2_idle --> Working : start\\n}\\n```\\n\\nUse `fork` and `join` to spawn / synchronize across regions:\\n\\n```\\nstateDiagram-v2 [direction: LR]\\n\\n[*] --> F\\nstate F <<fork>>\\nstate J <<join>>\\nF --> A\\nF --> B\\nA --> J : done_a\\nB --> J : done_b\\nJ --> [*]\\n```\\n\\n---\\n\\n## 7. Notes\\n\\nA short annotation can be attached to either side of any state.\\n\\n```\\nnote right of Checking : Calls /api/verify synchronously.\\nnote left of Idle : Anonymous landing state\\n```\\n\\nMulti-line notes use the Mermaid `end note` block form, or the Schematex `{ … }` form:\\n\\n```\\nnote right of Authenticating\\n Stores the JWT in localStorage\\n on success.\\nend note\\n\\nnote left_of Idle {\\n Anonymous landing state.\\n Returns here on 401.\\n}\\n```\\n\\n---\\n\\n## 8. Self-transitions\\n\\nA transition `A --> A` renders as a curved arc on the right side of the node.\\n\\n```\\nIdle --> Idle : poll / refresh()\\n```\\n\\nThe label is placed beside the arc, outside the bounding box.\\n\\n---\\n\\n## 9. Layout direction\\n\\nSchematex defaults to **`TB`** (top-to-bottom), matching Mermaid. Override on the header:\\n\\n```\\nstateDiagram-v2\\ndirection LR\\n\\n[*] --> Loading\\nLoading --> Ready\\n```\\n\\nOr with the Schematex bracket-attr form:\\n\\n```\\nstate \\\"Order Lifecycle\\\" [direction: TB]\\n\\n[*] --> Pending\\nPending --> Paid\\n```\\n\\n`BT` and `RL` are accepted by the parser but normalized to `TB` and `LR` respectively (the layout engine doesn't yet flip the visual order).\\n\\n---\\n\\n## 10. Common mistakes\\n\\n| You wrote | Parser says | Fix |\\n|---|---|---|\\n| `[*] -> [*]` | Treated as both initial alias and final alias on the same line | Always have at least one named state between `[*]` aliases |\\n| `state X <<branch>>` | `branch` is not a stereotype | Use `<<choice>>` (dynamic) or `<<fork>>` / `<<join>>` |\\n| `note right of`<br/>`text` | Multi-line note must end with `end note` | Add `end note` on its own line |\\n| `composite X` (no braces) | Treated as a bare state declaration | Open the block: `composite X {` |\\n| `direction LR` inside composite | Per-region direction not yet supported | Set direction on the header line |\\n\\n---\\n\\n## 11. Grammar (EBNF)\\n\\n```text\\ndocument = header statement*\\nheader = (\\\"stateDiagram-v2\\\" | \\\"stateDiagram\\\" | \\\"state\\\")\\n ( title )? ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\nattrs = attr (\\\",\\\" attr)*\\nattr = \\\"direction:\\\" (\\\"TB\\\" | \\\"LR\\\")\\n\\nstatement = comment\\n | direction-stmt %% direction LR / TB / BT / RL\\n | state-decl\\n | alias-decl %% state \\\"Long\\\" as ID\\n | stereotype-decl %% state ID <<choice|fork|join|end>>\\n | pseudo-decl %% initial / final / choice / ... ID\\n | composite-block %% (state | composite) ID { ... }\\n | label-stmt %% ID : description\\n | transition\\n | note-stmt\\n | region-sep %% -- or ---\\n\\ntransition = (ID | \\\"[*]\\\") \\\"-->\\\" (ID | \\\"[*]\\\") ( \\\":\\\" trans-label )? NEWLINE\\ntrans-label = trigger? ( \\\"[\\\" guard \\\"]\\\" )? ( \\\"/\\\" action )?\\n\\nnote-stmt = \\\"note\\\" side ID \\\":\\\" inline-text NEWLINE\\n | \\\"note\\\" side ID NEWLINE text-line+ (\\\"end note\\\" | \\\"}\\\") NEWLINE\\nside = \\\"left of\\\" | \\\"right of\\\" | \\\"left_of\\\" | \\\"right_of\\\"\\n\\ncomment = \\\"%%\\\" any | \\\"#\\\" any | \\\"//\\\" any\\n\\nID = [A-Za-z_] [A-Za-z0-9_]*\\n```\\n\\nAuthoritative source: `src/diagrams/state/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"pid\": {\n \"title\": \"P&ID (Piping & Instrumentation Diagram)\",\n \"content\": \"## 1. Your first P&ID\\n\\nA minimal P&ID has at least one piece of equipment and one process line.\\n\\n```\\npid\\n\\nequip T-1 : tank_atm\\nequip P-1 : pump_centrifugal\\nequip V-1 : vessel_v\\n\\nline L1 from T-1.bottom to P-1.in [size: \\\"2\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\nline L2 from P-1.out to V-1.in [size: \\\"2\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\n```\\n\\nThree rules cover 80% of usage:\\n\\n1. Start the document with `pid` (optional title and `[direction: LR]` attrs).\\n2. Declare each piece of equipment: `equip : <type> [tag: \\\"label\\\"]`.\\n3. Connect them with `line from <equip>.<port> to <equip>.<port> [type: \\\"process\\\", size: \\\"4\\\\\\\"\\\"]`.\\n\\nInstrumentation is added separately with `inst : <category>` plus indented `measures` / `controls` clauses.\\n\\n> Comments use `#` at the start of a line.\\n\\n---\\n\\n## 2. Equipment\\n\\nThe `equip` statement declares process equipment. The catalog follows ISO 10628 / ISA-5.1 conventions.\\n\\n```\\nequip T-101 : tank_atm [tag: \\\"Feed Tank\\\"]\\nequip P-101 : pump_centrifugal\\nequip E-201 : hx_shell_tube [tag: \\\"Overhead Cond\\\"]\\nequip T-201 : column_tray [tag: \\\"Stripper\\\"]\\n```\\n\\n### 2.1 Equipment catalog\\n\\n| Type | Symbol | Purpose |\\n|---|---|---|\\n| `tank_atm` | Cylinder + dome top | Atmospheric storage tank |\\n| `tank_cone_roof` | Cylinder + cone roof | Cone-roof storage tank |\\n| `vessel_v` | Vertical capsule | Vertical pressure vessel |\\n| `vessel_h` | Horizontal capsule | Horizontal pressure vessel |\\n| `sphere` | Filled circle | LPG / ammonia sphere |\\n| `column_tray` | Tall capsule + horizontal tray lines | Distillation tray column |\\n| `column_packed` | Tall capsule + cross-hatch | Packed absorption column |\\n| `hx_shell_tube` | Horizontal capsule + tube bundle | Shell-and-tube heat exchanger |\\n| `hx_air_cooled` | Rectangle + fan circle | Air-cooled (fin-fan) cooler |\\n| `reboiler` | Capsule + parallel tube lines | Kettle reboiler |\\n| `condenser` | Horizontal capsule + tubes | Overhead condenser |\\n| `pump_centrifugal` | Circle + right-side triangle outlet | Centrifugal pump |\\n| `pump_pd` | Circle + internal gears | Positive-displacement pump |\\n| `compressor` | Trapezoid (narrow on right) | Centrifugal compressor |\\n| `blower` | Circle + 3-blade fan | Blower / fan |\\n| `reactor_cstr` | Vertical capsule + agitator | Stirred tank reactor (CSTR) |\\n| `reactor_pfr` | Horizontal capsule + packed bed dots | Plug-flow / fixed-bed reactor |\\n| `filter` | Rectangle + diagonal hatch | Filter |\\n| `cyclone` | Cylinder + cone bottom | Cyclone separator |\\n| `flare` | Tall stack + flame | Flare stack |\\n| `cooling_tower` | Hourglass | Induced-draft cooling tower |\\n\\n### 2.2 Valve catalog\\n\\nValves are equipment that sit on the piping line. Render in `bowtie` style with type-specific actuator decoration.\\n\\n| Type | Decoration | Purpose |\\n|---|---|---|\\n| `valve_gate` | Plain bowtie | Manual on/off (full-port) |\\n| `valve_ball` | Bowtie + filled center circle | Manual on/off (quarter-turn) |\\n| `valve_globe` | Bowtie + small top circle | Manual flow control |\\n| `valve_butterfly` | Bowtie + center vertical line | Quarter-turn throttle |\\n| `valve_check` | Bowtie + arc | Non-return check valve |\\n| `valve_control` | Bowtie + diaphragm actuator | Pneumatic control valve (paired with FIC) |\\n| `valve_psv` | Bowtie + 45° outlet + spring stack | Pressure safety relief valve |\\n\\n```\\nequip V-101 : valve_control [tag: \\\"V-101 (FC)\\\"]\\nequip V-303 : valve_psv [tag: \\\"V-303 · 150 psig\\\"]\\n```\\n\\n---\\n\\n## 3. Piping & signal lines\\n\\nThe `line` statement connects two anchor points (equipment ports or instrument tags).\\n\\n```\\nline L1 from T-101.bottom to P-101.in [size: \\\"4\\\\\\\"\\\", service: \\\"water\\\", type: \\\"process\\\"]\\nline s1 from FT-101 to FIC-101 [type: \\\"electric\\\"]\\nline s2 from FIC-101 to V-101 [type: \\\"pneumatic\\\"]\\n```\\n\\n### 3.1 Anchor syntax\\n\\nEach end of a line is either:\\n- `<equip-id>.<port>` — port name from §2.2 (`in`, `out`, `top`, `bottom`, `feed`, `shell_in`, `tube_out`, `reflux`, etc.)\\n- `<equip-id>` — port omitted; defaults to `in` (target) / `out` (source) per equipment family\\n- `<inst-tag>` — instrument bubble center (signal lines)\\n\\n### 3.2 Line types (ISA-5.1 §5)\\n\\n| `type:` | Stroke | Use |\\n|---|---|---|\\n| `process` | Solid, thick | Major process line (default) |\\n| `process_minor` | Solid, thin | Auxiliary / utility |\\n| `pneumatic` | Solid + diagonal tick marks | Air-actuator signal |\\n| `electric` | Long-dash | Electric / 4–20 mA signal |\\n| `hydraulic` | Long-dash + pause | Hydraulic actuator |\\n| `capillary` | Dotted (round caps) | Filled-system temperature |\\n| `software` | Short-dash, light | DCS / PLC internal data link |\\n| `mechanical` | Mixed dash | Mechanical linkage |\\n\\n### 3.3 Line tags\\n\\nThe standard PIP PIC001 tag format is `<size>\\\"-<service>-<sequence>-<spec>`. Pass it via the `tag:` attribute and the renderer places a small white tag rectangle at the line midpoint.\\n\\n```\\nline L1 from T-101.bottom to P-101.in [size: \\\"4\\\\\\\"\\\", service: \\\"PG\\\", tag: \\\"4\\\\\\\"-PG-101-A1B\\\"]\\n```\\n\\n---\\n\\n## 4. Instrumentation (ISA-5.1 §4)\\n\\nThe `inst` statement declares an instrument bubble. The **tag** uses the ISA letter-code convention: first letter is the *measured variable*, subsequent letters are *modifiers* and *function*.\\n\\n```\\ninst FT-101 : field_discrete %% Flow Transmitter, loop 101\\ninst FIC-101 : cr_shared %% Flow Indicating Controller (DCS)\\ninst PSHH-301: cr_plc %% Pressure Switch High-High (PLC)\\ninst LIC-201 : cr_shared\\n measures D-201\\n controls V-202\\n```\\n\\n### 4.1 Letter codes (first letter)\\n\\nMost-used: `F` flow · `L` level · `P` pressure · `T` temperature · `A` analysis · `S` speed · `H` hand · `Y` event/state. Full list in ISA-5.1 Table 1.\\n\\n### 4.2 Function modifiers\\n\\n`I` indicator · `R` recorder · `C` controller · `T` transmitter · `E` element · `V` valve · `S` switch · `A` alarm · `H`/`L` high/low. Combine into the multi-letter tag: `FIC` = Flow Indicating Controller; `PSHH` = Pressure Switch High-High.\\n\\n### 4.3 Bubble categories\\n\\nISA-5.1 distinguishes **location** (where the instrument lives) and **type** (analog vs. shared vs. computer vs. PLC). Schematex implements the four most common combinations:\\n\\n| Category | Bubble shape | Use |\\n|---|---|---|\\n| `field_discrete` | Plain circle | Field-mounted analog instrument (FT, PT) |\\n| `cr_shared` | Circle + horizontal line + inscribed hexagon | DCS-controlled HMI display |\\n| `cr_computer` | Circle + horizontal line + inscribed diamond | Computer function (FY, calculation) |\\n| `cr_plc` | Circle + horizontal line + inscribed square | PLC-driven logic |\\n\\n`field_*` variants omit the horizontal centerline; `local_*` variants use a dashed centerline; `cr_*` variants use a solid centerline indicating \\\"main control panel — front.\\\"\\n\\n### 4.4 measures / controls\\n\\nIndented under an `inst` declaration:\\n\\n| Clause | Effect |\\n|---|---|\\n| `measures <equip-id>` | Auto-routed dashed-electric signal line from the equipment to the bubble |\\n| `controls <equip-id>` | Auto-routed pneumatic signal line from the bubble to the equipment (typically a `valve_control`) |\\n\\n```\\ninst FT-101 : field_discrete\\n measures P-101\\ninst FIC-101 : cr_shared\\n controls V-101\\n```\\n\\nThese auto-signals are independent of the explicit `line` statements — they get rendered with the appropriate signal-line style based on the relation type.\\n\\n---\\n\\n## 5. Layout direction\\n\\nThe default direction is **`LR`** (left-to-right) — process feed enters on the left, product exits on the right. Override on the header:\\n\\n```\\npid \\\"Distillation Tower\\\" [direction: TB]\\n\\nequip T-201 : column_tray\\n…\\n```\\n\\nThe MVP layout places equipment in declaration order along the primary direction with Manhattan signal-line routing. **Multi-row / parallel-flow layouts and tee junctions are roadmap items** — see §9.\\n\\n---\\n\\n## 6. Worked example: Distillation column\\n\\nA real overhead-condenser loop with reboiler, reflux drum, and instrumentation:\\n\\n```\\npid \\\"Distillation T-201\\\"\\n\\nequip T-201 : column_tray [tag: \\\"T-201\\\"]\\nequip E-201 : condenser [tag: \\\"Overhead Cond\\\"]\\nequip D-201 : vessel_h [tag: \\\"Reflux Drum\\\"]\\nequip P-201 : pump_centrifugal [tag: \\\"Reflux Pump\\\"]\\nequip E-202 : reboiler [tag: \\\"Reboiler\\\"]\\n\\nline L1 from T-201.top to E-201.shell_in [size: \\\"8\\\\\\\\\\\"\\\", service: \\\"vapor\\\", type: \\\"process\\\"]\\nline L2 from E-201.shell_out to D-201.in [size: \\\"8\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\nline L3 from D-201.bottom to P-201.in [size: \\\"3\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\nline L4 from P-201.out to T-201.reflux [size: \\\"3\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\nline L5 from T-201.bottom to E-202.in [size: \\\"6\\\\\\\\\\\"\\\", type: \\\"process\\\"]\\n\\ninst PT-201 : field_discrete\\n measures T-201\\ninst LIC-201 : cr_shared\\n measures D-201\\ninst TIC-201 : cr_shared\\n measures T-201\\n```\\n\\n---\\n\\n## 7. Grammar (EBNF)\\n\\n```text\\ndocument = header statement*\\nheader = \\\"pid\\\" ( title )? ( \\\"[\\\" attrs \\\"]\\\" )? NEWLINE\\nattrs = attr (\\\",\\\" attr)*\\nattr = \\\"direction:\\\" (\\\"LR\\\" | \\\"TB\\\")\\n | \\\"units:\\\" (\\\"imperial\\\" | \\\"metric\\\")\\n\\nstatement = comment\\n | equipment-decl\\n | line-decl\\n | instrument-decl\\n\\nequipment-decl = \\\"equip\\\" ID \\\":\\\" equip-type ( \\\"[\\\" attr-list \\\"]\\\" )? NEWLINE\\nequip-type = \\\"tank_atm\\\" | \\\"tank_cone_roof\\\"\\n | \\\"vessel_v\\\" | \\\"vessel_h\\\" | \\\"sphere\\\"\\n | \\\"column_tray\\\" | \\\"column_packed\\\"\\n | \\\"hx_shell_tube\\\" | \\\"hx_air_cooled\\\" | \\\"reboiler\\\" | \\\"condenser\\\"\\n | \\\"pump_centrifugal\\\" | \\\"pump_pd\\\"\\n | \\\"compressor\\\" | \\\"blower\\\"\\n | \\\"reactor_cstr\\\" | \\\"reactor_pfr\\\"\\n | \\\"filter\\\" | \\\"cyclone\\\" | \\\"flare\\\" | \\\"cooling_tower\\\"\\n | \\\"valve_gate\\\" | \\\"valve_ball\\\" | \\\"valve_globe\\\" | \\\"valve_butterfly\\\"\\n | \\\"valve_check\\\" | \\\"valve_control\\\" | \\\"valve_psv\\\"\\n\\nline-decl = \\\"line\\\" ID \\\"from\\\" anchor \\\"to\\\" anchor ( \\\"[\\\" attr-list \\\"]\\\" )? NEWLINE\\nanchor = ID ( \\\".\\\" port )?\\nport = \\\"in\\\" | \\\"out\\\" | \\\"top\\\" | \\\"bottom\\\" | \\\"left\\\" | \\\"right\\\"\\n | \\\"feed\\\" | \\\"reflux\\\" | \\\"shell_in\\\" | \\\"shell_out\\\"\\n | \\\"tube_in\\\" | \\\"tube_out\\\" | \\\"vapor_out\\\" | \\\"liquid_out\\\"\\n | \\\"bottom_return\\\"\\n\\ninstrument-decl = \\\"inst\\\" tag \\\":\\\" inst-category ( \\\"[\\\" attr-list \\\"]\\\" )? NEWLINE\\n ( indented \\\"measures\\\" anchor NEWLINE )*\\n ( indented \\\"controls\\\" ID NEWLINE )*\\ntag = letter-code \\\"-\\\" loop-num %% e.g., \\\"FIC-101\\\"\\ninst-category = \\\"field_discrete\\\" | \\\"field_shared\\\" | \\\"field_computer\\\" | \\\"field_plc\\\"\\n | \\\"cr_discrete\\\" | \\\"cr_shared\\\" | \\\"cr_computer\\\" | \\\"cr_plc\\\"\\n | \\\"local_discrete\\\" | \\\"local_shared\\\"\\n\\nattr-list = attr (\\\",\\\" attr)*\\nattr = key \\\":\\\" value\\nkey = \\\"tag\\\" | \\\"size\\\" | \\\"service\\\" | \\\"type\\\" | \\\"set_pressure\\\"\\n | \\\"actuator\\\" | \\\"fail\\\" | \\\"trays\\\" | …\\nvalue = quoted-string | bare-word\\n\\nID = [A-Za-z] [A-Za-z0-9_-]*\\n```\\n\\nAuthoritative source: `src/diagrams/pid/parser.ts`. If this diverges from the parser, the parser wins — please open an issue.\\n\\n---\"\n },\n \"erd\": {\n \"title\": \"ERD (Entity-Relationship Diagram)\",\n \"content\": \"## 1. Your first ERD\\n\\nThe smallest useful ERD: a parent table referenced by a child via foreign key.\\n\\n```\\nerd\\ntable Customer {\\n customer_id int PK\\n email varchar UK\\n}\\ntable Order {\\n order_id int PK\\n customer_id int FK -> Customer.customer_id\\n}\\nref Order.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"places\\\"\\n```\\n\\nFour rules cover 80 % of usage:\\n\\n1. Start with `erd`. Optional headers `title:`, `direction: LR | TB`.\\n2. Each table is a block: `table Name { col type marker }`. Markers are `PK`, `FK`, `UK`, `NN` (or `*`) for NOT NULL.\\n3. Inline foreign-key target: append `FK -> Other.column` to a column. The renderer adds an `FK` pill automatically.\\n4. Connect tables with a `ref` line: `ref Source <left-card> -- <right-card> Target [: \\\"label\\\"]`. Cardinality is one of `one-mandatory`, `one-optional`, `many-mandatory`, `many-optional` (named form), `1..1` / `0..1` / `1..N` / `0..N` (Min-Max), or Mermaid glyphs (`}o--||`, etc.) as alias.\\n\\n> Comments use `//` or `#`. Block forms can be either multi-line (one column per line) or inline (`table A { id int PK; name varchar }`).\\n\\n---\\n\\n## 2. Cardinality glyphs\\n\\nCrow's foot encodes the cardinality at each end of the relationship line:\\n\\n| Glyph | Reading | Min..Max | Named token |\\n|---|---|---|---|\\n| `─┃` (perpendicular bar) | Exactly one (mandatory one) | 1..1 | `one-mandatory` |\\n| `─○` (open circle) | Zero or one (optional one) | 0..1 | `one-optional` |\\n| `─┃<` (bar + crow's foot) | One or more (mandatory many) | 1..N | `many-mandatory` |\\n| `─○<` (circle + crow's foot) | Zero or more (optional many) | 0..N | `many-optional` |\\n\\nEach end of a line is annotated independently. A typical 1:N relationship reads \\\"exactly one CUSTOMER places zero-or-more ORDERs\\\":\\n\\n```\\nref Order.customer_id many-mandatory -- one-mandatory Customer.customer_id : \\\"places\\\"\\n```\\n\\nReading right-to-left: the **right end** of the line attaches to Customer with a single bar (one-mandatory); the **left end** attaches to Order with a bar + crow's foot (many-mandatory).\\n\\n---\\n\\n## 3. Mermaid alias\\n\\nIf you already use Mermaid `erDiagram`, the same glyphs work as input:\\n\\n```\\nerd\\ntable Customer { customer_id int PK; email varchar UK }\\ntable Order { order_id int PK; customer_id int FK -> Customer.customer_id }\\ntable Product { product_id int PK; name varchar }\\n\\nref Order }o--|| Customer : \\\"places\\\"\\nref Order }o--o{ Product : \\\"contains\\\"\\n```\\n\\n| Mermaid token | Schematex meaning |\\n|---|---|\\n| `\\\\|o` left / `o\\\\|` right | 0..1 |\\n| `\\\\|\\\\|` | 1..1 |\\n| `}o` left / `o{` right | 0..N |\\n| `}\\\\|` left / `\\\\|{` right | 1..N |\\n| `--` | identifying / solid line |\\n| `..` | non-identifying / dashed line |\\n\\n---\\n\\n## 4. Identifying vs non-identifying\\n\\nUse `--` for identifying relationships (solid line) and `..` for non-identifying (dashed):\\n\\n```\\nerd\\ntable User { id int PK; email varchar }\\ntable SessionLog { id int PK; user_id int FK -> User.id; created_at timestamp }\\n\\nref SessionLog.user_id many-optional .. one-optional User.id : \\\"logs (optional FK)\\\"\\n```\\n\\nThe dashed line follows the Barker / IDEF1X non-identifying convention.\\n\\n---\\n\\n## 5. Composite primary keys (associative tables)\\n\\nAssociative (\\\"junction\\\") tables resolve M:N relationships. Mark each PK + FK column with both `PK` and `FK`:\\n\\n```\\nerd\\ntable Student { student_id int PK; name varchar }\\ntable Course { course_id int PK; title varchar }\\ntable Enrollment {\\n student_id int PK FK -> Student.student_id\\n course_id int PK FK -> Course.course_id\\n grade char\\n}\\nref Enrollment.student_id many-mandatory -- one-mandatory Student.student_id\\nref Enrollment.course_id many-mandatory -- one-mandatory Course.course_id\\n```\\n\\nSchematex renders both pills (PK + FK) on the same row. The PK underline applies to the column name when any `PK` marker is present.\\n\\n---\\n\\n## 6. Layout direction\\n\\n`direction: LR` (default) places parent tables left, child tables right. `direction: TB` flips to top-to-bottom — useful for narrow embeds:\\n\\n```\\nerd\\ntitle: \\\"Library (top-down)\\\"\\ndirection: TB\\n\\ntable Member { id int PK; name varchar; email varchar UK }\\ntable Book { id int PK; title varchar; author varchar }\\ntable Loan { id int PK; member_id int FK -> Member.id; book_id int FK -> Book.id; due_date date }\\n\\nref Loan.member_id many-mandatory -- one-mandatory Member.id : \\\"borrowed by\\\"\\nref Loan.book_id many-mandatory -- one-mandatory Book.id : \\\"of\\\"\\n```\\n\\nLayered orthogonal Manhattan routing with single-bend edges. v0.1 uses appearance-order stacking inside layers; barycenter crossing-reduction is deferred to v0.2.\\n\\n---\\n\\n## 7. Notation modes\\n\\nThe DSL header can pin the notation:\\n\\n```\\nerd\\nnotation: crowsfoot // default — only mode supported in v0.1\\n```\\n\\n`notation: chen` (rectangle-diamond-oval, weak entities, ternary, ISA) and `notation: barker` (per-half dashed) are documented in `27-ERD-STANDARD.md` but rejected by the parser today. Targets v0.2.\\n\\n---\\n\\n## 8. Limitations of v0.1\\n\\n- **Crow's foot only.** Chen and Barker rendering deferred.\\n- **No edge-crossing minimization.** Layered placement uses declaration order within layers; large ERDs (10+ tables, dense FKs) will show some crossings. Reorder `table` blocks if a specific layout matters.\\n- **No self-referential C-loops.** Recursive relationships (`Employee.manager_id -> Employee.id`) parse but route as straight orthogonal lines, not the canonical C-shape.\\n- **No M:N auto-resolution.** Express the associative entity explicitly (this is the standard practice in production schemas anyway).\\n\\nFor the full standard reference, see `docs/reference/27-ERD-STANDARD.md`.\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"breadboard\": {\n \"title\": \"Breadboard / Physical Wiring\",\n \"content\": \"## 1. Your first breadboard\\n\\nThree sections: a one-line `breadboard` header, a `parts` block, and a `wires` block. Optional `board:` and `title:` lines come right after the header.\\n\\n```\\nbreadboard\\nparts\\n uno: mcu uno @beside-left\\n r1: resistor 220 @5e..9e\\n d1: led red @10e..10f\\n\\nwires\\n uno:5V --red-- @+t1\\n uno:GND --black-- @-t1\\n uno:D13 --yellow-- @5a\\n @10j --black-- @-t1\\n```\\n\\nEvery part is `id: kind [args] @placement`. Every wire is `<endpoint> --color-- <endpoint>`. That's the whole grammar.\\n\\n---\\n\\n## 2. Coordinates\\n\\nBreadboards have a 2D address grid. Schematex coordinates always start with `@`.\\n\\n| Form | Meaning | Example |\\n|---|---|---|\\n| `@<col><row>` | Main grid hole. Rows `a–e` (top half), `f–j` (bottom half). | `@5e`, `@12g` |\\n| `@+t<col>` | Top **positive** rail (red stripe). | `@+t8` |\\n| `@-t<col>` | Top **negative / GND** rail (blue stripe). | `@-t8` |\\n| `@+b<col>` | Bottom positive rail. | `@+b14` |\\n| `@-b<col>` | Bottom negative rail. | `@-b14` |\\n| `@<a>..<b>` | Span — used in part placement (resistor, diode, LED). | `@5e..9e` |\\n| `@beside-left` | Off-board placement for MCU boards. | `mcu uno @beside-left` |\\n\\nMini boards (`board: mini`) have **no power rails** — `@+t…` / `@-b…` are rejected by the parser.\\n\\n---\\n\\n## 3. Board sizes\\n\\n```\\nbreadboard\\nboard: half // default — 30 columns, 400 tie-points, rails (continuous)\\n```\\n\\n| Form | Tie points | Columns | Power rails |\\n|---|---|---|---|\\n| `mini` | 170 | 17 | none |\\n| `half` (default) | 400 | 30 | continuous |\\n| `full` | 830 | 63 | break at column 30/31 |\\n\\n> **Pitfall** — on full-size boards the rails break at the middle. If your circuit uses both halves you must jumper the rails together explicitly.\\n\\n---\\n\\n## 4. Parts catalog\\n\\nEach part is `id: <kind> [args] @<placement>`. The catalog covers the most common Arduino / ESP32 maker components:\\n\\n**Discrete components** (sit on the breadboard):\\n\\n| DSL | Args | Example |\\n|---|---|---|\\n| `resistor` | `value` (Ω; supports `k`/`M`) | `r1: resistor 220 @5e..9e` |\\n| `led` | `color` (red/green/blue/yellow/white/orange) | `d1: led red @10e..10f` |\\n| `cap-elec` | — | `c1: cap-elec @4e..4f` |\\n| `cap-ceramic` | — | `c2: cap-ceramic @6e..6f` |\\n| `diode` | — | `d2: diode @5e..8e` |\\n| `button` | — | `btn: button @8e` |\\n| `dip` | `pins=N` | `ic: dip pins=8 @4e` |\\n| `header` | `pins=N` | `h1: header pins=4 @20a` |\\n\\n**Microcontroller boards** (placed beside / above / below the substrate):\\n\\n| DSL | Pin labels |\\n|---|---|\\n| `mcu uno` | `5V`, `3V3`, `GND`, `VIN`, `RST`, `D2…D13`, `A0…A5`, `RX`, `TX` |\\n| `mcu nano` | Subset of Uno labels |\\n| `mcu esp32` | `3V3`, `GND`, `VIN`, `GPIO2`, `GPIO4`, `GPIO5`, `GPIO12…GPIO33` |\\n| `mcu pico` | Same generic GPIO labels |\\n\\n**Sensors / displays / actuators** (modules sit on the breadboard with pin row anchored at the supplied coordinate):\\n\\n| DSL | Pins |\\n|---|---|\\n| `sensor hcsr04` | `VCC`, `TRIG`, `ECHO`, `GND` |\\n| `sensor dht11` / `sensor dht22` | `VCC`, `DATA`, `GND` |\\n| `display oled-ssd1306` | `GND`, `VCC`, `SCL`, `SDA` |\\n| `display lcd-1602-i2c` | `GND`, `VCC`, `SDA`, `SCL` |\\n| `module rotary-ky040` | `CLK`, `DT`, `SW`, `VCC`, `GND` |\\n| `actuator servo-sg90` | `GND`, `VCC`, `SIG` |\\n\\nResistor color bands are decorated automatically from `value` — `220` → red-red-brown-gold, `10000` → brown-black-orange-gold.\\n\\n---\\n\\n## 5. Wires\\n\\nEvery wire connects two endpoints. An endpoint is either a **part pin** (`partId:pinName`) or a **breadboard coordinate** (`@…`).\\n\\n```\\nwires\\n uno:5V --red-- @+t1\\n uno:GND --black-- @-t1\\n uno:D9 --yellow-- @9c\\n @9a --green-- @+t9\\n```\\n\\n| Color | Conventional role |\\n|---|---|\\n| `red` | +V (5V, 3.3V, VCC) |\\n| `black` / `blue` | GND |\\n| `yellow` / `orange` / `green` / `white` / `purple` | Signal |\\n| `brown` / `grey` | Arbitrary signal |\\n\\nColor is purely visual — the engine does not validate it against electrical role.\\n\\nFor visually crowded boards, `via @<coord>` lets you pin an intermediate hole that biases the Bézier control points:\\n\\n```\\nwires\\n uno:D13 --yellow-- @9a via @8c\\n```\\n\\nMost wires don't need `via` — the layout engine produces a natural arc on its own.\\n\\n---\\n\\n## 6. Sensor with pull-up resistor (DHT11 motif)\\n\\nThe iconic Arduino tutorial pattern: a 10 kΩ pull-up between VCC and the sensor's data line.\\n\\n```\\nbreadboard\\nboard: half\\ntitle: \\\"DHT11 + 10kΩ pull-up\\\"\\n\\nparts\\n uno: mcu uno @beside-left\\n s1: sensor dht11 @6a\\n r1: resistor 10000 @8e..14e\\n\\nwires\\n s1:VCC --red-- @+t1\\n s1:GND --black-- @-t1\\n s1:DATA --yellow-- @8e\\n @14e --red-- @+t14\\n uno:5V --red-- @+t1\\n uno:GND --black-- @-t1\\n uno:D2 --yellow-- @8a\\n```\\n\\n---\\n\\n## 7. ESP32 + I²C OLED\\n\\nESP32 runs at 3.3 V (not 5 V). I²C convention: green = SDA, white = SCL.\\n\\n```\\nbreadboard\\nboard: half\\ntitle: \\\"ESP32 + SSD1306 OLED I²C\\\"\\n\\nparts\\n esp: mcu esp32 @beside-left\\n oled: display oled-ssd1306 @8a\\n\\nwires\\n oled:GND --black-- @-t1\\n oled:VCC --red-- @+t1\\n oled:SCL --white-- @10c\\n oled:SDA --green-- @11c\\n esp:3V3 --red-- @+t1\\n esp:GND --black-- @-t1\\n esp:GPIO22 --white-- @10c\\n esp:GPIO21 --green-- @11c\\n```\\n\\n---\\n\\n## 8. Limitations of v0.1\\n\\n- **No leader-line callouts** — reference designators (R1, C2) are drawn near the part body. Off-board callout boxes are deferred.\\n- **No `.fzz` import** — Schematex consumes only its own DSL; Fritzing files are not parsed.\\n- **No simulation** — this is a renderer, not a Wokwi-style simulator. Component-value validation (Ohm's law, current limits) is out of scope.\\n- **No PCB / schematic round-trip** — `breadboard` and `circuit` are independent engines. Authoring two views of the same prototype currently means writing two DSLs.\\n- **Fixed parts catalog** — user-defined part types are deferred. v0.1 ships the maker-tutorial 80% catalog (resistors, LEDs, caps, DIPs, headers, four MCU families, six sensor / display / actuator modules).\\n- **Power-rail break visual** — full-size boards mark the 30/31 break with a hole-wide gap; the rail stripes still draw through the gap (cosmetic).\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"bpmn\": {\n \"title\": \"BPMN / Business Process\",\n \"content\": \"## 1. Your first BPMN diagram\\n\\nThree sections: a one-line `bpmn` header, one or more `pool { … }` blocks, and a `flows` block. Inside each pool you put `lane { … }` blocks, and inside each lane you list flow objects as `id: kind \\\"label\\\"`.\\n\\n```\\nbpmn\\npool \\\"Service\\\" {\\n lane \\\"Worker\\\" {\\n A: start \\\"Request\\\"\\n B: task service \\\"Process\\\"\\n F: end \\\"Done\\\"\\n }\\n}\\n\\nflows\\nA --> B\\nB --> F\\n```\\n\\nEvery flow object starts with an **id**, a colon, the **kind**, an optional sub-keyword (trigger / marker / gateway type), and a quoted **label**. Ids are referenced by flow lines.\\n\\n---\\n\\n## 2. Pools and lanes\\n\\nA **pool** represents one participant — an organisation, a department, or a system. A **lane** subdivides a pool into roles. The pool label is rendered rotated 90° on the left edge of a horizontal pool.\\n\\n```\\npool \\\"Customer\\\" blackbox // black-box pool — no internal flow\\npool \\\"Bank\\\" {\\n lane \\\"Clerk\\\" { … }\\n lane \\\"Underwriter\\\" { … }\\n}\\n```\\n\\nA **black-box pool** is a participant whose internal process you don't model — typically an external customer or partner. Black-box pools must contain zero flow objects (Schematex enforces this in the parser).\\n\\nSequence flow (`-->`) is **not allowed** to cross pool boundaries. Use a message flow (`~~>`) for cross-pool communication.\\n\\n---\\n\\n## 3. Events\\n\\nEvents are circles. Stroke weight encodes lifecycle role:\\n\\n| Kind | Stroke | DSL |\\n|---|---|---|\\n| Start | thin (1px) | `start` |\\n| Intermediate | thin double ring | `intermediate` |\\n| End | thick (3px) | `end` |\\n\\nThe optional **trigger** keyword adds an inner glyph. v0.1 supports the three most common triggers — `none` (no glyph), `message` (envelope), and `timer` (clock face):\\n\\n```\\nA: start // none-trigger\\nA: start message \\\"Inbound\\\" // message-catch (unfilled envelope)\\nT: intermediate timer \\\"60 min\\\" // timer (clock face)\\nF: end \\\"Done\\\"\\n```\\n\\nFilled glyph = **throw**, unfilled glyph = **catch**. Schematex picks the right fill automatically based on event kind.\\n\\n---\\n\\n## 4. Activities — tasks and subprocesses\\n\\nActivities are rounded rectangles. The two v0.1 forms are `task` and a **collapsed** subprocess (the `+` marker indicates expandable detail):\\n\\n```\\nB: task \\\"Generic abstract task\\\"\\nU: task user \\\"User decides\\\"\\nS: task service \\\"API call\\\"\\nSE: task send \\\"Send email\\\"\\nRE: task receive \\\"Wait for reply\\\"\\nM: task manual \\\"Hand-stamp the form\\\"\\nSC: task script \\\"Run rule engine\\\"\\n\\nX: subprocess \\\"Verify identity\\\" collapsed\\n```\\n\\nThe **task marker** (small icon top-left) communicates *who or what* performs the work — a person (`user`), a software service (`service`), an outbound message (`send`), an inbound wait (`receive`), an out-of-system manual step (`manual`), or an automated script (`script`). When in doubt, omit the marker — it defaults to abstract.\\n\\n---\\n\\n## 5. Gateways\\n\\nGateways are diamonds. The inner glyph encodes branching semantics:\\n\\n| Kind | Glyph | Meaning | DSL |\\n|---|---|---|---|\\n| Exclusive (XOR) | **X** | Take exactly one outgoing branch (data-based) | `gateway xor` |\\n| Inclusive (OR) | **O** | Take one or more outgoing branches | `gateway or` |\\n| Parallel (AND) | **+** | Take all outgoing branches concurrently | `gateway and` |\\n| Event-based | pentagon-in-circle | Pick the branch whose event fires first | `gateway event` |\\n\\nSchematex uses Bruce Silver's **X glyph** for XOR by default — that's the convention real BPMN audits expect. Most diagrams use XOR (data branch) and AND (parallel split / join); OR is rare and event-based mostly appears in race-condition models.\\n\\n---\\n\\n## 6. Connectors\\n\\nFour connector types. Three of them stay inside a pool; only message flow is allowed to cross pool boundaries.\\n\\n```\\nA --> B // sequence flow (default)\\nG --? \\\"yes\\\" --> C // conditional sequence (label is a guard)\\nG --* \\\"default\\\" --> D // default flow (one per gateway, max)\\n\\\"Customer\\\" ~~> A : \\\"Submit application\\\" // message flow\\nE ~~> \\\"Customer\\\" : \\\"Notify approval\\\" // message flow back\\n```\\n\\n- `-->` is the workhorse — solid line + filled triangle arrowhead.\\n- `--? \\\"label\\\" -->` adds a small unfilled diamond at the source. Use it when leaving an activity *directly* on a guarded outcome. (At a gateway, the conditional label suffices; the diamond glyph isn't drawn.)\\n- `--* \\\"label\\\" -->` adds a slash mark at the source. **One default flow maximum per gateway** — Schematex enforces this.\\n- `~~>` is dashed with an open arrowhead and a small unfilled circle at the source. Source or target may be a quoted **pool name** (for black-box participants) or an object id.\\n\\n---\\n\\n## 7. Validation\\n\\nThe parser refuses diagrams that violate BPMN semantics, with line-numbered errors:\\n\\n| Rule | Error |\\n|---|---|\\n| Sequence flow crosses pool | `sequence flow 'A --> B' crosses pool boundary — use message flow (~~>)` |\\n| Message flow inside one pool | `message flow 'A ~~> B' must cross pool boundaries` |\\n| Black-box pool has internals | `black-box pool \\\"X\\\" cannot contain lanes` |\\n| Two default flows from same gateway | `gateway 'G' has 2 default flows (max 1)` |\\n| Duplicate id within a pool | `duplicate id 'A'` |\\n| Unknown source / target | `unknown source 'X' in sequence flow` |\\n\\nThese checks fire during parse, so an LLM gets a usable signal before the layout pass.\\n\\n---\\n\\n## 8. Larger example — pizza order with black-box customer\\n\\nA canonical BPMN tutorial: an external customer (whose process we don't model) places an order with a pizzeria split into Clerk / Chef / Delivery lanes, with a rework loop on the chef's quality check.\\n\\n```\\nbpmn\\ndirection: LR\\ntitle: \\\"Pizza order\\\"\\n\\npool \\\"Customer\\\" blackbox\\n\\npool \\\"Pizzeria\\\" {\\n lane \\\"Clerk\\\" {\\n A: start message \\\"Order received\\\"\\n B: task user \\\"Take order\\\"\\n }\\n lane \\\"Chef\\\" {\\n C: task manual \\\"Make pizza\\\"\\n G1: gateway xor \\\"Pizza ok?\\\"\\n D: task manual \\\"Rework\\\"\\n }\\n lane \\\"Delivery\\\" {\\n E: task send \\\"Deliver\\\"\\n F: end \\\"Done\\\"\\n }\\n}\\n\\nflows\\nA --> B\\nB --> C\\nC --> G1\\nG1 --? \\\"yes\\\" --> E\\nG1 --* \\\"no\\\" --> D\\nD --> C\\nE --> F\\n\\\"Customer\\\" ~~> A : \\\"Place order\\\"\\nE ~~> \\\"Customer\\\" : \\\"Pizza delivered\\\"\\n```\\n\\nThe rework loop (`D --> C`) creates a back-edge that the layout's cycle-break detects via DFS — the longest-path layering then proceeds on the forward DAG so columns stay sensible.\\n\\n---\\n\\n## 9. Limitations of v0.1\\n\\nThese are deferred to a later release. If your diagram needs one, file an issue with the use case:\\n\\n- **Boundary events** — events attached to an activity edge (timer, error, escalation, compensation). Currently you have to model the boundary as a free-floating intermediate event with manual flows.\\n- **Expanded subprocesses** — collapsed `subprocess` works; expanded inline blocks (`subprocess \\\"X\\\" { … }`) are deferred.\\n- **Rare event triggers** — error / escalation / cancel / compensation / signal / link / conditional / multiple / parallel-multiple. Use `none` or `message` as a placeholder.\\n- **Transaction / call activities** — render as normal tasks for v0.1.\\n- **Loop and multi-instance markers** — bottom-center activity glyphs; deferred.\\n- **Artifacts** — data object / data store / group / text annotation. Deferred.\\n- **BPMN 2.0 XML import / export** — out of scope. Schematex computes layout from DSL; no DI layer to round-trip.\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"fbd\": {\n \"title\": \"Function Block Diagram (FBD)\",\n \"content\": \"## 1. Your first FBD network\\n\\nThe smallest useful FBD network: one block, two inputs, one output.\\n\\n```\\nfbd\\nnetwork 0:\\n Out = AND(A, B)\\n```\\n\\n`A` and `B` are auto-declared as BOOL inputs (left-side terminals), and `Out` is auto-wired to the AND block's `OUT` port (right-side terminal). The block sits between them with port stubs and labels.\\n\\n---\\n\\n## 2. Variables\\n\\nDeclare variables before any networks. Each variable has a name, an IEC data type, and an optional initial value.\\n\\n```\\nfbd \\\"Tank Control\\\"\\n\\nvar StartBtn: bool\\nvar TankLevel: real\\nvar SetPoint: real = 80.0\\nvar DwellTimer: timer\\nvar Pulse: counter\\n```\\n\\nSupported types: `bool`, `int`, `dint`, `uint`, `udint`, `real`, `lreal`, `time`, `date`, `tod`, `string`, `wstring`, `byte`, `word`, `dword`, `timer`, `counter`. Any other identifier is treated as a user-defined function-block type.\\n\\nOptional scope prefixes (default = local): `var_input`, `var_output`, `var_in_out`, `var_global`, `var_external`.\\n\\n---\\n\\n## 3. Networks\\n\\nA **network** is one independent piece of data flow, evaluated left-to-right within itself; networks evaluate top-to-bottom across the program per scan.\\n\\n```\\nnetwork 0 \\\"Start latch\\\":\\n ...\\n\\nnetwork 1:\\n ...\\n```\\n\\nThe number is optional — networks are auto-numbered if absent. The title (in quotes) renders at the top-left of the network frame.\\n\\n---\\n\\n## 4. Block calls — inline expression notation\\n\\nThe clearest way to write a combinational network is as a single nested expression:\\n\\n```\\nnetwork 0:\\n Out = OR(A, AND(B, ~C))\\n```\\n\\nThe parser builds the call tree: outer OR with `A` on input 1 and the AND result on input 2; the AND has `B` and the negated `C`. The renderer lays them out left-to-right (inputs at layer 0, AND at layer 1, OR at layer 2, output at layer 3).\\n\\n`~C` adds a **negation bubble** (small open circle) at the input port — equivalent to inserting a NOT block on that wire, but cleaner.\\n\\n---\\n\\n## 5. Block calls — instance-named notation\\n\\nWhen you need to reference a block's outputs from elsewhere, give it an instance tag:\\n\\n```\\nnetwork 0:\\n Pulse = R_TRIG(CLK: Sensor)\\n Count = CTU(CU: Pulse.Q, R: Reset, PV: 100)\\n Done = GE(IN1: Count.CV, IN2: 100)\\n```\\n\\n`Pulse.Q`, `Count.CV` reference output ports of named instances. The instance tag renders italicized above the block header.\\n\\nArgument lists accept **named ports** (`CU: Pulse.Q`) or **positional** (`CTU(Pulse.Q, Reset, 100)`) — named is recommended for readability and required when you skip a port.\\n\\n---\\n\\n## 6. Inline constants\\n\\nInput ports can take literals directly — no wire needed:\\n\\n```\\nnetwork 0:\\n Dwell = TON(IN: BottleSensor, PT: T#50ms)\\n Cap = LIMIT(MN: 0.0, IN: Setpoint, MX: 95.0)\\n Mode = SEL(G: ManualSwitch, IN0: AutoMode, IN1: ManualMode)\\n```\\n\\n`T#50ms`, `0.0`, `95.0` render as small yellow boxed text to the left of their port. Time literals follow IEC 61131-3: `T#10ms`, `T#5s`, `T#3m20s`, `T#1h`. Booleans are `true` / `false` (case-insensitive).\\n\\n---\\n\\n## 7. Standard block library\\n\\n| Category | Blocks |\\n|---|---|\\n| Boolean | `AND`, `OR`, `NOT`, `NAND`, `NOR`, `XOR`, `XNOR`, `BUF` |\\n| Edge detect | `R_TRIG`, `F_TRIG` |\\n| Bistable | `SR`, `RS` |\\n| Timer | `TON`, `TOF`, `TP` |\\n| Counter | `CTU`, `CTD` |\\n| Math | `ADD`, `SUB`, `MUL`, `DIV`, `MOD`, `ABS`, `NEG`, `MOVE` |\\n| Comparison | `EQ`, `NE`, `GT`, `GE`, `LT`, `LE` |\\n| Selection | `SEL`, `MUX`, `MAX`, `MIN`, `LIMIT` |\\n\\nAND, OR, NAND, NOR, ADD, MUL, MAX, MIN accept any number of inputs (default 2). Pass extra positional args or use `[inputs: N]` to extend.\\n\\n```\\nnetwork 0:\\n All4 = AND(A, B, C, D)\\n Sum = ADD(X, Y, Z)\\n```\\n\\n---\\n\\n## 8. Larger example — bottle counter\\n\\n```\\nfbd \\\"Bottle Counter\\\"\\n\\nvar ConveyorRunning: bool\\nvar BottleSensor: bool\\nvar BatchDone: bool\\nvar BatchSize: counter\\nvar DwellTimer: timer\\n\\nnetwork 0 \\\"Debounce sensor with 50ms dwell\\\":\\n Dwell = TON(IN: BottleSensor, PT: T#50ms)\\n\\nnetwork 1 \\\"Count one bottle on rising edge of debounced signal\\\":\\n Pulse = R_TRIG(CLK: Dwell.Q)\\n BatchSize = CTU(CU: Pulse.Q, R: BatchDone, PV: 24)\\n\\nnetwork 2 \\\"Batch done\\\":\\n BatchDone = MOVE(BatchSize.Q)\\n```\\n\\nThree networks: debounce → edge-detect → count → flag. Each network is one DAG; the renderer routes wires through Manhattan paths.\\n\\n---\\n\\n## 9. v0.1 limitations\\n\\nThe current engine implements the standard-block subset most teams use day-to-day. The following are deferred and will be added in a follow-up:\\n\\n- **EN/ENO power-flow rails** (`[en]` block attribute, `[rail: on]` header) — adds a top-of-network enable rail, vendor convention from Studio 5000 / TIA Portal.\\n- **User-defined function blocks** with `pins_in:` / `pins_out:` declarations — for custom motor controllers, PID instances, etc.\\n- **Page connectors** (`connector_out` / `connector_in`) for wires that span multiple pages.\\n- **Bit-string blocks** (SHL, SHR, ROL, ROR, AND_BIT, OR_BIT, etc.).\\n- **Extended math** (SQRT, LN, LOG, EXP, SIN, COS, TAN, ASIN, ACOS, ATAN).\\n- **ANSI distinctive shape mode** (`[shape: ansi]`) — the `logic` engine already provides this for pure-Boolean diagrams.\\n- **CTUD** bidirectional counter, **TP** retentive timer (RTO).\\n\\nIf you need any of these now, open an issue or use the `ladder` engine for the full IEC 61131-3 LD subset.\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"sfc\": {\n \"title\": \"Sequential Function Chart (SFC)\",\n \"content\": \"## 1. Your first chart\\n\\nTwo steps, one transition, an initial marker:\\n\\n```\\nsfc\\nstep S0 [initial]\\nstep S1\\ntransition from: S0 to: S1: Trigger\\n```\\n\\n`S0` renders as a **double-bordered rectangle** (the IEC initial-step convention); `S1` as a single-border rectangle. Between them is a horizontal **transition bar** with the condition text `Trigger` to its right.\\n\\nIf you forget `[initial]`, the first declared step is auto-promoted to initial.\\n\\n---\\n\\n## 2. Steps\\n\\n```\\nstep S_Filling [label: \\\"Filling tank\\\"]\\n N FillValve_Open\\n D Mixer_Run T#30s\\n P StartChime\\n```\\n\\nA step has:\\n\\n- An **id** (unique across the chart) — used in transitions and jumps.\\n- An optional `[label: \\\"...\\\"]` for display.\\n- An optional `[initial]` (one allowed) or `[final]` (vendor stop step, three borders).\\n- Zero or more **action blocks**, indented one level, each with a qualifier letter.\\n\\n---\\n\\n## 3. Transitions\\n\\nA **transition** declares a directed link between two steps with a boolean condition:\\n\\n```\\ntransition from: S0 to: S1: StartBtn\\ntransition from: S1 to: S2: TankLevel >= 80.0 AND NOT EmergencyStop\\ntransition T_Reset from: S5 to: S0: ResetBtn\\n```\\n\\nThe condition text is opaque — Schematex stores it verbatim and renders it next to the bar. Every transition must have a non-empty condition; use `TRUE` for unconditional links.\\n\\nTransitions whose `from` and `to` are linearly adjacent in the body render as inline bars between the steps. Transitions whose pair is *not* linearly adjacent (e.g. a jump back to an earlier step) render as **margin arrows** on the left or right side of the chart.\\n\\n---\\n\\n## 4. Action qualifiers\\n\\nActions attach to the right side of a step and run according to their qualifier letter:\\n\\n| Qualifier | Behavior |\\n|---|---|\\n| `N` | Active while step is active (most common) |\\n| `S` | Stored — set true on entry, stays until matching `R` |\\n| `R` | Reset — clears a previously-stored action |\\n| `L` | Time-Limited — active up to T after step entry |\\n| `D` | Time-Delayed — activates T after entry |\\n| `P` | Pulse — true for one PLC scan only |\\n| `P0` | Pulse on deactivate (Siemens) |\\n| `P1` | Synonym for `P` (Siemens) |\\n| `SD` | Stored & Delayed |\\n| `DS` | Delayed & Stored |\\n| `SL` | Stored & Time-Limited |\\n\\nTime-parameterized qualifiers (L, D, SD, DS, SL) take a duration literal:\\n\\n```\\nstep S1\\n L LimitedRun T#5s\\n D DelayedRun T#2s\\n```\\n\\n---\\n\\n## 5. Alternative branches (single bar — OR)\\n\\nOnly **one** branch fires per scan, picked by transition condition:\\n\\n```\\nstep S0 [initial]\\nstep S_Pick\\n\\nalt from: S_Pick:\\n branch [priority: 1]:\\n transition: IsExpressShipping\\n step S_Express\\n N PrepExpressBox\\n transition: TRUE\\n branch [priority: 2]:\\n transition: IsStandardShipping\\n step S_Standard\\n N PrepStandardBox\\n transition: TRUE\\nmerge_to: S_Ship\\n\\nstep S_Ship\\n\\ntransition from: S0 to: S_Pick: ProductOrdered\\ntransition from: S_Ship to: S0: Shipped\\n```\\n\\nThe single horizontal lines above and below the branches are the divergence and convergence bars. Each branch starts with its **entry transition** (between div bar and first step) and ends with an **exit transition** (between last step and conv bar).\\n\\n---\\n\\n## 6. Simultaneous branches (double bar — AND)\\n\\n**All** branches run concurrently; the chart waits at the convergence until every branch finishes:\\n\\n```\\nsim from: S_Heat: TRUE\\n branch:\\n step S_Bake\\n D Oven_Run T#15m\\n branch:\\n step S_Cool\\n L Cooler_On T#5m\\nmerge_to: S_Done: Bake_Done AND Cool_Done\\n```\\n\\nThe two parallel horizontal lines (gap 4px) above and below the branches are the simultaneous bars. The shared **transition above** (`TRUE` here) triggers the divergence; the shared **transition below** (`Bake_Done AND Cool_Done`) is checked before convergence fires.\\n\\n---\\n\\n## 7. Jumps (loops)\\n\\nA transition whose target is an earlier step renders as a margin arrow:\\n\\n```\\nstep S0 [initial]\\nstep S1\\nstep S2\\ntransition from: S0 to: S1: A\\ntransition from: S1 to: S2: B\\ntransition T_Reset from: S2 to: S0: ResetBtn\\ntransition from: S2 to: S1: NOT ResetBtn\\n```\\n\\nThe forward `S2 → S1` (back-edge) gets the margin arrow on the right; the `T_Reset` jump back to `S0` goes on the left. Each margin arrow shows its target id and condition.\\n\\n---\\n\\n## 8. Variables\\n\\nReused from `ladder` and `fbd`:\\n\\n```\\nvar StartBtn: bool\\nvar TankLevel: real\\nvar BakeReady: bool\\nvar Counter: counter\\nvar T1: timer\\n```\\n\\nVariables declared in conditions and actions are not validated — Schematex treats condition / action body text as opaque strings, matching how `state` handles guards and actions.\\n\\n---\\n\\n## 9. v0.1 limitations\\n\\n- **Nested branches** (alt-in-sim, sim-in-alt) parse but layout collapse heuristics are basic; deep nests may overlap.\\n- **S/R action-pair dashed connectors** (visually link an `S` action with its matching `R` elsewhere) are deferred.\\n- **Active-step runtime indicator** (yellow fill on the currently active step) is deferred — useful for debugging integrations that surface PLC runtime state.\\n- **GRAFCET forcing orders** (out-of-scope per IEC 60848-only feature).\\n- **Final step** parses with `[final]` but renders with the same double border as initial; the IEC triple-border convention is deferred.\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"usecase\": {\n \"title\": \"UML Use Case Diagram\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `usecase` keyword, then a header, then declarations and relationships:\\n\\n```\\nusecase\\nsystem: \\\"Library\\\"\\n\\nactor: Member\\nusecase: \\\"Borrow Book\\\" as Borrow\\n\\nMember -- Borrow\\n```\\n\\n`actor:` declares an actor (a stick figure), `usecase:` declares a use case (an ellipse), and `Member -- Borrow` draws a plain association between them. `system:` wraps the use cases in a labelled **subject** rectangle. The primary actor is placed on the left; supporting actors on the right.\\n\\nThe header accepts:\\n\\n- `title: \\\"…\\\"` — a heading drawn above the diagram.\\n- `system: \\\"…\\\"` — the subject (system boundary) name. Omit it to let the use cases float free (Schematex warns if you omit it with ≥3 use cases).\\n- `direction: LR | TB` — default `LR` (actors flank the subject horizontally).\\n- `generalization: tree | individual` — whether to merge sibling generalization arrows (default `tree`).\\n\\n---\\n\\n## 2. Actors\\n\\n```\\nactor: Customer\\nactor: \\\"Payment Gateway\\\" as PG (external)\\nactor: \\\"Warehouse Staff\\\" as WH\\nactor: Admin (left)\\n```\\n\\n- A bare or `\\\"quoted\\\"` name becomes the label; `as ID` gives it a short identifier for relationships.\\n- `(external)` (or `(system)`) renders the actor as a **rectangle with an `«actor»` stereotype** instead of a stick figure — use it for other software systems (payment gateways, third-party APIs).\\n- `(business)` adds the Bittner & Spence diagonal slash across the stick figure.\\n- `(left)` / `(right)` pins the actor to a side. By default the first actor goes left and the rest go right.\\n\\nCustom stereotypes go in guillemets after the declaration: `actor: \\\"Audit Service\\\" as Audit (external) «system»`. The parser also accepts ASCII `<<system>>` and normalises it to `«system»`.\\n\\n---\\n\\n## 3. Use cases\\n\\n```\\nusecase: \\\"Checkout\\\" as Checkout {\\n extension point: payment failed\\n extension point: stock depleted\\n}\\n```\\n\\nA use case is an ellipse sized to fit its text. The optional `{ … }` block lists **extension points** in a compartment below the name, separated by a divider line. Stereotypes work here too: `usecase: \\\"Validate Card\\\" as ValidateCard «secured»`.\\n\\n---\\n\\n## 4. Relationships\\n\\nFour line types connect actors and use cases:\\n\\n| DSL | Meaning | Rendering |\\n|-----|---------|-----------|\\n| `A -- B` | association | solid line, no arrow |\\n| `A --> B` | directed association | solid line, open arrow at B |\\n| `A ..> B` | `A` **includes** `B` | dashed line, open arrow → B, `«include»` pill |\\n| `A <.. B` | `A` **extends** `B` | dashed line, open arrow → B (the base), `«extend»` pill |\\n| `A --\\\\|> B` | `A` is a specialisation of `B` | solid line, hollow triangle → parent B |\\n\\n```\\nCustomer -- Checkout\\nCheckout ..> Pay : «include»\\nPay ..> ValidateCard : «include»\\nCancel <.. Checkout : «extend» [payment failed] (extension point: payment failed)\\n```\\n\\n- **`«include»`** points *toward the included use case* — the reusable behavior `A` always runs. Source includes target.\\n- **`«extend»`** points *toward the base* — `A` is the optional behavior, `B` is the base it extends. You can attach a `[condition]` and reference one of the base's `(extension point: …)` entries. (The arrowhead is always drawn toward the base regardless of how you order the endpoints.)\\n- An `«extend»` line is drawn in the theme **accent color** so the rarer, more surprising relationship stands out.\\n\\nThe parser rejects the high-confidence mistakes humans and LLMs both make, with the offending line number: association between two actors or two use cases, `include`/`extend` touching an actor, generalization across metaclasses (actor → use case), reused identifiers, and extension-point references that don't exist on the base.\\n\\n---\\n\\n## 5. Generalization\\n\\n`--|>` works between two actors **or** between two use cases (never across the two — that's a hard error):\\n\\n```\\nactor: User as U\\nactor: \\\"Premium User\\\" as PU\\nPU --|> U\\n\\nusecase: \\\"Pay by Card\\\" as PayCard\\nusecase: \\\"Pay by PayPal\\\" as PayPaypal\\nusecase: \\\"Pay\\\" as Pay\\nPayCard --|> Pay\\nPayPaypal --|> Pay\\n```\\n\\nThe arrow carries a **hollow triangle** pointing at the parent. When three or more siblings share one parent, the arrows merge into a single shared head (UML 2.5 Figure 18.5 convention); set `generalization: individual` in the header to keep them separate. Actor hierarchies route as a clean bus on the outer edge of the actor stack.\\n\\n---\\n\\n## 6. Multiplicity\\n\\nQuote a multiplicity string immediately beside the endpoint it belongs to:\\n\\n```\\nCustomer \\\"1\\\" -- \\\"*\\\" Checkout\\nCashier \\\"1..*\\\" -- \\\"1\\\" Register\\n```\\n\\n---\\n\\n## 7. PlantUML-style inline form\\n\\nComing from PlantUML? The inline declaration form works and mixes freely with the declarative form:\\n\\n```\\nusecase\\n:Customer: as C\\n(Browse Catalog) as Browse\\n(Add to Cart) as AddCart\\n\\nC -- Browse\\nC -- AddCart\\nBrowse ..> AddCart : «include»\\n```\\n\\n`:Name:` declares an actor, `(Name)` declares a use case, and `as ID` aliases either. Schematex is *inspired by* PlantUML, not a 1:1 transpiler — multiplicity and relationship syntax differ slightly.\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = \\\"usecase\\\" NEWLINE header_prop* statement*\\nheader_prop = (\\\"title:\\\" | \\\"system:\\\") quoted_string\\n | \\\"direction:\\\" (\\\"LR\\\" | \\\"TB\\\")\\n | \\\"generalization:\\\" (\\\"tree\\\" | \\\"individual\\\")\\n\\nstatement = actor_decl | usecase_decl | plantuml_inline | relation | note\\n\\nactor_decl = \\\"actor\\\" \\\":\\\" name (\\\"as\\\" IDENT)? actor_kind? stereotype?\\nactor_kind = \\\"(\\\" (\\\"external\\\" | \\\"system\\\" | \\\"business\\\" | \\\"left\\\" | \\\"right\\\") \\\")\\\"\\nusecase_decl = \\\"usecase\\\" \\\":\\\" quoted (\\\"as\\\" IDENT)? stereotype? extpoints?\\nextpoints = \\\"{\\\" (\\\"extension point:\\\" TEXT)+ \\\"}\\\"\\nplantuml_inline = \\\":\\\" name \\\":\\\" (\\\"as\\\" IDENT)? ; actor\\n | \\\"(\\\" name \\\")\\\" (\\\"as\\\" IDENT)? ; use case\\n\\nrelation = endpoint relop endpoint label_clause?\\nendpoint = (IDENT | quoted) multiplicity? | multiplicity? (IDENT | quoted)\\nrelop = \\\"--\\\" | \\\"-->\\\" | \\\"..>\\\" | \\\"<..\\\" | \\\"--|>\\\"\\nlabel_clause = \\\":\\\" stereotype? condition? extpoint_ref?\\nstereotype = \\\"«\\\" TEXT \\\"»\\\" | \\\"<<\\\" TEXT \\\">>\\\"\\ncondition = \\\"[\\\" TEXT \\\"]\\\"\\nextpoint_ref = \\\"(extension point:\\\" TEXT \\\")\\\"\\nmultiplicity = quoted_string ; \\\"1\\\", \\\"*\\\", \\\"0..1\\\", \\\"1..*\\\"\\n```\\n\\n---\"\n },\n \"sequence\": {\n \"title\": \"UML Sequence Diagram\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `sequence` keyword and an optional `\\\"title\\\"`. Participants don't need to be declared — the first time you mention one in a message, it becomes a lifeline:\\n\\n```\\nsequence\\n Alice -> Bob : Authentication Request\\n Bob --> Alice : Authentication Response\\n```\\n\\nLifelines appear left-to-right in first-use order. `->` is a synchronous call (solid line, filled arrowhead); `-->` is a reply (dashed line, open arrowhead). Text after `:` is the message label.\\n\\n---\\n\\n## 2. Participants\\n\\nDeclare a participant explicitly to set its **kind**, give it an **alias**, or fix its **order**:\\n\\n```\\nsequence\\n actor User\\n participant Web as \\\"Web App\\\"\\n boundary LoginUI\\n control Auth\\n entity Account\\n database DB\\n collections Sessions\\n queue Events\\n```\\n\\n| Kind | Rendered as |\\n|------|-------------|\\n| `participant` (default) | rounded classifier box |\\n| `actor` | stick figure |\\n| `boundary` / `control` / `entity` | the Jacobson robustness icons (⊢◯ / ◯ with arrow / ◯ with underline) |\\n| `database` | cylinder |\\n| `collections` / `queue` | box with the kind as a `«stereotype»` |\\n\\n- `as \\\"Label\\\"` sets the display name (quotes optional; `「…」` CJK quotes accepted).\\n- A custom **stereotype** goes in guillemets or ASCII angle brackets after the declaration — it overrides the default label: `actor Printer «system»`, `participant Bus as \\\"Event Bus\\\" <<service>>`.\\n\\n---\\n\\n## 3. Messages\\n\\nThe arrow token chooses the UML semantics:\\n\\n| DSL | Meaning | Rendering |\\n|-----|---------|-----------|\\n| `A -> B` | synchronous call | solid line, **filled** arrowhead |\\n| `A ->> B` | asynchronous signal | solid line, **open** arrowhead |\\n| `A --> B` | reply / return | **dashed** line, open arrowhead |\\n| `A -x B` | lost message | line ending at a filled circle |\\n| `o-> B` | found message | line starting from a filled circle |\\n| `A -> A` | self message | bent loop back to the same lifeline |\\n\\nWhitespace around arrows is optional (`A->B` works), and labels are free text — including a return value, e.g. `aHotel -> aHotel : available(roomId, date): isRoom`.\\n\\n---\\n\\n## 4. Activations (execution specifications)\\n\\nThe thin bar on a lifeline shows it is active. Open and close it with explicit statements, or with `+` / `-` suffixes on the messages themselves:\\n\\n```\\nsequence\\n participant Client\\n participant Server\\n Client ->+ Server : request()\\n Server ->> Server : validate()\\n Server -->- Client : response\\n```\\n\\n`+` after the arrow activates the **receiver** on arrival; `-` deactivates the **sender** after the message is sent. The explicit form is `activate X` / `deactivate X`. Overlapping bars on one lifeline nest with a horizontal offset.\\n\\n---\\n\\n## 5. Object creation & destruction\\n\\n```\\nsequence\\n participant Factory\\n Factory -> *Worker : «create»\\n Factory -> Worker : work()\\n destroy Worker\\n```\\n\\nPrefix the receiver with `*` to make the message **instantiate** it — the new lifeline's head is drawn at the arrival row, not at the top. `destroy X` ends a lifeline with a ✕ and stops its time axis.\\n\\n---\\n\\n## 6. Combined fragments\\n\\nA combined fragment is a labelled frame around a region. Schematex implements the full UML `InteractionOperatorKind` set:\\n\\n| Operator | Meaning | Operands |\\n|----------|---------|----------|\\n| `alt` | alternatives (if/else-if/else) | `else`, each guarded |\\n| `opt` | runs iff the guard holds | one, guarded |\\n| `loop` | repeat | one; guard may be `(min,max)` |\\n| `par` | concurrent operands | `and` |\\n| `break` | exceptional exit | one, guarded |\\n| `critical` | atomic / no interleaving | one |\\n| `seq` / `strict` | weak / strict sequencing | `and` |\\n| `neg` | invalid traces (rendered tinted) | one |\\n| `ignore` / `consider` | message-set filter `{m1, m2}` | one |\\n| `assert` | the only valid continuation | one |\\n\\n```\\nsequence\\n actor User\\n participant API\\n User -> API : GET /resource\\n alt [authorized]\\n API --> User : 200 + body\\n else [forbidden]\\n API --> User : 403\\n end\\n```\\n\\nGuards go in `[brackets]` after the operator (and after `else`). Fragments nest, and inner frames inset automatically so they sit cleanly inside their parent.\\n\\n---\\n\\n## 7. Interaction use (`ref`)\\n\\nReference another interaction instead of inlining it — the way UML keeps large diagrams composable:\\n\\n```\\nsequence\\n participant A\\n participant B\\n ref over A, B : Establish session\\n A -> B : poll()\\n```\\n\\n`ref over <lifelines> : Name` draws a framed box across the named lifelines. Most tools omit this; it's how real systems decompose long flows.\\n\\n---\\n\\n## 8. Notes, dividers, invariants, numbering\\n\\n```\\nsequence\\n autonumber 1 1\\n actor Shopper\\n participant Cart\\n == Phase 1: review ==\\n Shopper -> Cart : view items\\n note over Cart : cart persisted in Redis\\n state Cart : ready\\n```\\n\\n- `note over A` / `note over A, B` / `note left of A` / `note right of A` — folded-corner annotations.\\n- `== text ==` — a full-width section divider.\\n- `state X : text` — a state-invariant capsule on a lifeline.\\n- `autonumber [start] [step]` — prefix every message with an incrementing number.\\n\\n---\\n\\n## 9. Grammar (EBNF)\\n\\n```text\\ndiagram = \\\"sequence\\\" [ string ] NEWLINE statement*\\nstatement = participant | message | activation | note\\n | fragment | ref | divider | invariant | destroy | autonumber\\n\\nparticipant = kind IDENT (\\\"as\\\" label)? stereotype?\\nkind = \\\"participant\\\" | \\\"actor\\\" | \\\"boundary\\\" | \\\"control\\\"\\n | \\\"entity\\\" | \\\"database\\\" | \\\"collections\\\" | \\\"queue\\\"\\nstereotype = \\\"«\\\" TEXT \\\"»\\\" | \\\"<<\\\" TEXT \\\">>\\\"\\n\\nmessage = IDENT? act? arrow act? (\\\"*\\\")? IDENT? (\\\":\\\" TEXT)?\\narrow = \\\"->\\\" | \\\"->>\\\" | \\\"-->\\\" | \\\"-x\\\" | \\\"o->\\\"\\nact = \\\"+\\\" | \\\"-\\\"\\nactivation = (\\\"activate\\\" | \\\"deactivate\\\") IDENT\\n\\nfragment = (\\\"alt\\\"|\\\"opt\\\"|\\\"loop\\\"|\\\"par\\\"|\\\"break\\\"|\\\"critical\\\"|\\\"seq\\\"\\n |\\\"strict\\\"|\\\"neg\\\"|\\\"ignore\\\"|\\\"consider\\\"|\\\"assert\\\") guard? NEWLINE\\n statement* ((\\\"else\\\"|\\\"and\\\") guard? NEWLINE statement*)* \\\"end\\\"\\nguard = \\\"[\\\" TEXT \\\"]\\\" | \\\"(\\\" NUMBER (\\\",\\\" NUMBER)? \\\")\\\"\\nref = \\\"ref\\\" \\\"over\\\" IDENT (\\\",\\\" IDENT)* \\\":\\\" TEXT\\nnote = \\\"note\\\" (\\\"over\\\"|\\\"left of\\\"|\\\"right of\\\") IDENT (\\\",\\\" IDENT)? \\\":\\\" TEXT\\ndivider = \\\"==\\\" TEXT \\\"==\\\"\\ninvariant = \\\"state\\\" IDENT \\\":\\\" TEXT\\ndestroy = \\\"destroy\\\" IDENT\\nautonumber = \\\"autonumber\\\" NUMBER? NUMBER?\\n```\\n\\n---\"\n },\n \"prisma\": {\n \"title\": \"PRISMA 2020 flow diagram\",\n \"content\": \"## 1. Your first diagram\\n\\nThe minimum is the four stage blocks. Counts are mandatory; the parser refuses to lay out a diagram with a missing total.\\n\\n```\\nprisma\\n\\nidentification:\\n databases:\\n n: 1000\\n\\nscreening:\\n records-screened: 900\\n excluded:\\n n: 600\\n\\neligibility:\\n full-text-assessed: 300\\n excluded:\\n n: 250\\n\\nincluded:\\n studies: 50\\n```\\n\\nIndentation is significant — **two spaces per level**, like genogram and SLD. The first non-blank line must be `prisma`. Comments use `#` or `//`.\\n\\n---\\n\\n## 2. Meta lines\\n\\nTop-level `key: value` lines, written before the stage blocks:\\n\\n```\\nprisma\\nmode: 2020-single\\nkind: systematic-review\\ntitle: My review\\nvalidate-counts: warn\\n```\\n\\n| Key | Values | Default | Meaning |\\n|---|---|---|---|\\n| `mode` | `2020-single` · `2020-dual` · `2009` | `2020-single` | Single column, or dual (\\\"other methods\\\") column. |\\n| `kind` | `systematic-review` · `scoping-review` · `ipd` · `nma` | `systematic-review` | Swaps stage vocabulary (see §6). |\\n| `title` | string | — | Rendered above the diagram. |\\n| `validate-counts` | `warn` · `strict` · `off` | `warn` | Arithmetic checking (see §7). |\\n| `direction` | `TB` / `TD` | `TB` | PRISMA is vertical by standard; horizontal is rejected. |\\n\\n---\\n\\n## 3. Identification\\n\\nThe `identification:` block holds a `databases:` sub-block (always) and an optional `other:` sub-block (dual mode).\\n\\n```\\nidentification:\\n databases:\\n n: 1418\\n sources: PubMed=600, Embase=450, Cochrane=184\\n duplicates-removed: 318\\n ineligible-automation: 0\\n other-removed: 0\\n```\\n\\n- `n:` — total records identified (**mandatory**).\\n- `sources:` — `name=count` pairs, comma-separated. Rendered as an indented breakdown. Names with spaces or punctuation can be quoted: `\\\"Web of Science\\\"=184`.\\n- `duplicates-removed:`, `ineligible-automation:`, `other-removed:` — optional removal counts. When any are present they render as a separate **\\\"Records removed before screening\\\"** box in the right column, connected by a horizontal arrow.\\n\\nLarge numbers may use commas: `n: 1,418` is the same as `n: 1418`.\\n\\n---\\n\\n## 4. Screening & Eligibility\\n\\nBoth stages carry a main count plus an `excluded:` block. The excluded block has its own `n:` and an optional `reasons:` breakdown.\\n\\n```\\nscreening:\\n records-screened: 1100\\n excluded:\\n n: 870\\n reasons: irrelevant title=750, non-English=120\\n reports-sought: 226 # optional\\n reports-not-retrieved: 12 # optional\\n\\neligibility:\\n full-text-assessed: 230\\n excluded:\\n n: 195\\n reasons: wrong population=80, wrong intervention=60, wrong outcome=55\\n```\\n\\n`reasons:` are `name=count` pairs. If you list more than 8, the renderer sorts them descending and aggregates the tail as `Other (n = …)` so the side-box stays readable.\\n\\n---\\n\\n## 5. Included\\n\\n```\\nincluded:\\n studies: 35\\n reports: 38 # one study may yield several reports\\n participants: 28741 # PRISMA-IPD only\\n```\\n\\n`studies:` is mandatory. `reports:` and `participants:` are optional extra count lines.\\n\\n---\\n\\n## 6. Dual pipeline & review kinds\\n\\n**Dual pipeline** — the PRISMA 2020 update added a second \\\"Identification via other methods\\\" column (citation searching, hand searches, expert recommendations). Add an `other:` block; the two columns merge into Screening via a Y-junction.\\n\\n```\\nprisma\\nmode: 2020-dual\\n\\nidentification:\\n databases:\\n n: 1234\\n duplicates-removed: 254\\n other:\\n n: 56\\n sources: citation-search=30, hand-search=20, expert-recommendation=6\\n\\nscreening:\\n records-screened: 1036\\n excluded:\\n n: 810\\n\\neligibility:\\n full-text-assessed: 226\\n excluded:\\n n: 195\\n\\nincluded:\\n studies: 31\\n```\\n\\n**Scoping review** — `kind: scoping-review` swaps \\\"studies\\\" → \\\"sources of evidence\\\" and re-labels the stages per Tricco et al. 2018, without changing geometry.\\n\\n**Updated review** — an optional `previous-studies:` block draws a dashed box on top that feeds into the identification section:\\n\\n```\\nprevious-studies:\\n n: 19\\n sources: previous review=19\\n```\\n\\n---\\n\\n## 7. Count arithmetic validation\\n\\nWith `validate-counts: warn` (default) the engine checks that the counts reconcile across stages — e.g. `databases.n + other.n − duplicates-removed = records-screened`, and that source/reason breakdowns sum to their totals. Mismatches render a small warning under the diagram (also surfaced in the SVG `<desc>` for screen readers).\\n\\n`validate-counts: strict` turns a mismatch into a parse error with an \\\"off by N\\\" message. `off` skips checking entirely.\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```\\nprisma-document = \\\"prisma\\\", { meta-line }, stage-block, { stage-block } ;\\nmeta-line = (\\\"mode:\\\" | \\\"kind:\\\" | \\\"title:\\\" | \\\"review-id:\\\" | \\\"validate-counts:\\\" | \\\"direction:\\\") value ;\\n\\nstage-block = previous-block | identification-block | screening-block | eligibility-block | included-block ;\\n\\nprevious-block = \\\"previous-studies:\\\" , indent, \\\"n:\\\" int, [ \\\"reports:\\\" int ], { \\\"sources:\\\" pairs } ;\\nidentification-block = \\\"identification:\\\" , indent,\\n \\\"databases:\\\" , indent, \\\"n:\\\" int, { \\\"sources:\\\" pairs },\\n [ \\\"duplicates-removed:\\\" int ], [ \\\"ineligible-automation:\\\" int ], [ \\\"other-removed:\\\" int ],\\n [ \\\"other:\\\" , indent, \\\"n:\\\" int, { \\\"sources:\\\" pairs } ] ;\\nscreening-block = \\\"screening:\\\" , indent, \\\"records-screened:\\\" int,\\n \\\"excluded:\\\" , indent, \\\"n:\\\" int, { \\\"reasons:\\\" pairs },\\n [ \\\"reports-sought:\\\" int ], [ \\\"reports-not-retrieved:\\\" int ] ;\\neligibility-block = \\\"eligibility:\\\" , indent, \\\"full-text-assessed:\\\" int,\\n \\\"excluded:\\\" , indent, \\\"n:\\\" int, { \\\"reasons:\\\" pairs } ;\\nincluded-block = \\\"included:\\\" , indent, \\\"studies:\\\" int, [ \\\"reports:\\\" int ], [ \\\"participants:\\\" int ] ;\\n\\npairs = pair, { \\\",\\\" pair } ;\\npair = (string | quoted) \\\"=\\\" int ;\\nint = digit, { digit | \\\",\\\" } ; (* commas stripped: 1,234 == 1234 *)\\n```\\n\\nIndentation is two spaces per level. Unknown keys inside a stage block are a parse error, keeping each stage well-defined.\\n\\n---\"\n },\n \"pert\": {\n \"title\": \"PERT / CPM Network\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `pert` keyword, an optional header, then one `task` line per activity:\\n\\n```\\npert\\nunit: days\\n\\ntask A \\\"Market research\\\" duration: 5\\ntask B \\\"Design mockups\\\" duration: 8 after: A\\ntask C \\\"Backend API\\\" duration: 15 after: A\\ntask D \\\"Frontend build\\\" duration: 10 after: B, C\\n```\\n\\nEach task carries an `<id>`, a quoted `<label>`, a `duration:`, and an optional `after:` list of predecessors. The engine adds an invisible Start and Finish, runs the schedule, and draws the six-field activity box for every task. You never type ES/EF/LS/LF — they are computed.\\n\\nThe header accepts:\\n\\n- `title: \\\"…\\\"` — a heading drawn above the diagram.\\n- `unit: days | weeks | hours | abstract` — the time unit (default `days`; purely a label, the engine is calendar-agnostic).\\n- `direction: LR | TB` — left-to-right (default) or top-to-bottom.\\n- `layout: network | timescaled` — the layered network (default) or a time-proportional view (§6).\\n- `critical-tolerance: <n>` — slack ≤ this counts as critical (default `0`; set `0.001` for three-point projects).\\n- `show-sentinels: true` — draw the synthetic Start / Finish nodes (hidden by default).\\n\\n---\\n\\n## 2. The six-field activity box\\n\\nEvery task renders as the canonical 3×2 PERT/CPM rectangle:\\n\\n```\\n┌──────────┬────────────┬──────────┐\\n│ ES │ Duration │ EF │\\n├──────────┴────────────┴──────────┤\\n│ Task Name (ID) │\\n├──────────┬────────────┬──────────┤\\n│ LS │ Slack │ LF │\\n└──────────┴────────────┴──────────┘\\n```\\n\\n- **ES / EF** — Early Start / Early Finish, from the forward pass.\\n- **LS / LF** — Late Start / Late Finish, from the backward pass.\\n- **Slack** (total float) = LS − ES = LF − EF. Zero slack means the activity is on the critical path.\\n\\nCritical activities get a **red border** and a bold `0` slack; the project's critical chain reads as an unbroken red line. Every field is also mirrored onto `data-*` attributes (`data-es`, `data-slack`, `data-critical`, …) so you can query the SVG without re-running the math.\\n\\n**On the two-colour palette.** A PERT chart is deliberately drawn in just two colours. Red for the critical path is a genuine industry convention — MS Project, Oracle Primavera P6, and PMBOK figures all use it, because \\\"critical vs. not\\\" is the one distinction the diagram exists to surface. Everything else stays a neutral house-blue. Adding more colours would imply categories that PERT's semantics don't have; if you need to group by team or phase, use [swimlanes](#7-swimlanes-tags-classes-and-comments) (`lane:`) instead of colour.\\n\\n---\\n\\n## 3. Dependencies (FS / SS / FF / SF + lag/lead)\\n\\n`after:` takes a comma-separated list of predecessor references. The default relationship is **Finish-to-Start (FS)** — a task starts once its predecessor finishes:\\n\\n```\\ntask D \\\"Frontend build\\\" duration: 10 after: B, C\\n```\\n\\nModern scheduling needs the other three Precedence-Diagramming relationships and **lag** (delay) or **lead** (negative lag):\\n\\n```\\ntask B \\\"Stakeholder interviews\\\" duration: 6 after: A SS+1 # start 1d after A starts\\ntask I \\\"Documentation\\\" duration: 4 after: D+3 # FS with a 3-day lag\\ntask J \\\"Translation\\\" duration: 3 after: I SS-1 # start 1d before I starts (lead)\\ntask K \\\"Sign-off\\\" duration: 1 after: I FF # finishes when I finishes\\ntask L \\\"Press release\\\" duration: 2 after: G SF+1 # start-to-finish (rare)\\n```\\n\\n| Form | Meaning |\\n|------|---------|\\n| `after: A` | Finish-to-Start, no lag (the common case) |\\n| `after: A+2` or `after: A+2d` | FS with a 2-unit lag |\\n| `after: A SS` / `A FF` / `A SF` | Start-to-Start / Finish-to-Finish / Start-to-Finish |\\n| `after: A SS+2d` / `A FF-1d` | any type with lag (`+`) or lead (`-`) |\\n\\nA lag unit suffix (`d` / `w` / `h`) must match the diagram's `unit:` or be omitted; mixed units are rejected. FS with zero lag is unlabelled; SS/FF/SF always show their type on the edge.\\n\\n---\\n\\n## 4. Three-point (PERT) estimation\\n\\nWrite a duration as `O/M/P` (optimistic / most-likely / pessimistic) and the engine computes the beta-distribution expected duration **te = (O + 4M + P) / 6** and the variance **σ² = ((P − O)/6)²**:\\n\\n```\\npert\\ncritical-tolerance: 0.01\\ntask A \\\"Spec\\\" duration: 2/3/5 # te = 3.17, σ² = 0.25\\ntask B \\\"Build\\\" duration: 5/8/14 after: A # te = 8.50, σ² = 2.25\\ntask C \\\"Test\\\" duration: 3/4/6 after: B\\ntask D \\\"Deploy\\\" duration: 1/2/3 after: C\\n```\\n\\nThe Duration field shows `te`; a small `σ=…` annotation appears under the name; and the project-level standard deviation (√ of the summed critical-path variances) is reported in the footer. Use `critical-tolerance: 0.01` so floating-point `te` values don't displace the visible critical path.\\n\\n---\\n\\n## 5. Milestones\\n\\nA milestone is a zero-duration checkpoint, drawn as a diamond. Use the `milestone` flag or `duration: 0`:\\n\\n```\\ntask P \\\"Cutover weekend\\\" milestone after: O\\ntask Q \\\"Go-live\\\" duration: 0 after: P\\n```\\n\\n---\\n\\n## 6. Time-scaled layout\\n\\n`layout: timescaled` switches from the layered network to a network-Gantt hybrid: each activity's **x-position is proportional to its ES** and its **width is proportional to its duration**, with a unit time axis along the bottom. Activities are packed into lanes so nothing overlaps.\\n\\n```\\npert\\nlayout: timescaled\\nunit: days\\n\\ntask A \\\"Inventory\\\" duration: 5\\ntask B \\\"Interviews\\\" duration: 6 after: A SS+1\\ntask C \\\"Design\\\" duration: 10 after: A, B\\ntask D \\\"Build\\\" duration: 15 after: C\\ntask E \\\"Pilot\\\" duration: 7 after: D\\n```\\n\\nThis is a bridge to a Gantt view, not a replacement: there's no calendar, working-time mask, or resource swimlane.\\n\\n### Activity-on-arrow (`layout: aoa`)\\n\\n`layout: aoa` renders the older **activity-on-arrow** (ADM) notation you'll find in textbooks and on Investopedia: numbered **event** circles, **activities as labelled arrows**, and dotted **dummy activities** auto-inserted wherever an activity has two or more predecessors. You write the same activity-on-node DSL — Schematex builds the event graph and numbers the events for you.\\n\\n```\\npert\\nlayout: aoa\\nunit: days\\n\\ntask A \\\"create schedule\\\" duration: 10\\ntask B \\\"buy hardware\\\" duration: 5\\ntask C \\\"programming\\\" duration: 20 after: A\\ntask D \\\"installation\\\" duration: 5 after: B\\ntask E \\\"conversion\\\" duration: 15 after: D\\ntask F \\\"test code\\\" duration: 20 after: C, E\\ntask G \\\"write manual\\\" duration: 15 after: E\\n```\\n\\nAOA is a **legacy** notation (PMBOK 7 dropped it; AON is the modern standard) and it can only express **finish-to-start** logic — SS/FF/SF and lag/lead are flattened to FS with a warning. Use it for teaching, exam prep, or matching an existing textbook figure; use the default `network` (AON) layout for real scheduling.\\n\\n---\\n\\n## 7. Swimlanes, tags, classes, and comments\\n\\nAdd `lane: \\\"…\\\"` to any task and the network re-groups into horizontal swimlanes — by responsible team, phase, or owner — while still computing the schedule exactly as before:\\n\\n```\\ntask T1 \\\"Support Account Deletion\\\" duration: 3 lane: \\\"Customer Account\\\"\\ntask T2 \\\"Design a New Theme\\\" duration: 8 lane: \\\"Shopping Site\\\"\\ntask T3 \\\"Apply New Theme\\\" duration: 15 after: T2 lane: \\\"Shopping Site\\\"\\n```\\n\\nLanes appear in first-declared order, each as a banded row with a label gutter on the left. Swimlanes are a presentation of the same AON network, not a different layout mode — they activate automatically when any task declares a lane.\\n\\n```\\ntask X \\\"External vendor work\\\" duration: 10 after: A tags: vendor, external class: secondary\\n# this is a comment\\n```\\n\\n`tags:` emit `data-tag=\\\"…\\\"` on the node group and `class:` adds a CSS class for downstream theming. `#` and `//` start a comment to end of line.\\n\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = \\\"pert\\\" NEWLINE header* task+\\nheader = \\\"title:\\\" quoted\\n | \\\"unit:\\\" (\\\"days\\\" | \\\"weeks\\\" | \\\"hours\\\" | \\\"abstract\\\")\\n | \\\"direction:\\\" (\\\"LR\\\" | \\\"TB\\\")\\n | \\\"layout:\\\" (\\\"network\\\" | \\\"timescaled\\\" | \\\"aoa\\\")\\n | \\\"critical-tolerance:\\\" number\\n | \\\"show-sentinels:\\\" boolean\\n\\ntask = \\\"task\\\" IDENT quoted \\\"duration:\\\" duration (\\\"after:\\\" reflist)? \\\"milestone\\\"? attrs?\\n | \\\"task\\\" IDENT quoted \\\"milestone\\\" (\\\"after:\\\" reflist)? attrs?\\nduration = number | number \\\"/\\\" number \\\"/\\\" number ; deterministic or O/M/P\\nreflist = ref (\\\",\\\" ref)*\\nref = IDENT (WS deptype)? laglead?\\n | IDENT \\\"+\\\" number unit? ; attached FS lag sugar\\ndeptype = \\\"FS\\\" | \\\"SS\\\" | \\\"FF\\\" | \\\"SF\\\"\\nlaglead = (\\\"+\\\" | \\\"-\\\") number unit?\\nunit = \\\"d\\\" | \\\"w\\\" | \\\"h\\\"\\nattrs = (\\\"tags:\\\" idlist)? (\\\"class:\\\" IDENT)? (\\\"lane:\\\" quoted)?\\n```\\n\\n---\"\n },\n \"petri\": {\n \"title\": \"Petri Net\",\n \"content\": \"## 1. Your first net\\n\\nEvery document starts with the `petri` keyword and an optional title, then declares **places** and **transitions** before connecting them with **arcs**:\\n\\n```\\npetri \\\"Minimal\\\"\\n place P1 *1\\n transition T1\\n place P2\\n P1 -> T1\\n T1 -> P2\\n```\\n\\n- `place <id>` — a circle. `*1` sets its initial token count (the marking).\\n- `transition <id>` — a bar (an event/action).\\n- `<a> -> <b>` — a directed arc. Arcs are **bipartite**: every arc goes place→transition or transition→place, never place→place or transition→transition. If you write one wrong, the engine tells you which line.\\n\\nUnlike some Schematex diagrams, nodes are **not** auto-declared from arcs — because an undeclared id can't be safely typed as a place or a transition. An arc that references an unknown node is a readable error.\\n\\n---\\n\\n## 2. Marking & tokens\\n\\nThe **marking** is how many tokens each place holds. Three equivalent ways to set it:\\n\\n```\\nplace P1 *3 # *n shorthand\\nplace P2 tokens: 3 # explicit\\nplace P3 ••• # literal dots (1–4)\\n```\\n\\nOr set several at once with a `marking:` line:\\n\\n```\\nmarking: P1=3, P3=2\\n```\\n\\nTokens render as dots (up to 4, laid out in a grid) and as a numeral beyond that. Force one style with `tokens: dots | count | auto` (default `auto`).\\n\\n---\\n\\n## 3. Transitions: immediate vs timed\\n\\n```\\ntransition fast # immediate — a solid bar (the default)\\ntransition slow timed rate: 0.8 # timed — a hollow box with a rate label λ\\n```\\n\\nImmediate transitions fire in zero time and render as the classic filled bar; **timed** transitions (the [GSPN](https://en.wikipedia.org/wiki/Stochastic_Petri_net) convention) render as a hollow box and carry an optional `rate:` (λ). A transition with a `rate:` is treated as timed automatically. `prio: n` sets a priority, and a `[guard]` is rendered as a label (not evaluated in v0.1).\\n\\n---\\n\\n## 4. Arc types\\n\\nFour arc heads cover the standard concurrency vocabulary:\\n\\n```\\nP -> T # standard arc (filled arrowhead)\\nP -> T weight: 2 # weight > 1 is labelled (weight: n or *n)\\nP -o T # inhibitor — enabled only while the place is empty (hollow-circle head)\\nP -- T # read / test — tests presence without consuming (no head)\\nP => T # reset — empties the place when the transition fires (double head)\\n```\\n\\nInhibitor and reset arcs are **place→transition only** — the parser rejects the reverse direction.\\n\\n---\\n\\n## 5. Capacity\\n\\nA place can be capped. Firing that would overflow it is disabled, and the place is drawn with a dashed border and a `K=n` label:\\n\\n```\\nplace Buffer capacity: 3\\n```\\n\\n---\\n\\n## 6. The dynamics: enabled & fire\\n\\nThe engine computes the semantics on every render:\\n\\n- **Enabled** transitions (every input satisfied; inhibitor inputs empty; no output would overflow capacity) get a green ring.\\n- **Dead** transitions — those that can never fire from the current marking — are muted.\\n- A **`fire:`** line replays a firing sequence and renders the *resulting* marking:\\n\\n```\\npetri\\n place P1 *1\\n transition T1\\n place P2\\n transition T2\\n place P3\\n P1 -> T1\\n T1 -> P2\\n P2 -> T2\\n T2 -> P3\\n fire: T1\\n```\\n\\nAfter firing `T1`, the token has moved P1 → P2, and now **T2** is the enabled transition. The SVG `<desc>` records the marking, the enabled set, and any detected subclass (state machine / marked graph / workflow net).\\n\\n---\\n\\n## 7. Layout & themes\\n\\n```\\nlayout: lr # left-to-right (default)\\nlayout: tb # top-to-bottom\\n```\\n\\nPlaces and transitions land on alternating layers automatically; cycles are detected and their feedback arcs routed as back-edge curves. Three themes:\\n\\n- **`default`** — house blue-grey, with green reserved for *enabled* and red for *inhibitor*.\\n- **`monochrome`** — the faithful Murata-1989 textbook look; enabled shows as a doubled black ring (colour falls back to shape).\\n- **`dark`** — Catppuccin Mocha.\\n\\nCJK labels and `「…」` / `\\\"…\\\"` quotes parse cleanly:\\n\\n```\\npetri \\\"生产流程\\\"\\n place 原料 *2 「原材料」\\n transition 加工\\n place 成品\\n 原料 -> 加工 weight: 2\\n 加工 -> 成品\\n```\\n\\n---\\n\\nFull specification: [Petri Net Standard Reference](https://github.com/schematex/schematex/blob/main/docs/reference/34-PETRINET-STANDARD.md).\\n\\n---\\n\\n## Related examples\\n\\nReady-to-use scenarios from the examples gallery:\"\n },\n \"network\": {\n \"title\": \"Network Topology\",\n \"content\": \"## 1. Your first diagram\\n\\nA complete network diagram needs only two kinds of line: **device declarations** and **links**. Nothing else is required.\\n\\n```\\nnetwork \\\"Tiny LAN\\\"\\nrouter r1 \\\"Edge Router\\\"\\nswitch sw1 \\\"Core Switch\\\"\\npc pc1 \\\"Workstation\\\"\\nr1 -- sw1\\nsw1 -- pc1\\n```\\n\\nThat's it — a valid, laid-out diagram. Just two rules:\\n\\n- `<kind> <id> [\\\"label\\\"]` — a typed device. The kind picks the icon.\\n- `<a> -- <b>` — an undirected link between two declared devices.\\n\\n**Everything else is optional and additive — but not all of it is equal.** Two cheap, high-value structural hints are worth adding whenever hierarchy matters: `layout:` (tiered/tree/star/ring/bus/mesh/spine-leaf) and `tier:` (edge/core/distribution/access). They drive a readable top-down hierarchy at almost no syntax cost:\\n\\n```\\nnetwork \\\"Branch\\\"\\n layout: tiered\\n router r1 \\\"Edge Router\\\" tier: edge\\n l3switch core1 \\\"Core SW\\\" tier: core\\n switch acc1 \\\"Access SW\\\" tier: access\\n pc pc1 \\\"Workstation\\\"\\n r1 -- core1\\n core1 -- acc1\\n acc1 -- pc1\\n```\\n\\nBy contrast, the **per-link annotations** — link types (`fiber`/`wireless`/`poe`…), speeds, `vlan:`, `port:`, `trunk`/`access`, and `subnet { }` boundaries — don't affect layout and are where generation most often breaks. Add them only when the request calls for them. Rule of thumb: keep the structural hints, drop the decorative annotations unless asked.\\n\\nDevices are **not** auto-declared from links — an undeclared id can't be safely typed, so a link to an unknown device is a readable error. Use `;` to put several statements on one line, and `a b c : kind` shorthand to declare several same-kind devices at once.\\n\\nOnce the skeleton works, you can layer on direction and annotations — `->` is a directed link, `==` is a LAG, and anything after `:` is the link spec:\\n\\n```\\nnetwork \\\"Home\\\"\\n layout: star\\n router gw \\\"Gateway\\\"\\n pc pc1\\n laptop lt1\\n gw -- pc1\\n gw -- lt1 : wireless\\n```\\n\\n---\\n\\n## 2. Device kinds\\n\\nPick the kind that matches the box; the icon follows the Cisco-convention silhouette.\\n\\n- **Infrastructure** — `router`, `switch`, `l3switch`, `firewall`, `loadbalancer`, `ap`, `wlc`, `gateway`, `modem`, `ids`, `proxy`, `vpngw`\\n- **Endpoints** — `server`, `serverfarm` (`count: n`), `pc`, `laptop`, `mobile`, `ipphone`, `printer`, `storage`\\n- **CCTV / security** — `camera` (with `type: fixed | bullet | dome | ptz | turret`), `nvr`, `dvr`, `poeswitch`, `encoder`, `monitor`\\n- **Clouds** — `internet`, `wan`, `pstn`, `cloud`, plus `lan` (a bus bar)\\n\\nAliases are accepted: `multilayer`→`l3switch`, `workstation`→`pc`, `wifi`→`ap`, `nas`/`san`→`storage`, `voip`→`ipphone`.\\n\\n```\\ncamera cam1 type: dome ip: 192.168.20.11\\nserverfarm farm \\\"Server Farm\\\" count: 4\\nl3switch core1 tier: core model: \\\"C9500\\\"\\n```\\n\\n---\\n\\n## 3. Links & annotations\\n\\nA link's appearance follows its type; everything after `:` is order-free.\\n\\n```\\na -- b # copper / ethernet (default solid)\\na -- b : fiber 10G # fiber — orange with slash ticks\\na -- b : wireless # dashed\\na -- b : serial # leased / WAN circuit\\na -- b : poe # Power-over-Ethernet (green + tag)\\na -- b : vpn \\\"site-to-site\\\" # dashed tunnel\\na == b : lag 40G # aggregated / EtherChannel (double line)\\na -- b : trunk vlan: 10,20 1G port: Gi0/1>Gi1/0/24\\n```\\n\\n- `trunk` / `access` — port mode (a trunk should connect switch-class devices).\\n- `vlan: 10` or `vlan: 10,20` — a single VLAN tints the link (skipping the reserved alarm-red).\\n- `1G` / `10G` / `100M` / `40G` — speed, shown mid-link.\\n- `port: near>far` — interface labels at each end.\\n\\n---\\n\\n## 4. Layout modes\\n\\n```\\nlayout: tiered # default — band by tier: edge → core → distribution → access\\nlayout: tree # hierarchical from the root\\nlayout: star # hub at center, spokes on a ring\\nlayout: ring # nodes on a circle\\nlayout: bus # shared backbone\\nlayout: mesh # full/partial mesh on a circle\\nlayout: spine-leaf # two rows, every leaf auto-meshed to every spine\\nlayout: manual # explicit at: x,y per device\\ndirection: tb | lr # flow axis for tiered/tree\\n```\\n\\nFor `tiered`, set `tier:` (`edge` / `core` / `distribution` / `access`) on infrastructure; untiered endpoints are placed below their switch. For `spine-leaf`, declare `spines:` and `leaves:` and the spine↔leaf links are generated for you.\\n\\n---\\n\\n## 5. Boundaries: sites, racks, subnets, VLANs\\n\\nA device can live inside nested boundary blocks. **Physical** containers (site/rack) draw a solid border; **logical** overlays (subnet/VLAN/zone/DMZ) draw a dashed tinted region.\\n\\n```\\nnetwork \\\"Branch\\\"\\n site hq \\\"HQ Building\\\" {\\n rack mdf \\\"MDF Rack\\\" {\\n firewall fw1 tier: edge\\n l3switch core1 tier: core\\n }\\n }\\n subnet lan \\\"10.0.10.0/24\\\" {\\n switch a1 tier: access\\n pc u1 \\\"User PC\\\" ip: 10.0.10.50\\n }\\n zone dmz \\\"DMZ\\\" {\\n server web\\n }\\n fw1 -- core1 : 10G\\n core1 -- a1 : trunk vlan: 10\\n a1 -- u1\\n```\\n\\nA device declared inside a `subnet` whose label is a CIDR has its `ip:` validated — an address outside the range is a readable error. A bare id on its own line inside a block adds an already-declared device to that group.\\n\\n---\\n\\n## 6. Validation & the no-drop guarantee\\n\\nThe engine guarantees every declared device and link renders — the dropped-device failure of generic tools is structurally impossible. It also checks:\\n\\n- **duplicate id** → error;\\n- **unknown kind** → error with the nearest suggestion (`\\\"swtich\\\" → did you mean \\\"switch\\\"?`);\\n- **link to an undeclared device** → error;\\n- **VLAN id outside 1–4094** → warning (still renders);\\n- **device IP outside its subnet CIDR** → error.\\n\\nThe SVG `<desc>` records device/link counts, the detected topology class (star / ring / bus / mesh / tree / hierarchical / spine-leaf), and any warnings.\\n\\n---\\n\\n## 7. Themes\\n\\n```\\ntheme: default # house \\\"network blue\\\" Cisco-style bodies\\ntheme: monochrome # clean line-art for print/audit (link meaning via line-style + tags)\\ntheme: dark # Catppuccin Mocha\\n```\\n\\nCJK labels and `「…」` / `\\\"…\\\"` quotes parse cleanly:\\n\\n```\\nnetwork \\\"办公室\\\"\\n multilayer core1 「核心交换机」\\n poeswitch poe1\\n camera cam1 type: dome\\n core1 -- poe1 : trunk vlan: 10\\n poe1 -- cam1 : poe\\n```\\n\\n---\"\n },\n \"umlclass\": {\n \"title\": \"UML Class Diagram\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `umlclass` keyword (the Mermaid `classDiagram` header is also accepted), then declarations and relationships:\\n\\n```\\numlclass\\nclass Account {\\n + id : String\\n - balance : Money\\n + deposit(amount : Money) : void\\n}\\nclass Customer {\\n + name : String\\n}\\nCustomer \\\"1\\\" o-- \\\"*\\\" Account : owns\\n```\\n\\nA `class X { … }` block declares a classifier with a name compartment, an attributes compartment, and an operations compartment. Members on their own lines inside the braces; you can also write the body on a single line (`class Account { + id : String + deposit() }`). The header accepts:\\n\\n- `title: \\\"…\\\"` — a heading drawn above the diagram.\\n- `direction: tb | bt | lr | rl` — rank direction, default `tb` (parents on top).\\n- `theme: …` — a theme override.\\n\\n---\\n\\n## 2. Classifiers\\n\\n```\\nclass Order\\n«interface» Repository\\n«enumeration» Status\\nabstract class Shape\\ndatatype Money\\nprimitive int\\n```\\n\\nThe five classifier kinds are `class`, `interface`, `enum` (alias `enumeration`), `datatype`, and `primitive`. A `«stereotype»` (or ASCII `<<stereotype>>`) renders above the name; `abstract class` (or the `{abstract}` annotation) renders the name in italics. Use `as` to give a display name that differs from the reference id: `class \\\"Order Service\\\" as OrderSvc`.\\n\\n---\\n\\n## 3. Members — attributes & operations\\n\\n```\\nclass Account {\\n + id : String\\n - balance : Money = 0\\n / available : Money\\n # owner : Customer\\n ~ region : String\\n + count : int {static}\\n + deposit(amount : Money) : void\\n + transfer(to : Account, amount : Money) : boolean {query}\\n}\\n```\\n\\n- **Visibility** glyphs: `+` public, `-` private, `#` protected, `~` package.\\n- `: Type` gives the attribute type or operation return type; `= value` a default; `[0..*]` a multiplicity; `/` a derived attribute.\\n- `{…}` annotations: `{static}` (renders underlined), `{abstract}` (italic operation), `{readOnly}`, `{query}`, `{ordered}`, …\\n- `name : Type`, `name: Type`, and Java-order `Type name` are all accepted and normalised to `name : Type`.\\n\\n**Enum literals** are bare names inside an `enum` body:\\n\\n```\\n«enumeration» Status {\\n ACTIVE\\n SUSPENDED\\n CLOSED\\n}\\n```\\n\\n---\\n\\n## 4. Relationships\\n\\n```\\nVehicle <|-- Car generalization (hollow triangle → parent)\\nShape <|.. Circle realization (dashed + hollow triangle → interface)\\nOrder *-- LineItem composition (filled diamond at the whole)\\nCustomer o-- Address aggregation (hollow diamond at the whole)\\nService --> Repository directed association (open arrow → target)\\nService ..> Logger dependency (dashed + open arrow → supplier)\\nA -- B plain association (no head)\\n```\\n\\nReversed forms are accepted and normalised (`Car --|> Vehicle` ≡ `Vehicle <|-- Car`). Whitespace around a connector is optional.\\n\\nWhen two or more children share one parent via generalization/realization, the heads are **tree-merged**: one trunk, one shared triangle, per-child legs.\\n\\n---\\n\\n## 5. Labels & multiplicity\\n\\n```\\nCustomer \\\"1\\\" o-- \\\"0..*\\\" Order : places\\n```\\n\\nA trailing `: label` names the association (drawn at the line midpoint). Quoted ends are multiplicities or role names: `\\\"1\\\"`, `\\\"0..1\\\"`, `\\\"*\\\"`, `\\\"1..*\\\"`. The source end is the left of the connector, the target end the right (after reversed-form normalisation).\\n\\n---\\n\\n## 6. Namespaces / packages\\n\\nGroup classifiers into a labelled containment frame:\\n\\n```\\numlclass\\nnamespace Platform {\\n namespace Auth {\\n class UserService {\\n + login()\\n }\\n }\\n namespace Data {\\n class Repository {\\n + find()\\n }\\n }\\n}\\nclass Gateway {\\n + route()\\n}\\nGateway --> UserService : delegates\\nGateway --> Repository : delegates\\n```\\n\\n- Blocks **nest** syntactically. Dot-notation auto-creates parents: `namespace Company.Engineering.Backend { … }` creates `Company` and `Company.Engineering` too.\\n- An explicit label: `namespace plat[\\\"Platform Layer\\\"] { … }`.\\n- Each package renders as a frame = the union of its members (and nested sub-frames) + padding + a top label. Namespace bodies must use newlines (one declaration per line).\\n\\n---\\n\\n## 7. Mermaid-compatibility forms\\n\\nFor one-line migration from Mermaid `classDiagram`:\\n\\n```\\nclassDiagram\\nclass Repository~T~ {\\n + findAll() List~T~\\n + cache : Map~String,List~int~~\\n + count$\\n + flush()*\\n}\\nRepository : <<service>>\\nRepository : + save(e : T) T\\n```\\n\\n- **Tilde-generics** `List~T~` → `List` (nesting supported: `Map~String,List~int~~` → `Map>`); also on class names (`class Box~T~`).\\n- **Single-line member**: `ClassName : +member` appends a member; `ClassName : <<interface>>` sets the kind/stereotype.\\n- **Member classifiers**: trailing `*` = abstract (italic), trailing `$` = static (underlined).\\n- **Space-return-type**: `getId() String` needs no colon.\\n\\nA lone leading `~` is still the package-visibility glyph; tilde-generics only convert balanced `~…~` pairs inside a type, so the two never collide.\\n\\n---\\n\\n## 8. Theming & accessibility\\n\\nAll strokes and fills come from theme tokens (no inline styles); CSS classes are prefixed `sx-umlclass-*`. Visibility renders as text glyphs (`+ - # ~`), never coloured icons — standard-faithful and monochrome-safe. Every diagram carries `<title>`/`<desc>` and `data-*` attributes (`data-id`, `data-kind`, `data-from`/`data-to`/`data-kind` on relationships, `data-package-id` on frames) for interactivity.\"\n },\n \"faulttree\": {\n \"title\": \"Fault Tree Analysis\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `faulttree` keyword (alias `fta`), an optional title, then a flat list of declarations wired by id:\\n\\n```\\nfaulttree \\\"Both pumps fail\\\"\\n analysis: cutsets, probability\\n top T \\\"Both redundant pumps fail\\\" = AND(PA, PB)\\n basic PA \\\"Pump A fails\\\" p: 0.01\\n basic PB \\\"Pump B fails\\\" p: 0.01\\n```\\n\\n`top` declares the single root event and the gate that produces it; `basic` declares a leaf component failure with a probability. The engine computes the minimal cut set `{PA, PB}` and P(top) = 1.0e-4. The DSL is **flat declaration + reference** (not nested by indentation) — a fault tree is a DAG, so a shared event is just referenced by id from several gates.\\n\\nHeader directives:\\n\\n- `analysis: cutsets, probability` — what to compute (also `pathsets`, `none`).\\n- `prob: rare | mcub | exact` — the probability method (default `rare`, a conservative upper bound).\\n- `layout: tb | bt` — top-down (default) or bottom-up.\\n\\n---\\n\\n## 2. Events\\n\\n```\\ntop T \\\"System fails\\\" = OR(A, B)\\ngate G1 \\\"Sub-fault\\\" = AND(A, B)\\nbasic A \\\"Component A fails\\\" p: 0.01\\nundeveloped EXT \\\"External fire (not modelled)\\\"\\nhouse HX \\\"Power on\\\" state: 1\\n```\\n\\n- **`top`** — the one undesired event being analysed (rectangle, emphasised border). Exactly one is required.\\n- **`gate`** — an intermediate event that is itself a gate output (rectangle).\\n- **`basic`** — a primary component failure, the leaf that carries `p:` (circle).\\n- **`undeveloped`** — an event not developed further (diamond); may carry `p:`.\\n- **`house`** — a normally-expected event forced `state: 0` or `state: 1` (house glyph) — switches branches of the tree on/off.\\n\\nProbabilities accept decimals or scientific notation (`p: 0.004` or `p: 1e-6`); `p:` and `prob:` are interchangeable. An event with no probability is treated symbolically (cut sets still computed; P(top) reported as n/a).\\n\\n---\\n\\n## 3. Gates\\n\\n```\\ntop T1 = AND(A, B, C) # all inputs occur\\ntop T2 = OR(A, B) # at least one input occurs\\ntop T3 = XOR(A, B) # exactly one (treated as OR for cut sets)\\ntop T4 = VOTING(2/3; A, B, C) # at least k of n\\ngate G1 = INHIBIT(A) if COND # A occurs AND the condition holds\\ngate G2 = PAND(A, B) order: A, B # A then B (order rendered, AND for cut sets)\\n```\\n\\nGates are drawn **output-up, inputs-down** (the mirror of a `logic` gate): AND is a flat-bottomed dome, OR/XOR/VOTING a shield, INHIBIT a hexagon. The conditioning event of an `INHIBIT`/`PAND` renders as an ellipse to the side. A gate may reference another gate or any event — and the same basic event may feed several gates (a repeated event).\\n\\n---\\n\\n## 4. Computed cut sets & probability\\n\\nThis is the differentiator. With `analysis: cutsets`, the engine runs **MOCUS**: AND gates grow the order of a cut set, OR gates multiply the number of cut sets, then idempotence (`A∧A=A`) and absorption (`X ⊆ Y ⇒ drop Y`) minimise the result.\\n\\n- Each **minimal cut set** is boxed in red; an **order-1 cut set is a single point of failure** (strongest red, `data-spof`).\\n- A **repeated event** (one basic event under several gates) is handled by absorption — the case a naive expander gets wrong.\\n- **P(top)** is computed from per-event probabilities: `rare` (Σ cut-set probs, default), `mcub` (1 − ∏(1−P)), or `exact` (inclusion-exclusion, which correctly de-duplicates a shared event). The method is shown next to the top event and noted in `<desc>`.\\n- A `house state: 0` can make the top event unsatisfiable — reported as \\\"no cut sets.\\\"\\n\\n---\\n\\n## 5. Repeated events\\n\\n```\\nfaulttree \\\"Safety function fails\\\"\\n analysis: cutsets, probability\\n prob: exact\\n top T \\\"Safety function fails\\\" = OR(C1, C2)\\n gate C1 \\\"Channel 1\\\" = AND(S1, L1)\\n gate C2 \\\"Channel 2\\\" = AND(S2, L1)\\n basic S1 \\\"Sensor 1 fails\\\" p: 0.05\\n basic S2 \\\"Sensor 2 fails\\\" p: 0.05\\n basic L1 \\\"Shared logic solver fails\\\" p: 0.05\\n```\\n\\n`L1` feeds both channels — it is drawn once per reference with a shared-event mark, but the cut-set engine treats every instance as one Boolean variable. Cut sets are `{S1, L1}` and `{S2, L1}`; `prob: exact` subtracts the overlap (L1 counted once over the union), giving 0.004875 rather than the rare-event 0.005.\\n\\n---\\n\\n## 6. Transfers\\n\\n```\\ngate OVP \\\"Sustained over-pressure\\\" = INHIBIT(PUMP) if HEATER\\ntransfer OVP -> \\\"OVP-detail\\\"\\n```\\n\\nA `transfer ID -> \\\"name\\\"` draws the transfer-out triangle below an event whose development lives elsewhere; a matching `transfer \\\"name\\\" = gate_expr` defines that named subtree and is spliced in for cut-set computation. v0.1 resolves transfers in-document.\\n\\n---\\n\\n## 7. Validation\\n\\nThe parser fails fast with readable errors so the cut-set math is meaningful:\\n\\n- exactly one `top` is required (zero or several is an error);\\n- a gate referencing an undeclared id reports the id by name;\\n- cycles are rejected (a fault tree is a DAG);\\n- a probability outside `[0, 1]`, a `VOTING k/n` with `k > n` or `n ≠ input count`, or an `if` condition on a non-INHIBIT/PAND gate are all reported in plain English.\\n\\n---\\n\\n## 8. Theming\\n\\n`default` uses the house palette — soft slate-blue event boxes, **green gates** (\\\"logic proceeds\\\"), **red cut-set boxes** (the computed risk), blue probability numerals, a yellow house. `monochrome` reproduces the NUREG-0492 black-and-white textbook look, where the dome/shield shape (not colour) carries the gate type. All strokes/fills come from `ReliabilityTokens`; every element carries `data-*` (`data-cutset`, `data-spof`, `data-prob`, `data-gate`) so the computed analysis is inspectable downstream.\"\n },\n \"bowtie\": {\n \"title\": \"Bowtie Risk Diagram\",\n \"content\": \"## 1. Your first diagram\\n\\nEvery document starts with the `bowtie` keyword, an optional title, then the hazard, the top event, and the two wings:\\n\\n```\\nbowtie\\ntopevent \\\"Loss of containment\\\"\\nthreat \\\"Corrosion\\\"\\n prevent \\\"Inspection programme\\\"\\nconsequence \\\"Release to atmosphere\\\"\\n mitigate \\\"Gas detection + ESD\\\"\\n```\\n\\n`topevent` declares the single knot at the centre (mandatory, exactly one). Each `threat` starts a left-wing line; each `consequence` ends a right-wing line. A barrier under a `threat` is **preventative** (`prevent`); under a `consequence` it is **mitigative** (`mitigate`). The diagram is laid out symmetrically about the knot — threats fan in from the left, consequences fan out to the right.\\n\\nThe DSL is **indentation-structured** and mirrors the CCPS 7-step build methodology: identify the hazard → the top event → the threats → the consequences → the preventative barriers → the mitigative barriers → the escalation factors.\\n\\nHeader directives (any order):\\n\\n- `layout: symmetric | compact` — band model (default `symmetric`).\\n- `legend: on | off | bottom | top` — the auto-derived colour legend (default on).\\n\\n---\\n\\n## 2. Hazard and top event\\n\\n```\\nhazard \\\"Working at height\\\"\\ntopevent \\\"Person falls from height\\\"\\n```\\n\\n- **`hazard`** — the operation or material with the potential to cause harm: the *context* the bowtie is about (e.g. \\\"Working at height\\\", \\\"Hydrocarbon under pressure\\\"). Optional; renders as a header box above the knot with a tie-line down to it. At most one.\\n- **`topevent`** — the moment control of the hazard is **lost** (e.g. \\\"Loss of containment\\\", \\\"Person falls from height\\\"). The knot of the bowtie, drawn as a green circle. **Mandatory, exactly one.**\\n\\nA hazard is a *thing/activity*, not a failure; the top event is the precise moment of *loss of control* — not a cause, and not yet a consequence.\\n\\n---\\n\\n## 3. Threats and consequences\\n\\n```\\nthreat \\\"Guardrail removed for access\\\"\\n prevent \\\"Permit-to-work system\\\"\\n\\nconsequence \\\"Fatality\\\"\\n mitigate \\\"Fall-arrest harness + lanyard\\\"\\n```\\n\\n- A **threat** is a credible cause that, *on its own*, could trigger the top event. Each threat is the start of one left-wing line, drawn as an orange box on the left edge.\\n- A **consequence** is a credible outcome *of the top event* (not of the threat), drawn as a red box on the right edge.\\n\\nThreats and consequences may be declared in any interleaved order — the parser groups all left-wing blocks and all right-wing blocks regardless of sequence. A bowtie needs **at least one of each**: a one-wing diagram is a fault tree (see `faulttree`) or an event tree, not a bowtie.\\n\\n---\\n\\n## 4. Barriers (the controls in between)\\n\\n```\\nthreat \\\"Guardrail removed for access\\\"\\n prevent \\\"Permit-to-work system\\\"\\n prevent \\\"Temporary edge protection\\\"\\n prevent \\\"Spotter / banksman\\\"\\n```\\n\\nA **barrier** is a control that interrupts the threat → top-event path (preventative) or reduces the consequence after the top event (mitigative). Each is a grey box *on the line*. Chains are free length (1..n) — the wing simply extends.\\n\\n**Barrier order is declaration order**: the first declared is the **outermost** (closest to the threat/consequence, the first line of defence); the last declared is the **innermost** (closest to the knot). This matches the left-to-right reading of a real bowtie. Each barrier carries `data-order` (0 = outermost) and `data-side` (`prevent` / `mitigate`) for downstream interactivity.\\n\\nWhen chains differ in length, barriers are **centre-anchored**: the innermost barriers align in a neat column near the knot, and the threat/consequence boxes are ragged by chain depth — reading as defence-in-depth.\\n\\n---\\n\\n## 5. Escalation factors\\n\\n```\\nthreat \\\"Corrosion\\\"\\n prevent \\\"UT thickness inspection\\\"\\n escalation \\\"Inspection interval too long\\\"\\n barrier \\\"Risk-based inspection scheme\\\"\\n```\\n\\nAn **escalation factor** (or degradation factor) is a condition that *degrades a specific barrier's effectiveness* — e.g. \\\"Edge protection not inspected\\\", \\\"Operator fatigue\\\". It attaches to **one** barrier (not to the line) and drops vertically below it as an amber box, joined by a muted \\\"degrades\\\" connector.\\n\\nAn **escalation-factor barrier** is a control placed on the escalation factor itself — it protects the barrier from being degraded (e.g. a pre-use inspection regime). It nests one level deeper, under the escalation factor, and renders as a grey box below it.\\n\\nIndentation binds the nesting: `prevent`/`mitigate` at 2 spaces, `escalation` at 4, `barrier` at 6.\\n\\n---\\n\\n## 6. Correct by construction (the barrier rule set)\\n\\nBefore it draws a single shape, the engine validates the structural half of the CCPS/EI barrier rule set and **refuses to render** on failure — exactly as `prisma` refuses missing counts:\\n\\n- **Exactly one top event** — zero or several is an error.\\n- **Every threat has ≥ 1 preventative barrier** — a bare threat is a Swiss-cheese cartoon, not a bowtie.\\n- **Every consequence has ≥ 1 mitigative barrier** — the mirror rule.\\n- **Every escalation factor is attached to a barrier** — it cannot float on a line or on the top event.\\n- **At least one threat and one consequence** — a one-wing diagram is an FTA or an ETA.\\n\\nMessages name the offending element and the rule in plain English, e.g. *\\\"Threat 'Corrosion' has no preventative barrier — every threat must reach the top event through at least one barrier (CCPS/EI barrier rule). Add a `prevent` line under it.\\\"* This is what separates a real bowtie from a doodle. The engine does **not** judge whether a barrier is truly *effective* or *independent* — that is the analyst's qualitative judgement.\\n\\n---\\n\\n## 7. Bowtie vs fault tree\\n\\nA fully-developed bowtie *is* a fault tree glued to an event tree at the top event: the left wing read backwards is the fault tree whose top event is the bowtie's knot, and the right wing is the event tree that propagates it into consequences. Schematex keeps them as two engines because their use differs:\\n\\n- **`bowtie`** is qualitative and symmetric — the barrier inventory and the at-a-glance defence-in-depth story; no probability arithmetic.\\n- **`faulttree`** is quantitative and Boolean — AND/OR gates, basic-event probabilities, minimal cut sets, a probability rollup.\\n\\nWhere you want the gate-level detail behind a single threat, draw a separate `faulttree`.\\n\\n---\\n\\n## 8. Theming\\n\\n`default` uses the recognised BowTieXP / bowtiemaster palette — **orange threats** (left), **grey barriers** on the line, a **green top-event disc** (centre knot), **red consequences** (right), **amber escalation factors** dropping below — mapped onto Schematex's semantic slots so it stays coherent with `prisma` / `pert` / `petri`. `monochrome` reproduces the regulator-print black-and-white look, where element distinction rides on shape/border + position (escalation factors get a dashed border, the knot a doubled ring) rather than colour. `dark` follows Catppuccin Mocha. All strokes/fills come from `BowtieTokens`; every element carries `data-*` (`data-role`, `data-side`, `data-line`, `data-order`, `data-barrier`) so the structure is inspectable downstream.\"\n },\n \"eventtree\": {\n \"title\": \"Event Tree Analysis\",\n \"content\": \"## 1. Your first event tree\\n\\nEvery document starts with the `eventtree` keyword (alias `eta`), an optional title, then a flat list of declarations:\\n\\n```\\neventtree \\\"Smoke detector demand\\\"\\n initiating FIRE \\\"Fire starts\\\" freq: 0.01\\n function D \\\"Detector actuates\\\" p: 0.02\\n function S \\\"Suppression works\\\" p: 0.05\\n outcome s s -> \\\"Controlled\\\"\\n outcome s f -> \\\"Damage, contained\\\"\\n outcome f * -> \\\"Uncontrolled fire\\\"\\n```\\n\\n- **`initiating ID \\\"label\\\" freq: N`** — exactly one. The challenge frequency, accepting decimals or scientific notation (`freq: 0.01` or `freq: 1e-4`).\\n- **`function ID \\\"label\\\" p: N`** — one per branch column, **declared left→right in query order**. `p:` is the **failure** probability; the engine derives the success leg as its complement `1 − p` (you never state both).\\n- **`outcome <pattern> -> \\\"end state\\\"`** — one realised leaf each.\\n\\n---\\n\\n## 2. The s / f / * outcome pattern\\n\\nEach `outcome` row reads left→right over the function columns:\\n\\n```\\noutcome s s s -> \\\"OK\\\" # every function succeeds\\noutcome s s f -> \\\"Late release\\\" # C fails on the last query\\noutcome s f * -> \\\"Early release\\\"# B fails; C is never queried (pruned)\\noutcome f * * -> \\\"Core damage\\\" # A fails; path terminates immediately\\n```\\n\\n- **`s`** — success leg (upper branch).\\n- **`f`** — failure leg (lower branch).\\n- **`*`** — pruned: the path is not queried here, it runs flat to its leaf.\\n\\nThis is how an event tree avoids being a full balanced 2ⁿ tree: once a function failure makes later questions moot, you write `*` and the sequence terminates early. Two hard rules: a pattern may not be **longer** than the column count, and **once a column is pruned (`*`) every later column must also be `*`** — a path that has terminated cannot resume querying.\\n\\n---\\n\\n## 3. Computed path frequencies & outcomes\\n\\nThis is the differentiator. With the failure probabilities and `freq`, the engine computes:\\n\\n- **Each path frequency** = `f₀ · ∏ branch-probabilities` along its `s`/`f` legs (success legs contribute `1 − p`, failure legs `p`).\\n- **Outcome roll-up**: outcomes with the same end-state label are summed across every path that reaches them (every `\\\"Core damage\\\"` leaf adds up).\\n- **The dominant sequence** — the largest-frequency path — gets the reserved-red accent, the ETA analogue of the fault tree's single point of failure.\\n\\nEvery leaf carries `data-*` (`data-freq`, `data-outcome`) so the computed numbers are inspectable downstream.\\n\\n---\\n\\n## 4. Common mistakes\\n\\n```\\n# WRONG — function with no failure probability\\nfunction A \\\"ECCS\\\"\\n\\n# WRONG — querying after a pruned column (path already terminated)\\noutcome * s -> \\\"bad\\\"\\n\\n# WRONG — more tokens than declared columns\\nfunction A p: 0.1\\noutcome s s -> \\\"ok\\\"\\n\\n# WRONG — initiating event with no frequency\\ninitiating LOCA \\\"Large LOCA\\\"\\n```\\n\\nEach is rejected with a plain-English message naming the line. State `p:` as a **failure** probability (small), give the initiating event a `freq:`, keep prunes trailing, and you are correct by construction.\\n\\n---\"\n },\n \"fmea\": {\n \"title\": \"FMEA Worksheet\",\n \"content\": \"## 1. Your first worksheet\\n\\nEvery document starts with `fmea`, an optional title, optional directives, then a **nested** failure chain. Structure comes from the keyword, not the indent depth:\\n\\n```\\nfmea \\\"Pump DFMEA\\\"\\n item \\\"Impeller\\\" fn \\\"Move fluid\\\"\\n mode \\\"No flow\\\"\\n effect \\\"Process stops\\\" sev: 8\\n cause \\\"Impeller wear\\\" occ: 4\\n controls detection: \\\"Flow sensor\\\" det: 5\\n```\\n\\n- **`item \\\"name\\\" fn \\\"function\\\"`** — a part and the function it delivers. `fn` is optional.\\n- **`mode \\\"failure mode\\\"`** — how that function fails. An item may hold several.\\n- **`effect \\\"consequence\\\" sev: 1..10`** — what the failure causes; carries its own **Severity**. A mode may have several (the engine uses the *worst* for every row of that mode).\\n- **`cause \\\"root cause\\\" occ: 1..10`** — why it happens; carries **Occurrence**.\\n- **`controls prevention: \\\"…\\\", detection: \\\"…\\\" det: 1..10`** — current controls and the **Detection** rating they earn. With no control, Detection defaults to **10** (undetectable).\\n\\nAll three ratings are integers 1–10; anything outside that range is rejected.\\n\\n---\\n\\n## 2. Header directives\\n\\n```\\ntype: design # design (dfmea) | process (pfmea) | msr\\nrank: ap # ap (default) | rpn — the sort/priority key\\nflag: ap >= High # or `rpn > 100` — highlight rows over a threshold\\nnumber: FMEA-2026-014 # free metadata: number/team/author/date/revision/dept/process/product\\n```\\n\\n`rank` chooses how rows are prioritised; `flag` highlights the rows that breach a threshold (`ap >= High` / `ap == High`, or `rpn > 100` / `rpn >= 120`).\\n\\n---\\n\\n## 3. Computed RPN & Action Priority\\n\\nThis is the differentiator. From the nested AST the engine:\\n\\n1. **Flattens** to one row per (item, mode, cause); the mode's worst effect severity governs every row of that mode.\\n2. **RPN = S × O × D** (1–1000).\\n3. **Action Priority** by the AIAG-VDA band structure — **Severity is the primary axis**, Occurrence second, Detection third. S = 9–10 (safety/regulatory) is High for *every* O and D; mid-severity degrades High→Medium→Low as Occurrence falls.\\n4. **Sorts** by the chosen key. For `ap`: High > Medium > Low, tie-broken by Severity then RPN — *never* RPN alone, which would re-introduce the bug AP was designed to fix.\\n5. **Flags** rows over the threshold.\\n\\nEach row carries `data-rpn` and `data-ap` so the computed priority is inspectable.\\n\\n---\\n\\n## 4. After-action follow-up\\n\\nRecord corrective actions and the revised ratings to show the before/after delta:\\n\\n```\\nfmea \\\"Brake DFMEA\\\"\\n item \\\"MC\\\"\\n mode \\\"Seal leak\\\"\\n effect \\\"Loss of braking\\\" sev: 9\\n cause \\\"Degradation\\\" occ: 3 det: 4\\n action \\\"Seal leak\\\" / \\\"Degradation\\\"\\n do: \\\"Upgrade seal to EPDM\\\" owner: \\\"J. Lee\\\" target: 2026-Q3\\n revised sev: 9 occ: 1 det: 4\\n```\\n\\n`action \\\"Mode\\\" / \\\"Cause\\\"` targets a chain by its quoted mode and (optional) cause; `do:` is the recommendation; `revised sev/occ/det` recomputes the after-action RPN and AP so the engine reports the risk reduction.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — rating out of the 1..10 band\\neffect \\\"Leak\\\" sev: 11\\n\\n# WRONG — mode before any item\\nmode \\\"orphan mode\\\"\\n\\n# WRONG — effect before any mode\\nitem \\\"x\\\"\\n effect \\\"e\\\" sev: 3\\n```\\n\\nRatings must be integers 1–10; the failure chain must nest `item → mode → effect/cause`; out-of-order keywords are rejected by name. Detection silently defaults to 10 if no control rates it — state `det:` (on the cause or its `controls`) when you have a detection control.\\n\\n---\"\n },\n \"causalloop\": {\n \"title\": \"Causal Loop Diagram\",\n \"content\": \"## 1. Your first causal loop\\n\\nStart with the `causalloop` keyword (alias `cld`), an optional title, then **signed links**. Variables are auto-created from the links — you rarely declare them:\\n\\n```\\ncausalloop \\\"Adoption model\\\"\\n\\\"Adoption rate\\\" -> Adopters : +\\nAdopters -> \\\"Adoption rate\\\" : +\\nloop R1 \\\"Word of mouth\\\"\\n```\\n\\nA link is `SOURCE -> TARGET : POLARITY`. Multi-word variable names are quoted (`\\\"Adoption rate\\\"`); single words need no quotes (`Adopters`). At least one link is required.\\n\\n---\\n\\n## 2. Link polarity\\n\\nPolarity is the sign of the causal influence and is **mandatory** on every link:\\n\\n```\\nA -> B : + # same direction (more A → more B)\\nB -> C : - # opposite direction (more B → less C)\\nA -> B : s # alias for + (same)\\nB -> C : o # alias for − (opposite)\\nC -> D : same # alias for +\\nD -> E : opposite # alias for −\\nA -> B + # the colon is optional\\n```\\n\\n`+` / `s` / `same` mean *same direction*; `−` / `o` / `opposite` mean *opposite*. A link with no polarity is rejected.\\n\\n---\\n\\n## 3. Delays and explicit variables\\n\\n```\\n\\\"Training quality\\\" -> \\\"Salesperson skills\\\" : + delay # marked delay (∥ hash on the arrow)\\nA -> B : + ~delay # the ~delay form also works\\nvar \\\"Adoption rate\\\" # pin a variable so it isn't auto-created\\nloop R1 \\\"Word of mouth\\\" # name/annotate a loop\\n```\\n\\n- **`delay`** / **`~delay`** marks a link as delayed (the system-dynamics hash mark).\\n- **`var \\\"name\\\"`** declares a variable explicitly (fixes its label; not auto-created).\\n- **`loop ID \\\"phrase\\\"`** attaches a human-readable name to a loop the engine detects.\\n\\n---\\n\\n## 4. Computed feedback loops\\n\\nThis is the differentiator. The engine:\\n\\n1. Builds the **signed directed graph** (nodes = variables, edges = signed links).\\n2. Enumerates **every elementary feedback loop** (simple directed cycle) with Johnson's algorithm — deterministically, in declaration order.\\n3. **Classifies** each loop by counting negative links:\\n - **even** count (including 0) → **R** (reinforcing); product of signs = +1\\n - **odd** count → **B** (balancing); product of signs = −1\\n\\nThis is exactly Sterman's even/odd rule. Loops are numbered in detection order by kind (R1, B1, R2…) and drawn with their `R`/`B` rotation glyph at the loop centre. Each loop carries `data-loop` and `data-kind`.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — link with no polarity\\nA -> B\\n\\n# WRONG — a diagram with no links at all\\ncld\\n```\\n\\nEvery link needs a polarity (`: +` or `: -`); a CLD with no links is rejected. Remember polarity is about *direction of change*, not desirability — a link from \\\"deaths\\\" to \\\"population\\\" is still `-` (more deaths → less population) even though deaths are bad.\\n\\n---\"\n },\n \"markov\": {\n \"title\": \"Markov Chain\",\n \"content\": \"## 1. Your first chain\\n\\nStart with the `markov` keyword (alias `markovchain`), an optional title, then **probability-weighted transitions**. States are auto-created from the first arc that mentions them:\\n\\n```\\nmarkov \\\"Weather\\\"\\n Sunny -> Sunny : 0.9\\n Sunny -> Rainy : 0.1\\n Rainy -> Sunny : 0.5\\n Rainy -> Rainy : 0.5\\n```\\n\\nA transition is `FROM -> TO : PROBABILITY`. A self-loop (`Sunny -> Sunny`) is the probability of staying put. Every probability must be in `[0, 1]`, and **the probabilities leaving each state must sum to 1**.\\n\\n---\\n\\n## 2. Declaring states\\n\\nYou can declare states explicitly to fix label, order, or mark them absorbing:\\n\\n```\\nmarkov \\\"Gambler's ruin\\\"\\n state Broke \\\"$0\\\" absorbing\\n state Rich \\\"$4\\\" absorbing\\n state S1\\n state S2\\n Broke -> Broke : 1\\n Rich -> Rich : 1\\n S1 -> Broke : 0.5\\n S1 -> S2 : 0.5\\n S2 -> S1 : 0.5\\n S2 -> Rich : 0.5\\n```\\n\\n`state ID \\\"label\\\" absorbing` — the label is optional; `absorbing` asserts the state is a sink (a self-loop of probability 1). The engine cross-checks the assertion against the matrix.\\n\\n---\\n\\n## 3. Directives\\n\\n```\\nlayout: layered # layout mode\\nnormalize: true # scale each row to sum to 1 instead of hard-erroring\\nanalysis: classify, absorbing # what to compute: classify | absorbing | stationary\\n```\\n\\n- **`normalize: true`** rescales each row to sum to 1 (handy for unnormalised weights like `A -> B : 1`, `A -> C : 1`). Without it, a row that does not sum to 1 is a hard error.\\n- **`analysis:`** selects which computations to run and surface.\\n\\n---\\n\\n## 4. The computed answer\\n\\nThis is the differentiator. Three hand-written, dependency-free linear-algebra passes:\\n\\n1. **Matrix assembly + validation** — build P and enforce the row-sum policy (hard error, or rescale under `normalize`).\\n2. **State classification** — Tarjan SCC → communicating classes; a class is **recurrent** iff closed, **transient** otherwise; a closed singleton with a probability-1 self-loop is **absorbing**.\\n3. **The quantitative answer**:\\n - **Stationary distribution** π (πP = π, Σπ = 1) by power iteration with an exact Gaussian-elimination fallback for periodic chains.\\n - For **absorbing chains**: the fundamental matrix N = (I−Q)⁻¹, absorption probabilities B = N·R, and expected steps to absorption t = N·1.\\n\\nTransient states, recurrent classes, and absorbing states are rendered distinctly; computed values are carried in `data-*`.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — probability outside [0,1]\\nA -> B : 1.5\\n\\n# WRONG — transition with no probability\\nA -> B\\n\\n# WRONG — rows that don't sum to 1 (without `normalize: true`)\\nA -> B : 0.3\\nA -> C : 0.3\\n```\\n\\nEvery transition needs a probability in `[0, 1]`; each state's outgoing probabilities must sum to 1, or you must set `normalize: true`. An empty chain (no transitions) is rejected.\\n\\n---\"\n },\n \"gitgraph\": {\n \"title\": \"Git Graph\",\n \"content\": \"## 1. Your first git graph\\n\\nStart with the `gitGraph` keyword (case-insensitive; a trailing colon is allowed), then one operation per line. The first commit lands on the main branch:\\n\\n```\\ngitGraph\\n commit\\n branch develop\\n checkout develop\\n commit id: \\\"feature work\\\"\\n checkout main\\n merge develop tag: \\\"v1.0\\\"\\n```\\n\\nEvery operation runs against the **currently checked-out branch**. `commit` appends to it; `branch` creates a new line from the current commit; `checkout` (alias `switch`) moves the cursor; `merge` brings another branch into the current one.\\n\\n---\\n\\n## 2. Operations\\n\\n```\\ncommit # plain commit on the current branch\\ncommit id: \\\"init\\\" # give the commit an explicit id\\ncommit tag: \\\"v0.1\\\" # attach a release tag\\ncommit type: HIGHLIGHT # NORMAL (default) | HIGHLIGHT | REVERSE\\nbranch develop # fork a branch from the current commit\\nbranch hotfix order: 3 # pin its lane order\\ncheckout develop # switch the cursor (alias: switch)\\nmerge develop tag: \\\"v1.0\\\" # merge a branch into the current one\\ncherry-pick id: \\\"abc\\\" # copy a commit onto the current branch\\n```\\n\\n- **`commit`** takes optional `id:`, `tag:`, and `type:` (`NORMAL` / `HIGHLIGHT` / `REVERSE`).\\n- **`branch NAME`** takes an optional `order:` to control lane placement.\\n- **`checkout` / `switch`** are interchangeable.\\n- **`cherry-pick id:`** copies a commit; an optional `parent:` disambiguates a merge commit.\\n\\n---\\n\\n## 3. Orientation\\n\\nThe graph defaults to left-to-right. Set the direction inline on the header:\\n\\n```\\ngitGraph TB:\\n commit\\n branch feature\\n checkout feature\\n commit\\n checkout main\\n merge feature\\n```\\n\\n`LR` (default), `TB`, and `BT` are accepted. Config can also be supplied via a leading `%%{init: {'gitGraph': {...}}}%%` directive or a YAML frontmatter `config:` block for Mermaid compatibility (`mainBranchName`, `showCommitLabel`, `rotateCommitLabel`).\\n\\n---\\n\\n## 4. How the engine lays it out\\n\\nMermaid-compatibility is the differentiator, but the layout is the work:\\n\\n- The operation list is **replayed in order** to build the commit DAG and assign each commit to its branch lane.\\n- Branch lanes are ordered by appearance (overridable with `order:`); merge connectors are routed from the merged branch's tip to the new merge commit.\\n- Commit nodes are styled by `type:` — a HIGHLIGHT commit is emphasised, a REVERSE commit marked — and tags render as flags. Cherry-picks draw a dashed copy edge to the source.\\n\\nEvery commit carries `data-*` (branch, id, type) for downstream interaction.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — no gitGraph header\\ncommit\\ncommit\\n\\n# WRONG — unknown operation\\ngitGraph\\n rebase main\\n\\n# WRONG — unknown commit type\\ngitGraph\\n commit type: SQUASH\\n```\\n\\nThe document must start with `gitGraph`; only `commit` / `branch` / `checkout` / `switch` / `merge` / `cherry-pick` are valid operations; `type:` must be `NORMAL`, `HIGHLIGHT`, or `REVERSE`. `%%` starts a comment, matching Mermaid.\\n\\n---\"\n },\n \"epc\": {\n \"title\": \"EPC (Event-driven Process Chain)\",\n \"content\": \"## 1. Your first EPC\\n\\nStart with the `epc` keyword, an optional title, then declare **nodes by id** and **wire them with arrows**:\\n\\n```\\nepc \\\"Order fulfilment\\\"\\n event E1 \\\"Order received\\\"\\n function F1 \\\"Check credit\\\"\\n event E2 \\\"Credit OK\\\"\\n E1 -> F1 -> E2\\n```\\n\\nNodes carry an id and an optional quoted label; arrows reference ids. The canonical form declares connectors as nodes (`xor X1`) and wires everything by id — closest to how ARIS stores an EPC.\\n\\n---\\n\\n## 2. Node kinds\\n\\n```\\nevent E1 \\\"Order received\\\" # passive state (rounded hexagon)\\nfunction F1 \\\"Check credit\\\" # active task (rounded rectangle); alias: func\\nfunc F2 \\\"Send invoice\\\" # `func` is shorthand for `function`\\nand A1 # AND connector (∧)\\nor O1 # OR connector (∨)\\nxor X1 # exclusive-OR connector (×)\\n```\\n\\nA connector fans either way (split or join) depending on its incoming/outgoing arcs, so the same glyph serves both. Connector labels are optional.\\n\\n---\\n\\n## 3. Wiring control flow\\n\\n```\\nE1 -> F1 -> X1 # a chain is sugar for the pairwise arcs E1→F1, F1→X1\\nX1 -> E2 # connector split into two branches\\nX1 -> E3\\nF2 -> E2 : sent # a single arc may carry a ': label'\\n```\\n\\n- A `->` **chain** expands to pairwise edges.\\n- A trailing **`: label`** annotates a single arc.\\n- An arrow endpoint not yet declared is **auto-created** (and flagged by the validator), so you can sketch fast and clean up later.\\n\\n```\\nepc \\\"Procure-to-pay\\\"\\n layout: tb\\n event E1 \\\"Need identified\\\"\\n function F1 \\\"Create PO\\\"\\n and A1\\n function F2 \\\"Notify supplier\\\"\\n function F3 \\\"Update budget\\\"\\n E1 -> F1 -> A1\\n A1 -> F2\\n A1 -> F3\\n```\\n\\n`layout: tb` lays the chain top-to-bottom (default is also vertical-friendly).\\n\\n---\\n\\n## 4. Computed well-formedness\\n\\nThis is the differentiator. The engine validates (flags, doesn't throw):\\n\\n1. **Bipartite alternation** — events and functions strictly alternate along any path; connectors don't break it.\\n2. **Start/end must be events** — a function may not be a start or end node.\\n3. **Signature rule** — an *event must not be the source of an OR/XOR split* (a passive event cannot decide); an AND-split after an event is allowed.\\n4. **Split/join balancing** — a split of type T should be closed by a join of type T; mismatches are warnings (real EPCs are sometimes unbalanced).\\n5. **Single-in / single-out** per event and function — connectors carry the multiplicity.\\n6. **Reachability** — every node reachable from a start and reaching an end.\\n\\nOffending nodes are highlighted with `data-*` flags; the diagram still renders.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — invalid id (must start with a letter)\\nevent 9bad\\n\\n# AVOID — redeclaring a node (the first wins, a warning is raised)\\nevent E1 \\\"first\\\"\\nevent E1 \\\"second\\\"\\n```\\n\\nIds must start with a letter; a redeclared node keeps the first definition and warns. Because event→XOR/OR splits are flagged, route a decision through a **function** that produces the decision, then split.\\n\\n---\"\n },\n \"idef0\": {\n \"title\": \"IDEF0 Function Model\",\n \"content\": \"## 1. Your first IDEF0 diagram\\n\\nStart with the `idef0` keyword, an optional title, an optional `node` (the diagram's node number), then **function boxes** and their **ICOM arrows**:\\n\\n```\\nidef0 \\\"Fill order\\\"\\nfunction A1 \\\"Receive order\\\"\\ninput A1 \\\"Customer request\\\"\\ncontrol A1 \\\"Order policy\\\"\\nmechanism A1 \\\"Order clerk\\\"\\noutput A1 \\\"Confirmed order\\\"\\n```\\n\\n`function ID \\\"name\\\"` declares a box (in declaration order). `node A0` sets the parent node number used to derive child node numbers (A0 → A1..An). FIPS guidance is 3–6 boxes per diagram; outside that range the engine warns.\\n\\n---\\n\\n## 2. ICOM boundary arrows\\n\\nEach keyword pins an arrow to a specific side of a box, and that *is* its role:\\n\\n```\\ninput A1 \\\"Sales orders\\\" # enters the LEFT edge\\ncontrol A1 \\\"Production schedule\\\" # enters the TOP edge (governs the activity)\\noutput A1 \\\"Product\\\" # leaves the RIGHT edge\\nmechanism A1 \\\"CNC machines\\\" # enters the BOTTOM edge (the resource)\\n```\\n\\n`input`, `control`, and `mechanism` route from the diagram frame **into** the box; `output` routes from the box **out** to the frame. The engine codes these boundary arrows down each edge (I1, I2 / C1 / O1 / M1).\\n\\n---\\n\\n## 3. Flow arrows between boxes\\n\\nA `->` arrow connects two boxes; by default it lands on the target's **input**, but you can name the target's ICOM side:\\n\\n```\\nA1 -> A2 \\\"Work plan\\\" # box→box; defaults to A2's input\\nA2 -> A3.control \\\"Parts spec\\\" # land on A3's control (top) edge\\ninput A2 \\\"Raw material\\\" (tunnel) # (tunnel) hides the arrow at this level\\n```\\n\\n- `target.control` / `target.input` / `target.mechanism` picks the landing side.\\n- A flow **cannot land on the target's `.output`** — an output leaves a box, it does not enter one.\\n- `(tunnel)` marks a tunnelled arrow (suppressed on the parent/child diagram per FIPS).\\n\\n---\\n\\n## 4. Computed structural enforcement\\n\\nThis is the differentiator — what makes the model correct where a drawing tool is not:\\n\\n1. **ICOM placement enforcement** — the role is resolved against the box's geometry side; a malformed role, or a flow asked to *enter* a box via `.output`, is rejected.\\n2. **Reference resolution** — every box id named by an arrow must be declared.\\n3. **Decomposition numbering** — boxes get contiguous box numbers 1..n (lower-right corner) and node numbers (A0 → A1..An); explicit `#N` numbers are checked for contiguity, range, and duplicates.\\n4. **Boundary coding** — boundary arrows are coded I1/C1/O1/M1 down each edge.\\n5. **Box-count guideline** — fewer than 3 or more than 6 boxes raises a FIPS-183 warning.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — no idef0 header\\nfunction A1 \\\"x\\\"\\n\\n# WRONG — a flow landing on the target's output\\nA1 -> A2.output \\\"bad\\\"\\n\\n# WRONG — an unknown ICOM side word\\nA1 -> A2.sideways \\\"bad\\\"\\n```\\n\\nThe document must start with `idef0`; arrows may target `.input` / `.control` / `.mechanism` only; every referenced box id must be declared. Because the keyword encodes the side, you cannot accidentally draw a control as an input — the standard is enforced, not suggested.\\n\\n---\"\n },\n \"threatmodel\": {\n \"title\": \"Threat Model (STRIDE DFD)\",\n \"content\": \"## 1. Your first threat model\\n\\nStart with the `threatmodel` keyword (alias `stride`), an optional title, then **declare elements** and **wire flows**:\\n\\n```\\nthreatmodel \\\"Login flow\\\"\\nexternal: User\\nprocess 1.1: Web Server\\ndatastore D1: User DB\\nUser -> 1.1 : \\\"Login request\\\"\\n1.1 -> D1 : Lookup\\n```\\n\\nEach element is `kind: ID: Label` (or `kind: Label`, where the id is slugged from the label — `external: Mobile App` becomes id `Mobile_App`). A flow is `SOURCE -> TARGET : label`, and the **label is mandatory** (it names the data crossing).\\n\\n---\\n\\n## 2. Element kinds and flows\\n\\n```\\nexternal: User # external entity (the attacker's side)\\nprocess 1.1: Web Server # a process / service\\ndatastore D1: User DB # a data store\\ndatastore D2: Audit log # a log/audit store (gets conditional Repudiation)\\nUser -> 1.1 : \\\"HTTPS Request\\\" # directed flow, quoted or bare label\\n1.1 <-> D1 : Read/Write # <-> expands into two directed flows\\n```\\n\\n- Process ids are often dotted DFD numbers (`1.1`, `2.3`); external/store ids are usually short slugs (`User`, `D1`).\\n- A `<->` flow expands into **two** directed flows.\\n- A store whose name/id matches `log|audit|journal` (or carries an explicit hint) is treated as a log store.\\n\\n**Flow rules** the engine enforces: no store→store flows (data stores are passive), no external→external flows, and every endpoint must be a declared element.\\n\\n---\\n\\n## 3. Trust boundaries\\n\\n```\\nboundary \\\"Internet\\\" { User }\\nboundary \\\"DMZ\\\" { 1.1 }\\nboundary \\\"Internal\\\" { D1, D2 }\\n```\\n\\n`boundary \\\"name\\\" { id, id, … }` groups elements into a trust zone. An element may belong to **at most one** boundary; members must be declared. Elements in no boundary share an implicit untrusted zone.\\n\\n---\\n\\n## 4. Computed STRIDE analysis\\n\\nThis is the differentiator. The engine applies the **STRIDE-per-element** mapping:\\n\\n| DFD element | Threats applied |\\n|-----------------|------------------------|\\n| External entity | S, R |\\n| Process | S, T, R, I, D, E |\\n| Data store | T, I, D (+ R if log) |\\n| Data flow | T, I, D |\\n\\n- The data-store **Repudiation** is conditional — added for log / audit / journal stores (the Shostack green \\\"?\\\").\\n- **Boundary crossing**: a flow whose endpoints sit in different trust zones is flagged, because that is where Spoofing / Tampering / Information-disclosure concentrate. Two elements in the same (or implicit) zone do not cross.\\n\\nEach element and flow carries its applicable STRIDE categories in `data-*` so the analysis is inspectable.\\n\\n---\\n\\n## 5. Common mistakes\\n\\n```\\n# WRONG — flow with no label\\nUser -> 1.1\\n\\n# WRONG — store to store (data stores are passive)\\nD1 -> D2 : x\\n\\n# WRONG — external to external\\nA -> B : x\\n\\n# WRONG — unknown flow endpoint\\nP -> Ghost : x\\n\\n# WRONG — an element in two boundaries\\nboundary \\\"A\\\" { P }\\nboundary \\\"B\\\" { P }\\n```\\n\\nEvery flow needs a label; stores and externals cannot be flow partners with their own kind; endpoints must be declared; an element belongs to at most one trust boundary. Duplicate ids are rejected.\\n\\n---\"\n }\n};\n","/**\n * Example library — runtime lookup over the bundled MDX examples.\n */\nimport { EXAMPLES, type GeneratedExample } from \"./_generated\";\n\nexport type Example = GeneratedExample;\n\nexport interface GetExamplesOptions {\n /** Maximum number of examples to return. Default 5. */\n limit?: number;\n /** Prefer examples marked `featured: true` when set. */\n preferFeatured?: boolean;\n /** Maximum complexity (1–5). */\n maxComplexity?: number;\n}\n\n/**\n * Normalise a diagram-registry type to the diagram key used in example\n * frontmatter. Most are identical; a few legacy keys differ.\n */\nfunction normaliseDiagramKey(type: string): string[] {\n // The frontmatter uses short keys like \"block\" while the plugin type is\n // \"blockdiagram\". Return all aliases to match on.\n switch (type) {\n case \"blockdiagram\":\n return [\"block\", \"blockdiagram\"];\n default:\n return [type];\n }\n}\n\nexport function getExamplesForType(\n type: string,\n opts: GetExamplesOptions = {}\n): Example[] {\n const keys = normaliseDiagramKey(type);\n const all = EXAMPLES.filter((e) => keys.includes(e.diagram));\n let filtered = all;\n const maxComplexity = opts.maxComplexity;\n if (typeof maxComplexity === \"number\") {\n filtered = filtered.filter((e) => e.complexity <= maxComplexity);\n }\n // Featured first when requested, then by complexity ascending.\n const sorted = [...filtered].sort((a, b) => {\n if (opts.preferFeatured) {\n if (a.featured !== b.featured) return a.featured ? -1 : 1;\n }\n return a.complexity - b.complexity;\n });\n const limit = opts.limit ?? 5;\n return sorted.slice(0, limit);\n}\n\nexport function listAllExampleSlugs(): string[] {\n return EXAMPLES.map((e) => e.slug);\n}\n","import type { DiagramType } from \"../core/types\";\n\n/**\n * Shared generation policy exposed to LLM-facing syntax callers.\n *\n * Parsers remain domain-specific and may accept imported dialects or aliases.\n * Generated DSL should stay on this smaller surface unless a caller asks for\n * reference syntax to reach an advanced feature.\n */\nexport const COMMON_GENERATION_RULES = [\n \"Generate one diagram document with one selected diagram type.\",\n \"Use the canonical header and canonical forms from the generation profile first.\",\n 'Use ASCII double quotes (\") for generated labels and titles.',\n \"Do not emit DSL comments unless the user explicitly asks for annotated source.\",\n \"Prefer explicit IDs and declarations when they make validation less ambiguous.\",\n \"Call validateDsl with the explicit selected type, fix reported errors, and validate again before returning DSL.\",\n] as const;\n\nexport interface GenerationProfile {\n /** Canonical type id from `listDiagrams()`. */\n type: DiagramType;\n /** First line form preferred for generated DSL. */\n header: string;\n /** Short name for the preferred authoring mode when a parser has several. */\n mode: string;\n /** Forms that cover most first-shot generations for this type. */\n forms: readonly string[];\n /** Short grammar choices the model should make by default. */\n prefer: readonly string[];\n /** Accepted adapters / advanced paths to avoid unless explicitly needed. */\n avoid: readonly string[];\n /** Validation or semantic reminders that prevent common failed renders. */\n repair: readonly string[];\n}\n\nconst PROFILES: Record<DiagramType, GenerationProfile> = {\n genogram: {\n type: \"genogram\",\n header: 'genogram \"Title\"',\n mode: \"family declarations + indented children\",\n forms: [\n \"personId [sex, birthYear, optionalAttrs]\",\n 'parentA -- parentB \"optional relationship label\"',\n \"indent children under the couple line\",\n ],\n prefer: [\"Declare people before emotional relationships.\", \"Use `[label: \\\"...\\\"]` only where the syntax reference shows a label attribute.\"],\n avoid: [\"Avoid inline comments and speculative relationship operators.\"],\n repair: [\"Unknown individuals usually need a declaration before the relationship line.\"],\n },\n ecomap: {\n type: \"ecomap\",\n header: 'ecomap \"Title\"',\n mode: \"center + external systems\",\n forms: [\n 'center: client [label: \"Client\"]',\n 'systemId [label: \"System\", category: family]',\n 'systemId === client [label: \"support\"]',\n ],\n prefer: [\"Declare exactly one center.\", \"Declare outside systems before their connection lines.\"],\n avoid: [\"Avoid borrowing genogram operators such as `--`.\"],\n repair: [\"A valid render with a missing center is semantically wrong; add `center:` first.\"],\n },\n pedigree: {\n type: \"pedigree\",\n header: 'pedigree \"Title\"',\n mode: \"clinical pedigree\",\n forms: [\n \"personId [sex, generationAttrs]\",\n \"parentA -- parentB\",\n \"indent offspring under the couple line\",\n ],\n prefer: [\"Use pedigree status/trait attributes from the syntax reference.\", \"Keep generation structure explicit.\"],\n avoid: [\"Avoid genogram emotional-relationship lines in pedigree output.\"],\n repair: [\"Declare every referenced individual before relationships.\"],\n },\n phylo: {\n type: \"phylo\",\n header: 'phylo \"Title\"',\n mode: \"quoted Newick\",\n forms: ['newick: \"((A:0.1,B:0.2),C:0.3);\"', 'clade Group = (A, B) [label: \"Group\"]'],\n prefer: [\"Use Newick for first-shot generation.\", \"Quote the Newick string.\"],\n avoid: [\"Avoid indent-tree mode unless the user wants a hand-authored tree.\"],\n repair: [\"A phylo document needs exactly one tree definition: Newick or indent tree.\"],\n },\n sociogram: {\n type: \"sociogram\",\n header: 'sociogram \"Title\"',\n mode: \"declared nodes + social ties\",\n forms: ['nodeId [label: \"Person\"]', 'nodeA -> nodeB [label: \"choice\"]', \"config: layout = circular\"],\n prefer: [\"Declare actors first.\", \"Use one supported layout/config value at a time.\"],\n avoid: [\"Avoid unknown config values; some adapters keep defaults.\"],\n repair: [\"Unknown edge endpoints need matching node declarations.\"],\n },\n timing: {\n type: \"timing\",\n header: 'timing \"Title\"',\n mode: \"WaveDrom signals, with clock/run-length shorthands\",\n forms: [\n \"CLK: clock 8 (clock generator, 8 periods — no char-counting)\",\n \"RST: rle 1*2 0*6 (run-length: two 1s then six 0s)\",\n 'DATA: x====x data: [\"A\",\"B\"] (raw WaveDrom wave + bus labels)',\n ],\n prefer: [\n \"Use `clock N` for clocks instead of counting `p` characters.\",\n \"Use `rle <state>*<count> ...` for level/data signals instead of counting characters — it auto-aligns length.\",\n \"Drop to a raw wave string only for fine control; keep all signals the same total length so they align.\",\n \"Use `data:` labels for bus segments (`=` or digit states).\",\n ],\n avoid: [\"Avoid hand-counting long runs of identical characters — that is the main source of misaligned waves.\"],\n repair: [\n \"Wave-state errors name the offending character and list the valid states.\",\n \"If two signals don't line up, make their total cell counts equal (clock N and rle make this easy).\",\n ],\n },\n logic: {\n type: \"logic\",\n header: 'logic \"Title\"',\n mode: \"logic netlist\",\n forms: [\"INPUT A, B\", \"G1 = AND(A, B)\", \"OUTPUT Y = G1\"],\n prefer: [\n \"Gate form is `id = TYPE(in1, in2, …)`; declare `INPUT`/`OUTPUT` ports explicitly. Prefix a signal with `~` for active-low.\",\n \"Use only these canonical gate TYPEs: combinational AND, OR, NOT, NAND, NOR, XOR, XNOR, BUF; output buffers TRISTATE_BUF, TRISTATE_INV, OPEN_DRAIN, SCHMITT; flip-flops DFF, JKFF, SRFF, TFF; latches LATCH_SR, LATCH_D; complex MUX, DEMUX, DECODER, ENCODER, COUNTER, SHIFT_REG.\",\n ],\n avoid: [\"Avoid circuit component names (R, C, transistors) inside logic diagrams.\"],\n repair: [\"An unrecognised gate renders as a flagged `?` placeholder; replace it with the closest canonical gate from the list above (e.g. LOAD/REG → DFF, INV → NOT).\"],\n },\n circuit: {\n type: \"circuit\",\n header: 'circuit \"Title\" netlist',\n mode: \"SPICE-style netlist (recommended for generation)\",\n forms: [\n \"V1 in 0 5V (component-id node-A node-B value)\",\n \"R1 in out 1k\",\n \"C1 out 0 100n\",\n ],\n prefer: [\n \"Always use netlist mode (`... netlist` header). Each line is one component; no spatial state to track.\",\n \"Two components that share a node name are wired together. `0`, `gnd`, or `GND` is the ground net.\",\n \"The component-id prefix sets the type (R=resistor, C=capacitor, L=inductor, V=source, D=diode, Q=BJT). Add explicit `type=` only when the prefix is ambiguous.\",\n \"Optional orientation hint `dir=` (right|left|up|down) nudges a single symbol's facing, e.g. `C1 out 0 100n dir=down` for a shunt cap. Connectivity is unaffected; omit it unless layout readability needs it.\",\n ],\n avoid: [\n \"Avoid positional cursor routing (`wire`, `at:`) — that mode is for hand-drawing, not generation.\",\n \"Do not invent coordinates; the layout engine places components from the net connectivity. `dir=` only rotates a symbol, it does not set position.\",\n ],\n repair: [\"If a component type or pin count is ambiguous, make the symbol type explicit with `type=`.\"],\n },\n blockdiagram: {\n type: \"blockdiagram\",\n header: 'blockdiagram \"Title\"',\n mode: \"blocks, sums, signals\",\n forms: ['ctrl = block(\"PID\") [role: controller]', \"err = sum(+r, -y)\", \"err -> ctrl -> plant\"],\n prefer: [\"Use named blocks and directed `->` chains.\"],\n avoid: [\"Avoid unlabeled feedback intent; model the summing junction.\"],\n repair: [\"Connections must point at declared blocks, sums, signals, or boundary IDs.\"],\n },\n ladder: {\n type: \"ladder\",\n header: 'ladder \"Title\"',\n mode: \"rungs + IEC/Rockwell elements\",\n forms: ['rung 1 \"Run motor\":', \" XIC(START_PB)\", \" OTE(MOTOR_RUN)\"],\n prefer: [\"Use uppercase element names.\", \"Use `parallel:` + `branch:` only for OR branches.\"],\n avoid: [\"Avoid variable declarations and ST syntax.\"],\n repair: [\"Element typos are repairable from parser suggestions; keep the tag in parentheses.\"],\n },\n sld: {\n type: \"sld\",\n header: 'sld \"Title\"',\n mode: \"equipment assignments + power-flow edges\",\n forms: ['util = utility [label: \"Grid\"]', 'xfmr = transformer [rating: \"500 kVA\"]', \"util -> xfmr (one edge per line, no chaining)\"],\n prefer: [\n \"Declare equipment as `id = nodeType [attrs]`, one `from -> to` connection per line.\",\n \"Use only these canonical nodeTypes: sources utility, generator, solar, wind, ups; transformers transformer, transformer_dy, transformer_yd, transformer_yy, transformer_dd, autotransformer, transformer_3winding; buses bus, bus_tie, hub; switching breaker, breaker_vacuum, switch, switch_load, ground_switch, ats, recloser, sectionalizer, fuse, fuse_cl; protection ct, pt, relay, surge_arrester, ground_fault; loads motor, load, capacitor_bank, harmonic_filter, vfd; metering watthour_meter, demand_meter.\",\n \"IEC/REBT residential aliases are also accepted: mcb/mccb→breaker, rcd/rcbo/rccb→ground_fault, isolator/disconnector→switch_load, panel/consumer_unit/distribution_board→bus.\",\n ],\n avoid: [\"Avoid generic flowchart node syntax.\"],\n repair: [\"An unrecognised nodeType renders as a flagged `?` placeholder; pick the closest canonical type or alias from the list above (e.g. meter→watthour_meter, inverter→vfd).\"],\n },\n entity: {\n type: \"entity\",\n header: 'entity-structure \"Title\"',\n mode: \"legal entities + ownership edges\",\n forms: ['entity holdco \"HoldCo\" corp@US', 'entity opco \"OpCo\" llc@DE', \"holdco -> opco : 100%\"],\n prefer: [\"Use `entity` declarations before ownership edges.\", \"Keep legal form and jurisdiction explicit when known.\"],\n avoid: [\"Avoid database schema terminology; use `erd` for tables and FKs.\"],\n repair: [\"Unknown ownership endpoints need entity declarations.\"],\n },\n fishbone: {\n type: \"fishbone\",\n header: 'fishbone \"Title\"',\n mode: \"effect + cause categories\",\n forms: ['effect \"Late Delivery\"', 'category process \"Process\"', 'process: \"Handoff delay\"'],\n prefer: [\"Use one effect and structured categories for generated DSL.\"],\n avoid: [\"Avoid mixing compact alien syntax when a structured category form works.\"],\n repair: [\"If a cause lands nowhere, add or reference its category explicitly.\"],\n },\n venn: {\n type: \"venn\",\n header: 'venn \"Title\"',\n mode: \"declared-set region counts\",\n forms: ['set A \"Group A\"', 'set B \"Group B\"', \"A & B : 120\", \"A only : 80\"],\n prefer: [\"Use declared sets plus region counts for first-shot Venn output.\", \"Use Euler relations only when subset/disjoint structure is the request.\"],\n avoid: [\"Avoid mixing enumeration mode with explicit region counts.\"],\n repair: [\"Declare every set before region or Euler relation lines.\"],\n },\n flowchart: {\n type: \"flowchart\",\n header: 'flowchart TD \"Title\"',\n mode: \"Mermaid-compatible nodes + edges\",\n forms: [\"start([Start]) --> check{Decision?}\", \"check -->|Yes| done([Done])\"],\n prefer: [\"Choose one direction in the header.\", \"Declare shapes explicitly when shape matters.\"],\n avoid: [\"Avoid subgraph complexity unless grouping is part of the request.\"],\n repair: [\"A bad header direction fails early; use TD, TB, BT, LR, or RL.\"],\n },\n mindmap: {\n type: \"mindmap\",\n header: \"mindmap\",\n mode: \"Markdown headings + bullets\",\n forms: [\"# Root\", \"## Branch\", \"- Child item\"],\n prefer: [\"Use exactly one `#` root heading.\", \"Use bullets/headings instead of graph edges.\"],\n avoid: [\"Avoid comments in the body.\"],\n repair: [\"An orphan branch means the root `#` heading is missing.\"],\n },\n matrix: {\n type: \"matrix\",\n header: 'matrix \"Title\"',\n mode: \"quadrant scatter\",\n forms: [\"x-axis: Low -> High\", \"y-axis: Low -> High\", '\"Item\" at (0.25, 0.8)'],\n prefer: [\"Use quadrant scatter for first-shot prioritization/portfolio requests.\", \"Use built-in templates when the framework is named.\"],\n avoid: [\"Avoid heatmap, correlation, and table modes unless the user asks for that form.\"],\n repair: [\"Point coordinates are normalized fractions; keep them in `[0,1]`.\"],\n },\n orgchart: {\n type: \"orgchart\",\n header: 'orgchart \"Title\"',\n mode: \"indented hierarchy\",\n forms: ['ceo: \"Name\" | CEO', ' cto: \"Name\" | CTO', ' eng: \"Name\" | Engineer'],\n prefer: [\"Use indentation for the reporting tree.\", \"Use dotted explicit edges only for matrix reporting.\"],\n avoid: [\"Avoid mixing explicit report edges with indentation unless needed.\"],\n repair: [\"Duplicate IDs and unknown explicit edge endpoints are parse failures.\"],\n },\n decisiontree: {\n type: \"decisiontree\",\n header: 'decisiontree \"Title\"',\n mode: \"taxonomy questions\",\n forms: ['question \"Question?\"', ' yes: answer \"Outcome\"', ' no: answer \"Other outcome\"'],\n prefer: [\"Use taxonomy mode for troubleshooting and triage.\", \"Select `decisiontree:decision` or `decisiontree:ml` only when expected value or ML is explicit.\"],\n avoid: [\"Avoid mixing mode-specific keywords.\"],\n repair: [\"Indent each child under its parent and use the branch prefix required by the selected mode.\"],\n },\n timeline: {\n type: \"timeline\",\n header: 'timeline \"Title\"',\n mode: \"dated events\",\n forms: ['2026-05-22: \"Event\"', '2026-06-01 - 2026-06-30: \"Phase\"', '2026-07-01: milestone \"Launch\"'],\n prefer: [\"Use dated events/ranges and `milestone` for important points.\"],\n avoid: [\"Avoid custom row keys when a date is known.\"],\n repair: [\"Quote labels and keep the colon after the date/range.\"],\n },\n state: {\n type: \"state\",\n header: \"stateDiagram-v2\",\n mode: \"Mermaid stateDiagram-v2 (recommended for generation)\",\n forms: [\n \"[*] --> Idle\",\n \"Idle --> Running : start\",\n \"Running --> Done : finish\",\n \"Done --> [*]\",\n ],\n prefer: [\n \"Use Mermaid `stateDiagram-v2` syntax: `[*]` for the start/end pseudo-states, `-->` for transitions, `: label` for the event/guard.\",\n \"This matches the most common training data, so prefer it over the native `state \\\"Title\\\"` + `initial`/`final` form (which is also accepted).\",\n ],\n avoid: [\n \"Avoid composite/concurrent-state syntax until the request needs it.\",\n \"Do not mix the two styles in one file (e.g. `[*]` together with `initial X`); pick `[*]`.\",\n ],\n repair: [\n \"Every transition uses `-->`; place at least one named state between a `[*]` start and a `[*]` end.\",\n \"If the header is rejected, use exactly `stateDiagram-v2` (or `state \\\"Title\\\"`).\",\n ],\n },\n pid: {\n type: \"pid\",\n header: 'pid \"Title\"',\n mode: \"equipment + process lines\",\n forms: [\n \"equip T-101 : tank_atm\",\n \"equip P-101 : pump_centrifugal\",\n \"line L1 from T-101.bottom to P-101.in\",\n \"inst FIC-201 : cr_shared\",\n ],\n prefer: [\n \"Declare equipment first (`equip ID : type [attrs]`), then process/signal lines, then instruments (`inst TAG : category`).\",\n \"Use only these canonical equipment types: tanks/vessels tank_atm, tank_cone_roof, vessel_v, vessel_h, sphere; columns column_tray, column_packed; heat transfer hx_shell_tube, hx_air_cooled, reboiler, condenser; rotating pump_centrifugal, pump_pd, compressor, blower; reactors reactor_cstr, reactor_pfr; misc filter, cyclone, flare, cooling_tower; valves valve_gate, valve_ball, valve_globe, valve_butterfly, valve_check, valve_control, valve_psv.\",\n \"Instrument categories: field_discrete, field_shared, field_computer, field_plc, cr_discrete, cr_shared, cr_computer, cr_plc, local_discrete, local_shared. Line types (`[type: …]`): process, process_minor, pneumatic, electric, hydraulic, capillary, software, mechanical.\",\n ],\n avoid: [\"Avoid SLD electrical nodes (transformer, breaker) in a P&ID.\"],\n repair: [\"An unrecognised equipment type renders as a flagged `?` placeholder; pick the closest canonical type from the list above (e.g. exchanger/heat_exchanger→hx_shell_tube, vessel_horizontal→vessel_h, cstr→reactor_cstr).\"],\n },\n erd: {\n type: \"erd\",\n header: \"erDiagram\",\n mode: \"Mermaid erDiagram (recommended for generation)\",\n forms: [\n \"CUSTOMER ||--o{ ORDER : places\",\n \"ORDER {\",\n \" int id PK\",\n \" string customerId FK\",\n \"}\",\n ],\n prefer: [\n \"Use Mermaid `erDiagram` syntax: relationships `A <card>--<card> B : label` with crow's-foot glyphs (`||` one, `o{` zero-or-many, `|{` one-or-many, `|o` zero-or-one); entity blocks `NAME { type name KEY }` with attributes **type-first** and KEY ∈ PK/FK/UK.\",\n \"Entities are auto-created from relationships; you only need a `{ … }` block to list attributes.\",\n \"This matches the dominant training-data prior. The native `erd` header with `table NAME { name type PK }` + `ref … many-mandatory -- one-mandatory …` is also accepted.\",\n ],\n avoid: [\"Do not mix the two header styles; under `erDiagram`, attributes are type-first (`int id PK`), not name-first.\"],\n repair: [\n \"Crow's-foot glyph pairs must be valid (`||`, `|o`, `}o`, `}|` on the left; `||`, `o|`, `o{`, `|{` on the right).\",\n \"If the header is rejected, use exactly `erDiagram` (or native `erd`).\",\n ],\n },\n breadboard: {\n type: \"breadboard\",\n header: \"breadboard\",\n mode: \"parts + wires blocks\",\n forms: ['title: \"Prototype\"', \"parts\", \"wires\"],\n prefer: [\"Use physical parts and addressable tie points.\", \"Keep schematic tasks on `circuit` instead.\"],\n avoid: [\"Avoid abstract netlist syntax in breadboard output.\"],\n repair: [\"Missing parts or invalid breadboard connection endpoints need the breadboard syntax reference.\"],\n },\n bpmn: {\n type: \"bpmn\",\n header: \"bpmn\",\n mode: \"pool/lane objects + flows\",\n forms: ['pool \"Service\" {', ' lane \"Worker\" { A: start \"Request\" }', \"flows\", \"A --> B\"],\n prefer: [\"Use pools, lanes, and a `flows` block.\", \"Use `~~>` only for cross-pool message flow.\"],\n avoid: [\"Avoid generic flowchart syntax for BPMN semantics.\"],\n repair: [\"Sequence flows cannot cross pools; switch to message flow when needed.\"],\n },\n fbd: {\n type: \"fbd\",\n header: 'fbd \"Title\"',\n mode: \"networks + blocks\",\n forms: [\"var Start: bool\", 'network \"Logic\":', \"Motor = AND(Start, Safe)\"],\n prefer: [\"Use network/expression forms from the FBD syntax guide.\"],\n avoid: [\"Avoid ladder rung syntax in FBD output.\"],\n repair: [\"Invalid block calls need a supported block and valid arguments.\"],\n },\n sfc: {\n type: \"sfc\",\n header: 'sfc \"Title\"',\n mode: \"steps + transitions\",\n forms: [\"step Idle [initial]\", \"transition Idle -> Run : Start\", \"step Run\"],\n prefer: [\"Use explicit steps and transitions before alternative/simultaneous branches.\"],\n avoid: [\"Avoid UML state syntax in SFC output.\"],\n repair: [\"Every transition step reference must resolve to a declared step.\"],\n },\n prisma: {\n type: \"prisma\",\n header: \"prisma\",\n mode: \"PRISMA 2020 single pipeline\",\n forms: [\"identification:\", \" databases:\", \" n: 1000\", \"screening:\", \"included:\"],\n prefer: [\"Use the required four stages and mandatory counts.\", \"Use single-pipeline 2020 mode unless other-methods data is present.\"],\n avoid: [\"Avoid generic flowchart boxes for PRISMA requests.\"],\n repair: [\"Missing stage blocks or mandatory `n` fields are intentional parser errors.\"],\n },\n usecase: {\n type: \"usecase\",\n header: \"usecase\",\n mode: \"declarative UML use cases\",\n forms: ['system: \"System\"', \"actor: Customer\", 'usecase: \"Checkout\" as Checkout', \"Customer -- Checkout\"],\n prefer: [\"Use declarative actor/usecase lines for generated DSL.\"],\n avoid: [\"Avoid PlantUML inline form unless converting PlantUML-like input.\"],\n repair: [\"Include/extend relations must connect use cases, not actors.\"],\n },\n pert: {\n type: \"pert\",\n header: \"pert\",\n mode: \"AON tasks + dependencies\",\n forms: ['task A \"Spec\" duration: 3', 'task B \"Build\" duration: 8 after: A'],\n prefer: [\"Use AON network tasks first.\", \"Use time-scaled/AOA layouts only when requested.\"],\n avoid: [\"Avoid writing computed ES/EF/LS/LF fields yourself.\"],\n repair: [\"Task IDs must exist before they are used in `after:` lists.\"],\n },\n sequence: {\n type: \"sequence\",\n header: \"sequenceDiagram\",\n mode: \"Mermaid sequenceDiagram (recommended for generation)\",\n forms: [\n \"participant Alice\",\n \"participant Bob\",\n \"Alice->>Bob: request\",\n \"Bob-->>Alice: response\",\n \"Note over Alice,Bob: handshake\",\n ],\n prefer: [\n \"Use Mermaid `sequenceDiagram` syntax: `->>` is a sync call, `-->>` a reply/return, `-)` async; `participant`/`actor`, `Note over A,B:`, and `loop`/`alt`/`opt`/`par … end` all work.\",\n \"This matches the dominant training-data prior; the native `sequence \\\"Title\\\"` header (where `->>` means async) is also accepted.\",\n \"Add combined fragments only when control flow matters.\",\n ],\n avoid: [\"Do not mix the two header styles; pick `sequenceDiagram` and keep Mermaid arrow meanings throughout.\"],\n repair: [\n \"Every fragment (`loop`/`alt`/`opt`/`par`/`break`/`critical`) needs a matching `end`; `else` only inside `alt`.\",\n \"If the header is rejected, use exactly `sequenceDiagram` (or `sequence \\\"Title\\\"`).\",\n ],\n },\n petri: {\n type: \"petri\",\n header: 'petri \"Title\"',\n mode: \"declared places + transitions + arcs\",\n forms: [\n \"place P1 *1\",\n \"transition T1\",\n \"P1 -> T1\",\n \"T1 -> P2\",\n \"P3 -> T2 weight: 2\",\n ],\n prefer: [\n \"Declare every place and transition before any arc references it.\",\n \"Use `*n` or `tokens: n` for the initial marking and `weight: n` for arc multiplicity > 1.\",\n \"Keep arcs bipartite: every arc goes place→transition or transition→place.\",\n ],\n avoid: [\n \"Avoid place→place or transition→transition arcs.\",\n \"Avoid `-o`/`=>` arcs from a transition; inhibitor and reset arcs are place→transition only.\",\n ],\n repair: [\n \"An 'unknown node' error means an arc references an undeclared place/transition — declare it first.\",\n \"Set the initial marking so the transitions you intend to be enabled actually have enough input tokens.\",\n ],\n },\n network: {\n type: \"network\",\n header: 'network \"Title\"',\n mode: \"device declarations + links (annotations are optional)\",\n forms: [\n 'router r1 \"Edge Router\" (kind id \"label\")',\n 'l3switch core1 \"Core\" tier: core (optional structural hint)',\n 'switch acc1 \"Access\" tier: access',\n 'pc pc1 \"Workstation\"',\n \"r1 -- core1 (link: id -- id)\",\n \"core1 -- acc1\",\n \"acc1 -- pc1\",\n ],\n prefer: [\n \"Start from the skeleton: `kind id \\\"label\\\"` device lines plus `a -- b` links. That alone renders a complete, valid diagram.\",\n \"Declare every device before any link references it.\",\n \"Keep the cheap structural hints `layout:` (tiered/tree/star/ring/bus/mesh/spine-leaf) and `tier:` (edge/core/distribution/access) — they cost little and drive a readable hierarchy. They are recommended, not noise.\",\n \"Common kinds: router, switch, l3switch, firewall, ap, server, pc, laptop, camera, nvr, poeswitch, internet, cloud.\",\n ],\n avoid: [\n \"Avoid linking to an undeclared device id.\",\n \"Add the verbose per-link annotations — `vlan:`, `port:`, speeds (1G/10G), `trunk`/`access` — and `subnet \\\"cidr\\\" { ... }` boundaries ONLY when the request explicitly needs them. These don't affect the layout and are where generation most often breaks.\",\n ],\n repair: [\n \"An 'undeclared device' error means a link references an id with no `kind id` declaration — declare it first.\",\n \"If the layout looks flat/messy, add `layout: tiered` + `tier:` on infrastructure; if unsure about per-link annotations, drop them — the skeleton always renders.\",\n ],\n },\n umlclass: {\n type: \"umlclass\",\n header: \"umlclass\",\n mode: \"classifier declarations + relationship lines (PlantUML-flavoured, Mermaid aliases accepted)\",\n forms: [\n 'class Order { + id : String + place() : void } (visibility: + - # ~)',\n '«interface» Shape { + area() : double } (stereotype above name)',\n 'abstract class AbstractShape { + area() : double {abstract} }',\n '«enumeration» Suit { HEARTS DIAMONDS CLUBS SPADES } (literals in attr compartment)',\n 'Animal <|-- Dog (generalization — hollow triangle to parent)',\n 'Shape <|.. Circle (realization — dashed + hollow triangle)',\n 'Order *-- \"1..*\" LineItem : contains (composition — filled diamond at whole)',\n 'Customer o-- \"0..*\" Address (aggregation — hollow diamond at whole)',\n 'A \"1\" --> \"*\" B : owns (directed association — open arrow to target)',\n 'X ..> Y (dependency — dashed + open arrow)',\n ],\n prefer: [\n \"Single-word keyword is `umlclass` (also accepts `class-diagram` and Mermaid's `classDiagram`).\",\n \"Use `class`, `abstract class`, `«interface»`, `«enumeration»`, or any custom `«stereotype»` above the name.\",\n \"Members go in `{ … }`; visibility glyphs are `+ - # ~`; `{static}` underlines, `{abstract}` italicises, `/name` marks a derived attribute.\",\n \"Multiplicity is the quoted token next to an endpoint: `\\\"1\\\"`, `\\\"0..*\\\"`, `\\\"1..*\\\"`. The line midpoint label after `:` is the association name.\",\n \"PlantUML connectors are primary; the Mermaid reversed forms `--|>`, `..|>`, `--*`, `--o` are accepted and normalised.\",\n ],\n avoid: [\n \"Don't use bare `class` as the diagram keyword — that's a reserved programming-language word, and the engine keyword is `umlclass`.\",\n \"Don't put `-->` for dependency: `-->` is *directed association*; dependency is the dashed `..>` (this is a deliberate deviation from PlantUML, matching Mermaid and the usual UML reading).\",\n \"Don't declare a classifier with an empty body and `{}` if you want a name-only sketch box — write `class Foo` on its own line.\",\n ],\n repair: [\n \"A 'malformed relationship' error means no connector glyph was found between two ids — check the line uses one of `<|--` `<|..` `*--` `o--` `-->` `..>` `--` `..`.\",\n \"A 'generalization cycle' error means inheritance edges form a loop — fix the parent/child direction of one of the edges named in the cycle.\",\n \"If a class appears as a one-line empty box you didn't expect, the parser auto-created it from an arc reference — declare it explicitly or fix the typo in the relationship id.\",\n ],\n },\n faulttree: {\n type: \"faulttree\",\n header: 'faulttree \"Title\"',\n mode: \"flat event/gate declarations wired by id (top + gates + leaves)\",\n forms: [\n \"analysis: cutsets, probability\",\n 'top T \"System fails\" = OR(G1, G2)',\n 'gate G1 \"Sub-fault\" = AND(A, B)',\n 'basic A \"Component A fails\" p: 0.01',\n \"undeveloped EXT \\\"External cause\\\"\",\n 'house HX \"Power on\" state: 1',\n \"RELIEF = VOTING(2/3; PRV_A, PRV_B, PRV_C)\",\n \"OVP = INHIBIT(PUMP) if HEATER\",\n ],\n prefer: [\n \"Single-word keyword is `faulttree` (alias `fta`). Declare exactly one `top` event.\",\n \"Declare every referenced event before or after use; wire gates by id (the tree is a DAG — a basic event may feed several gates).\",\n \"Gate expressions: AND/OR/XOR(a, b, …), VOTING(k/n; …), INHIBIT(x) if cond, PAND(a, b) order: a, b.\",\n \"Put `p: 0.001` (or scientific `1e-3`) on basic/undeveloped events; the engine computes minimal cut sets and P(top).\",\n \"Use `prob: rare` (default), `mcub`, or `exact`; `house … state: 0|1` switches branches on/off.\",\n ],\n avoid: [\n \"Don't nest by indentation — fault tree is flat declaration + id reference (so repeated/shared events are unambiguous).\",\n \"Don't attach `if <cond>` to anything but INHIBIT (or `order:` to anything but PAND).\",\n \"Don't declare more than one `top`, and don't create cycles (a gate may not transitively reference itself).\",\n ],\n repair: [\n \"'references undefined event' means a gate input id was never declared — add the `basic`/`gate`/… line.\",\n \"'must have exactly one top' — keep a single `top`; downgrade the others to `gate`.\",\n \"'VOTING k/n: n must equal the number of inputs' — make n match the listed inputs.\",\n \"If P(top) shows 'n/a', a basic event in a cut set is missing its `p:`.\",\n ],\n },\n bowtie: {\n type: \"bowtie\",\n header: 'bowtie \"Title\"',\n mode: \"indentation-structured: hazard + topevent, then threat/consequence blocks with indented barrier chains\",\n forms: [\n 'hazard \"Working at height\"',\n 'topevent \"Person falls from height\"',\n 'threat \"Guardrail removed for access\"',\n ' prevent \"Permit-to-work system\"',\n ' prevent \"Temporary edge protection\"',\n ' escalation \"Edge protection not inspected\"',\n ' barrier \"Pre-use inspection regime\"',\n 'consequence \"Fatality\"',\n ' mitigate \"Fall-arrest harness\"',\n ],\n prefer: [\n \"Single-word keyword is `bowtie`. Declare exactly one `topevent` (the knot) and an optional `hazard` header.\",\n \"Each `threat` needs ≥ 1 indented `prevent` barrier; each `consequence` needs ≥ 1 indented `mitigate` barrier (the engine rejects a bare threat/consequence).\",\n \"Barrier order = declaration order (first = outermost, nearest the threat/consequence; last = innermost, nearest the knot).\",\n \"`escalation` nests (4 spaces) under the `prevent`/`mitigate` barrier it degrades; an escalation-factor `barrier` nests (6 spaces) under the escalation.\",\n \"Bowtie is qualitative — no probabilities. For Boolean gates + cut sets behind one threat, use a separate `faulttree`.\",\n ],\n avoid: [\n \"Don't put a `prevent` before any `threat`, or a `mitigate` before any `consequence` — they bind to the most recent one.\",\n \"Don't leave a threat or consequence with no barrier — that is a Swiss-cheese cartoon, not a bowtie (it is rejected).\",\n \"Don't float an `escalation` on its own — it must follow a barrier line.\",\n \"Don't declare more than one `topevent` or more than one `hazard`.\",\n ],\n repair: [\n \"'has no preventative barrier' / 'no mitigative barrier' — add a `prevent`/`mitigate` line under the threat/consequence.\",\n \"'not attached to a barrier' — move the `escalation` so it follows a `prevent`/`mitigate` line.\",\n \"'needs at least one threat/consequence' — a one-wing diagram is a fault tree or event tree; add the missing wing.\",\n \"'exactly one top event' — keep a single `topevent` line.\",\n ],\n },\n eventtree: {\n type: \"eventtree\",\n header: 'eventtree \"Title\"',\n mode: \"initiating event + ordered safety functions, then outcome rows with s/f/* branch patterns\",\n forms: [\n 'initiating LOCA \"Large LOCA\" freq: 1e-4',\n 'function A \"ECCS injects\" p: 0.001',\n 'function B \"Containment spray\" p: 0.01',\n 'outcome s s -> \"OK\"',\n 'outcome s f -> \"Late release\"',\n 'outcome f * -> \"Core damage\"',\n ],\n prefer: [\n \"Keyword `eventtree` (or `eta`). One `initiating` line with a `freq:`; then `function` lines in left-to-right order, each with its failure probability `p:` (success is auto-complemented to 1−p).\",\n \"Each `outcome` row gives a `s`/`f`/`*` pattern (one symbol per function) then `-> \\\"label\\\"`. `*` = path already terminated (pruned) — runs flat to its leaf, no further branching.\",\n \"Let the engine compute path frequencies (f_initiating × Π branch-probs) — don't hand-write them.\",\n ],\n avoid: [\n \"Don't try to make a balanced 2ⁿ tree — prune with `*` where a sequence ends early.\",\n \"Don't put probabilities on outcome rows; `p:` belongs on `function` lines.\",\n \"Don't reverse the success/failure convention — success branches up, failure down.\",\n ],\n repair: [\n \"'outcome pattern length' — give exactly one s/f/* per declared function.\",\n \"'no initiating event' — add one `initiating <id> \\\"…\\\" freq: …` line.\",\n \"'once pruned stays pruned' — after a `*` in a pattern, the rest must also be `*`.\",\n ],\n },\n fmea: {\n type: \"fmea\",\n header: 'fmea \"Title\"',\n mode: \"indentation-structured worksheet: item → failure mode → effect/cause/controls with S/O/D scores\",\n forms: [\n 'fmea \"Brake System DFMEA\"',\n ' item \"Master cylinder\" fn \"Generate pressure\"',\n ' mode \"Internal seal leak\"',\n ' effect \"Loss of braking\" sev: 9',\n ' cause \"Seal degradation\" occ: 3',\n ' controls detection: \"Bench test\" det: 4',\n ],\n prefer: [\n \"Keyword `fmea`. Nest `item` → `mode` → `effect`/`cause` → `controls`. Put Severity on the effect (`sev:`), Occurrence on the cause (`occ:`), Detection on the controls (`det:`) — each 1–10.\",\n \"Let the engine compute RPN = S×O×D and the Action Priority (High/Medium/Low) and rank the sheet — don't hand-write RPN.\",\n \"Optional `rank: ap|rpn` and `flag: ap >= High` / `flag: rpn > 100` to control sorting/highlighting.\",\n ],\n avoid: [\n \"Don't write the RPN or AP yourself — they are computed.\",\n \"Don't use scores outside 1–10.\",\n \"Don't put `occ:` on an effect or `sev:` on a cause — they bind to the wrong column.\",\n ],\n repair: [\n \"'score out of range' — keep S/O/D in 1–10.\",\n \"'mode has no effect/cause' — every failure mode needs at least one effect and one cause.\",\n ],\n },\n causalloop: {\n type: \"causalloop\",\n header: 'causalloop \"Title\"',\n mode: \"signed causal links between variables; engine detects R/B loops\",\n forms: [\n 'causalloop \"Adoption model\"',\n '\"Adoption rate\" -> Adopters : +',\n 'Adopters -> \"Adoption rate\" : +',\n '\"Adoption rate\" -> \"Potential adopters\" : -',\n 'loop R1 \"Word of mouth\"',\n 'loop B1 \"Market saturation\"',\n ],\n prefer: [\n \"Keyword `causalloop` (or `cld`). Write `A -> B : +` or `A -> B : -` (you may use `s`/`o` aliases). Multi-word variables go in quotes.\",\n \"Let the engine classify loops R (reinforcing) / B (balancing) by counting negative links; optionally name them with `loop R1 \\\"…\\\"`.\",\n \"Put the `+`/`−` polarity at the end of each link.\",\n ],\n avoid: [\n \"Don't draw boxes around variables — CLD variables are boxless text.\",\n \"Don't omit polarity — every causal link is signed.\",\n ],\n repair: [\n \"'link needs a polarity' — append `: +` or `: -`.\",\n \"'unknown variable' — variables are created on first use; check quoting/spelling.\",\n ],\n },\n markov: {\n type: \"markov\",\n header: 'markov \"Title\"',\n mode: \"probability-labelled state transitions; engine computes stationary distribution + classification\",\n forms: [\n 'markov \"Weather\"',\n \"Sunny -> Sunny : 0.9\",\n \"Sunny -> Rainy : 0.1\",\n \"Rainy -> Sunny : 0.5\",\n \"Rainy -> Rainy : 0.5\",\n ],\n prefer: [\n \"Keyword `markov` (or `markovchain`). Write `S1 -> S2 : 0.3` transitions; each state's outgoing probabilities must sum to 1.\",\n \"Mark absorbing states by a 1.0 self-loop (or the `absorbing` keyword); the engine computes the stationary distribution and classifies states.\",\n \"For an absorbing chain add `analysis: classify, absorbing` to get absorption probabilities + expected steps.\",\n ],\n avoid: [\n \"Don't let a state's out-probabilities sum to ≠ 1 (the engine errors); use `normalize: true` only if you intend rescaling.\",\n \"Don't hand-compute the stationary distribution — it is derived.\",\n ],\n repair: [\n \"'row does not sum to 1' — fix the probabilities or add `normalize: true`.\",\n \"'probability out of range' — keep each on (0,1].\",\n ],\n },\n gitgraph: {\n type: \"gitgraph\",\n header: \"gitGraph\",\n mode: \"Mermaid-compatible ordered git operations (commit/branch/checkout/merge)\",\n forms: [\n \"gitGraph\",\n ' commit id: \"init\"',\n \" branch develop\",\n \" checkout develop\",\n ' commit tag: \"v0.1\"',\n \" checkout main\",\n \" merge develop\",\n ],\n prefer: [\n \"Header `gitGraph` (Mermaid syntax). Operations in order: `commit`, `branch <name>`, `checkout <name>`, `merge <name>`, `cherry-pick id: \\\"…\\\"`.\",\n \"Annotate commits with `id: \\\"…\\\"`, `tag: \\\"…\\\"`, `type: HIGHLIGHT|REVERSE|NORMAL`.\",\n \"`checkout` (or `switch`) before committing onto a branch; `merge <name>` merges that branch into the current one.\",\n ],\n avoid: [\n \"Don't `merge` or `checkout` a branch you never created with `branch`.\",\n \"Don't merge a branch into itself.\",\n ],\n repair: [\n \"'unknown branch' — add a `branch <name>` before `checkout`/`merge`.\",\n \"'cannot merge current branch' — checkout the target lane first.\",\n ],\n },\n epc: {\n type: \"epc\",\n header: 'epc \"Title\"',\n mode: \"alternating events/functions joined by AND/OR/XOR connectors; alternation validated\",\n forms: [\n 'epc \"Order fulfilment\"',\n ' event E1 \"Order received\"',\n ' function F1 \"Check credit\"',\n \" xor X1\",\n ' event E2 \"Credit OK\"',\n ' event E3 \"Credit rejected\"',\n \" E1 -> F1 -> X1\",\n \" X1 -> E2\",\n \" X1 -> E3\",\n ],\n prefer: [\n \"Keyword `epc`. Declare `event`, `function`, and connectors `and`/`or`/`xor` with ids; then the control flow `A -> B -> C`.\",\n \"Strictly alternate events and functions (a connector may sit between them); start and end with events.\",\n \"Use a connector node to split/join — e.g. a `xor` after a function fans out to alternative events.\",\n ],\n avoid: [\n \"Don't make an event the source of an OR/XOR split (only functions may decide) — the engine rejects it.\",\n \"Don't connect event→event or function→function directly.\",\n ],\n repair: [\n \"'event cannot be an OR/XOR split source' — put a function (decision) before the connector.\",\n \"'alternation violated' — insert the missing event/function between two same-kind nodes.\",\n ],\n },\n idef0: {\n type: \"idef0\",\n header: 'idef0 \"Title\"',\n mode: \"function boxes + positional ICOM arrows (input-left, control-top, output-right, mechanism-bottom)\",\n forms: [\n 'idef0 \"Manufacture product\"',\n ' function A1 \"Plan production\"',\n ' function A2 \"Make parts\"',\n ' input A1 \"Sales orders\"',\n ' control A1 \"Production schedule\"',\n ' A1 -> A2 \"Work plan\"',\n ' mechanism A2 \"CNC machines\"',\n ' output A2 \"Product\"',\n ],\n prefer: [\n \"Keyword `idef0`. Declare `function` boxes; attach boundary arrows with `input`/`control`/`output`/`mechanism`.\",\n \"Box→box flow `A1 -> A2 \\\"label\\\"` lands on A2's input by default; use `A1 -> A2.control \\\"…\\\"` to land on another ICOM side.\",\n \"Remember the ICOM rule: Inputs enter left, Controls enter top, Outputs exit right, Mechanisms enter bottom — the engine enforces it.\",\n ],\n avoid: [\n \"Don't route an output anywhere but the right edge, or a control anywhere but the top — the engine rejects it.\",\n \"Don't hand-number the boxes — node numbers are assigned.\",\n ],\n repair: [\n \"'output must exit the right edge' — declare it with `output` / land flows on the correct side.\",\n \"'unknown box' — declare the `function` before referencing it.\",\n ],\n },\n threatmodel: {\n type: \"threatmodel\",\n header: 'threatmodel \"Title\"',\n mode: \"DFD elements + data flows + trust boundaries; engine maps STRIDE + flags boundary crossings\",\n forms: [\n 'threatmodel \"Web App — STRIDE\"',\n \"external: User\",\n \"process 1.1: Web Server\",\n \"datastore D1: User DB\",\n \"User -> 1.1 : HTTPS Request\",\n \"1.1 -> D1 : Lookup\",\n 'boundary \"Internet\" { User }',\n 'boundary \"DMZ\" { 1.1 }',\n ],\n prefer: [\n \"Keyword `threatmodel` (or `stride`). Declare `external:`, `process N:`, `datastore D:`; connect with `A -> B : \\\"label\\\"` flows; group ids into `boundary \\\"name\\\" { … }` trust zones.\",\n \"Let the engine annotate each element's STRIDE letters and flag flows that cross a trust boundary — don't list threats by hand.\",\n \"Name audit/log stores with `log`/`audit`/`journal` so they pick up the conditional Repudiation threat.\",\n ],\n avoid: [\n \"Don't connect store→store or external→external (not valid DFD edges).\",\n \"Don't leave data flows unlabelled.\",\n ],\n repair: [\n \"'unknown element' — declare the external/process/datastore before referencing it.\",\n \"'flow needs a label' — add `: \\\"…\\\"` to the flow.\",\n ],\n },\n};\n\nexport function getGenerationProfile(\n type: DiagramType\n): GenerationProfile {\n return PROFILES[type];\n}\n","/**\n * Syntax lookup — LLM-facing per-diagram grammar reference.\n *\n * The default \"canonical\" view stays intentionally narrow for first-shot\n * generation. The \"reference\" view preserves the fuller stripped-MDX docs\n * when a caller needs advanced syntax or adapter coverage.\n */\nimport type { DiagramType } from \"../core/types\";\nimport { SYNTAX } from \"./_generated\";\nimport {\n COMMON_GENERATION_RULES,\n getGenerationProfile,\n type GenerationProfile,\n} from \"./profiles\";\n\nexport type SyntaxDetail = \"canonical\" | \"reference\";\n\nexport interface SyntaxDoc {\n key: string;\n title: string;\n detail: SyntaxDetail;\n content: string;\n}\n\nexport function getSyntaxForType(\n syntaxKey: string,\n type: DiagramType,\n detail: SyntaxDetail = \"canonical\"\n): SyntaxDoc | undefined {\n const s = SYNTAX[syntaxKey];\n if (!s) return undefined;\n return {\n key: syntaxKey,\n title: s.title,\n detail,\n content:\n detail === \"reference\"\n ? s.content\n : buildCanonicalSyntax(getGenerationProfile(type)),\n };\n}\n\nexport function listSyntaxKeys(): string[] {\n return Object.keys(SYNTAX);\n}\n\nfunction buildCanonicalSyntax(profile: GenerationProfile): string {\n return [\n \"# Canonical generation syntax\",\n \"\",\n \"Use this compact path for new DSL generation. Ask for `detail: \\\"reference\\\"` only when the request needs advanced forms or an imported adapter.\",\n \"\",\n \"## Generation profile\",\n \"\",\n `- Canonical type: \\`${profile.type}\\``,\n `- Canonical header: \\`${profile.header}\\``,\n `- Preferred mode: ${profile.mode}`,\n bulletSection(\"Core forms\", profile.forms),\n bulletSection(\"Prefer\", profile.prefer),\n bulletSection(\"Avoid by default\", profile.avoid),\n bulletSection(\"Repair checks\", profile.repair),\n \"## Shared generation rules\",\n \"\",\n ...COMMON_GENERATION_RULES.map((rule) => `- ${rule}`),\n ]\n .filter((part) => part !== \"\")\n .join(\"\\n\");\n}\n\nfunction bulletSection(title: string, items: readonly string[]): string {\n return [`### ${title}`, \"\", ...items.map((item) => `- ${item}`), \"\"].join(\"\\n\");\n}\n","/**\n * AI-facing tool functions — the five tools an LLM uses to work with Schematex.\n *\n * Pure TypeScript, zero framework deps. Both the Vercel AI SDK adapter\n * (ai-sdk.ts) and the MCP server wrap these functions.\n */\nimport {\n parseResult,\n renderResult,\n type SchematexConfig,\n} from \"../core/api\";\nimport type { SchematexDiagnostic } from \"../core/diagnostics\";\nimport {\n DIAGRAM_REGISTRY,\n getDiagramMeta,\n resolveDiagramType,\n type DiagramMeta,\n} from \"./registry\";\nimport type { SchematexValidationError } from \"./errors\";\nimport { getExamplesForType, type Example, type GetExamplesOptions } from \"./examples\";\nimport { getGenerationProfile } from \"./profiles\";\nimport {\n getSyntaxForType,\n type SyntaxDetail,\n type SyntaxDoc,\n} from \"./syntax\";\n\n// ─── listDiagrams ───────────────────────────────────────────────\n\nexport interface DiagramListItem {\n type: string;\n name: string;\n tagline: string;\n useWhen: string;\n cluster: DiagramMeta[\"cluster\"];\n standard: string;\n}\n\nexport function listDiagrams(): DiagramListItem[] {\n return DIAGRAM_REGISTRY.map((d) => ({\n type: d.type,\n name: d.name,\n tagline: d.tagline,\n useWhen: d.useWhen,\n cluster: d.cluster,\n standard: d.standard,\n }));\n}\n\n// ─── getSyntax ──────────────────────────────────────────────────\n\nexport interface GetSyntaxResult {\n type: string;\n name: string;\n standard: string;\n syntax: SyntaxDoc;\n}\n\nexport interface GetSyntaxOptions {\n /** `canonical` is the compact first-shot generation surface. */\n detail?: SyntaxDetail;\n}\n\nexport function getSyntax(\n type: string,\n opts: GetSyntaxOptions = {}\n): GetSyntaxResult {\n const meta = getDiagramMeta(type);\n if (!meta) {\n throw new Error(\n `Unknown diagram type '${type}'. Call listDiagrams() for valid types.`\n );\n }\n const syntax = getSyntaxForType(meta.syntaxKey, meta.type, opts.detail);\n if (!syntax) {\n throw new Error(`No syntax doc available for '${type}' (key: ${meta.syntaxKey}).`);\n }\n return {\n type: meta.type,\n name: meta.name,\n standard: meta.standard,\n syntax,\n };\n}\n\n// ─── getExamples ────────────────────────────────────────────────\n\nexport interface GetExamplesResult {\n type: string;\n count: number;\n examples: Example[];\n}\n\nexport function getExamples(\n type: string,\n opts: GetExamplesOptions = {}\n): GetExamplesResult {\n const meta = getDiagramMeta(type);\n if (!meta) {\n throw new Error(\n `Unknown diagram type '${type}'. Call listDiagrams() for valid types.`\n );\n }\n const examples = getExamplesForType(meta.type, opts);\n return { type: meta.type, count: examples.length, examples };\n}\n\n// ─── validateDsl ────────────────────────────────────────────────\n\nexport type ValidateDslResult =\n | {\n ok: true;\n type: string | null;\n /**\n * `valid` = parsed cleanly; `partial` = parsed and renderable but the\n * engine recovered from incomplete/incorrect input (see `warnings`). A\n * `partial` result still renders — it is NOT a failure.\n */\n status: \"valid\" | \"partial\";\n /** Non-fatal lint findings (empty when `status` is `valid`). */\n warnings: SchematexValidationError[];\n }\n | { ok: false; type: string | null; status: \"invalid\"; errors: SchematexValidationError[] };\n\nexport function validateDsl(type: string | undefined, dsl: string): ValidateDslResult {\n const resolvedType = type ? resolveDiagramType(type) : undefined;\n const config: SchematexConfig | undefined = type\n ? { type: (resolvedType ?? type) as SchematexConfig[\"type\"] }\n : undefined;\n const result = parseResult(dsl, config);\n if (result.ok) {\n return {\n ok: true,\n type: result.type,\n status: result.status,\n warnings: result.diagnostics.map((diagnostic) =>\n toValidationError(diagnostic, result.type)\n ),\n };\n }\n return {\n ok: false,\n type: result.type ?? resolvedType ?? resolveTypeFromText(dsl),\n status: \"invalid\",\n errors: result.diagnostics.map((diagnostic) =>\n toValidationError(diagnostic, result.type ?? resolvedType)\n ),\n };\n}\n\n// ─── renderDsl ──────────────────────────────────────────────────\n\nexport type RenderDslResult =\n | {\n ok: true;\n status: \"valid\" | \"partial\";\n type: string | null;\n svg: string;\n }\n | {\n ok: false;\n status: \"invalid\";\n type: string | null;\n svg: string;\n errors: SchematexValidationError[];\n };\n\nexport function renderDsl(\n type: string | undefined,\n dsl: string,\n options: Omit<SchematexConfig, \"type\"> = {}\n): RenderDslResult {\n const resolvedType = type ? resolveDiagramType(type) : undefined;\n const config: SchematexConfig = {\n ...options,\n ...(type ? { type: (resolvedType ?? type) as SchematexConfig[\"type\"] } : {}),\n };\n const result = renderResult(dsl, config);\n if (result.ok) {\n return {\n ok: true,\n status: result.status,\n type: result.type,\n svg: result.svg,\n };\n }\n return {\n ok: false,\n status: result.status,\n type: result.type ?? resolvedType ?? resolveTypeFromText(dsl),\n svg: result.svg,\n errors: result.diagnostics.map((diagnostic) =>\n toValidationError(diagnostic, result.type ?? resolvedType)\n ),\n };\n}\n\n// ─── helpers ────────────────────────────────────────────────────\n\nfunction resolveTypeFromText(text: string): string | null {\n const first = text.trim().split(/\\s+|\\n/)[0]?.toLowerCase() ?? \"\";\n return resolveDiagramType(first) ?? null;\n}\n\nfunction toValidationError(\n diagnostic: SchematexDiagnostic,\n type?: string | null\n): SchematexValidationError {\n return {\n line: diagnostic.line,\n column: diagnostic.column,\n source: diagnostic.source,\n message: diagnostic.message,\n hint: diagnostic.hint ?? repairHint(type),\n };\n}\n\nfunction repairHint(type?: string | null): string {\n const resolved = type ? resolveDiagramType(type) : undefined;\n const profile = resolved ? getGenerationProfile(resolved) : undefined;\n const typeHint = profile?.repair[0];\n return [\n typeHint,\n \"Fix the reported DSL error, then call validateDsl again before rendering or returning DSL.\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n"]}
|