schematex 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/ai/ai-sdk.cjs +16 -14
  2. package/dist/ai/ai-sdk.cjs.map +1 -1
  3. package/dist/ai/ai-sdk.d.cts +1 -1
  4. package/dist/ai/ai-sdk.d.ts +1 -1
  5. package/dist/ai/ai-sdk.js +11 -9
  6. package/dist/ai/ai-sdk.js.map +1 -1
  7. package/dist/ai/index.cjs +19 -17
  8. package/dist/ai/index.d.cts +1 -1
  9. package/dist/ai/index.d.ts +1 -1
  10. package/dist/ai/index.js +11 -9
  11. package/dist/browser.cjs +13 -11
  12. package/dist/browser.cjs.map +1 -1
  13. package/dist/browser.js +11 -9
  14. package/dist/browser.js.map +1 -1
  15. package/dist/chunk-2KTQ75LN.js +67 -0
  16. package/dist/chunk-2KTQ75LN.js.map +1 -0
  17. package/dist/chunk-3KRL2EGN.cjs +70 -0
  18. package/dist/chunk-3KRL2EGN.cjs.map +1 -0
  19. package/dist/{chunk-YWDODCW2.js → chunk-3M6T7KB4.js} +60 -14
  20. package/dist/chunk-3M6T7KB4.js.map +1 -0
  21. package/dist/{chunk-OIZ4MYSF.cjs → chunk-3M6WB62Y.cjs} +43 -9
  22. package/dist/chunk-3M6WB62Y.cjs.map +1 -0
  23. package/dist/{chunk-KVP7AORH.js → chunk-6IGSKU6D.js} +61 -12
  24. package/dist/chunk-6IGSKU6D.js.map +1 -0
  25. package/dist/{chunk-JDBG5DU2.js → chunk-6OSUNBZY.js} +43 -9
  26. package/dist/chunk-6OSUNBZY.js.map +1 -0
  27. package/dist/{chunk-O5POCPXZ.cjs → chunk-EGSUMHCS.cjs} +21 -10
  28. package/dist/chunk-EGSUMHCS.cjs.map +1 -0
  29. package/dist/{chunk-5FF2IT3C.js → chunk-IBRW3UOA.js} +51 -10
  30. package/dist/chunk-IBRW3UOA.js.map +1 -0
  31. package/dist/{chunk-LPKVIRYT.js → chunk-JHDR56XO.js} +18 -9
  32. package/dist/chunk-JHDR56XO.js.map +1 -0
  33. package/dist/{chunk-Z5NGIM4Z.js → chunk-KWQTF6ZL.js} +30 -13
  34. package/dist/chunk-KWQTF6ZL.js.map +1 -0
  35. package/dist/{chunk-Z5UECSNM.cjs → chunk-N3SLYVNW.cjs} +47 -1785
  36. package/dist/chunk-N3SLYVNW.cjs.map +1 -0
  37. package/dist/{chunk-GZY4CJ23.cjs → chunk-N7W5KZK7.cjs} +51 -10
  38. package/dist/chunk-N7W5KZK7.cjs.map +1 -0
  39. package/dist/chunk-PIV2A3HG.js +55 -0
  40. package/dist/chunk-PIV2A3HG.js.map +1 -0
  41. package/dist/chunk-SBB6C4OP.cjs +57 -0
  42. package/dist/chunk-SBB6C4OP.cjs.map +1 -0
  43. package/dist/{chunk-DHHVYSQX.cjs → chunk-SMXU3KYA.cjs} +38 -21
  44. package/dist/chunk-SMXU3KYA.cjs.map +1 -0
  45. package/dist/{chunk-K6RAUXRQ.cjs → chunk-TZTCIAYW.cjs} +7 -6
  46. package/dist/chunk-TZTCIAYW.cjs.map +1 -0
  47. package/dist/{chunk-YTLGK5BZ.js → chunk-UBTKM2TB.js} +45 -1783
  48. package/dist/chunk-UBTKM2TB.js.map +1 -0
  49. package/dist/{chunk-6WORZSL3.cjs → chunk-VFZOPRQP.cjs} +60 -14
  50. package/dist/chunk-VFZOPRQP.cjs.map +1 -0
  51. package/dist/{chunk-E2EJRVWS.cjs → chunk-VITE3MZQ.cjs} +61 -12
  52. package/dist/chunk-VITE3MZQ.cjs.map +1 -0
  53. package/dist/{chunk-WHNIK4LK.js → chunk-VJGMEGMR.js} +7 -6
  54. package/dist/chunk-VJGMEGMR.js.map +1 -0
  55. package/dist/{chunk-3MJKJX27.cjs → chunk-VZ5LDNHK.cjs} +18 -9
  56. package/dist/chunk-VZ5LDNHK.cjs.map +1 -0
  57. package/dist/{chunk-6XGSEG3K.js → chunk-ZL5RB4UV.js} +21 -10
  58. package/dist/chunk-ZL5RB4UV.js.map +1 -0
  59. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  60. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  61. package/dist/diagrams/circuit/index.d.cts +1 -1
  62. package/dist/diagrams/circuit/index.d.ts +1 -1
  63. package/dist/diagrams/ecomap/index.cjs +7 -6
  64. package/dist/diagrams/ecomap/index.d.cts +1 -1
  65. package/dist/diagrams/ecomap/index.d.ts +1 -1
  66. package/dist/diagrams/ecomap/index.js +2 -1
  67. package/dist/diagrams/entity/index.d.cts +1 -1
  68. package/dist/diagrams/entity/index.d.ts +1 -1
  69. package/dist/diagrams/fishbone/index.cjs +8 -7
  70. package/dist/diagrams/fishbone/index.d.cts +1 -1
  71. package/dist/diagrams/fishbone/index.d.ts +1 -1
  72. package/dist/diagrams/fishbone/index.js +2 -1
  73. package/dist/diagrams/flowchart/index.cjs +8 -7
  74. package/dist/diagrams/flowchart/index.d.cts +2 -2
  75. package/dist/diagrams/flowchart/index.d.ts +2 -2
  76. package/dist/diagrams/flowchart/index.js +2 -1
  77. package/dist/diagrams/genogram/index.cjs +9 -8
  78. package/dist/diagrams/genogram/index.d.cts +1 -1
  79. package/dist/diagrams/genogram/index.d.ts +1 -1
  80. package/dist/diagrams/genogram/index.js +2 -1
  81. package/dist/diagrams/ladder/index.cjs +7 -5
  82. package/dist/diagrams/ladder/index.d.cts +1 -1
  83. package/dist/diagrams/ladder/index.d.ts +1 -1
  84. package/dist/diagrams/ladder/index.js +3 -1
  85. package/dist/diagrams/logic/index.d.cts +1 -1
  86. package/dist/diagrams/logic/index.d.ts +1 -1
  87. package/dist/diagrams/orgchart/index.d.cts +1 -1
  88. package/dist/diagrams/orgchart/index.d.ts +1 -1
  89. package/dist/diagrams/pedigree/index.cjs +7 -6
  90. package/dist/diagrams/pedigree/index.d.cts +1 -1
  91. package/dist/diagrams/pedigree/index.d.ts +1 -1
  92. package/dist/diagrams/pedigree/index.js +2 -1
  93. package/dist/diagrams/phylo/index.d.cts +1 -1
  94. package/dist/diagrams/phylo/index.d.ts +1 -1
  95. package/dist/diagrams/sld/index.cjs +7 -5
  96. package/dist/diagrams/sld/index.d.cts +1 -1
  97. package/dist/diagrams/sld/index.d.ts +1 -1
  98. package/dist/diagrams/sld/index.js +3 -1
  99. package/dist/diagrams/sociogram/index.d.cts +1 -1
  100. package/dist/diagrams/sociogram/index.d.ts +1 -1
  101. package/dist/diagrams/timing/index.d.cts +1 -1
  102. package/dist/diagrams/timing/index.d.ts +1 -1
  103. package/dist/diagrams/venn/index.d.cts +1 -1
  104. package/dist/diagrams/venn/index.d.ts +1 -1
  105. package/dist/{index-CGK0xVls.d.ts → index-BeUVaQiD.d.ts} +1 -2
  106. package/dist/{index-OW8eDrKj.d.cts → index-DYpJXJcy.d.cts} +1 -2
  107. package/dist/index.cjs +23 -21
  108. package/dist/index.d.cts +2 -2
  109. package/dist/index.d.ts +2 -2
  110. package/dist/index.js +10 -8
  111. package/dist/react.cjs +11 -9
  112. package/dist/react.cjs.map +1 -1
  113. package/dist/react.js +10 -8
  114. package/dist/react.js.map +1 -1
  115. package/dist/{types-Gkyab1sL.d.ts → types-DKdo-Ua_.d.cts} +1 -1
  116. package/dist/{types-Gkyab1sL.d.cts → types-DKdo-Ua_.d.ts} +1 -1
  117. package/package.json +1 -1
  118. package/dist/chunk-3MJKJX27.cjs.map +0 -1
  119. package/dist/chunk-5FF2IT3C.js.map +0 -1
  120. package/dist/chunk-6WORZSL3.cjs.map +0 -1
  121. package/dist/chunk-6XGSEG3K.js.map +0 -1
  122. package/dist/chunk-DHHVYSQX.cjs.map +0 -1
  123. package/dist/chunk-E2EJRVWS.cjs.map +0 -1
  124. package/dist/chunk-GZY4CJ23.cjs.map +0 -1
  125. package/dist/chunk-JDBG5DU2.js.map +0 -1
  126. package/dist/chunk-K6RAUXRQ.cjs.map +0 -1
  127. package/dist/chunk-KVP7AORH.js.map +0 -1
  128. package/dist/chunk-LPKVIRYT.js.map +0 -1
  129. package/dist/chunk-O5POCPXZ.cjs.map +0 -1
  130. package/dist/chunk-OIZ4MYSF.cjs.map +0 -1
  131. package/dist/chunk-WHNIK4LK.js.map +0 -1
  132. package/dist/chunk-YTLGK5BZ.js.map +0 -1
  133. package/dist/chunk-YWDODCW2.js.map +0 -1
  134. package/dist/chunk-Z5NGIM4Z.js.map +0 -1
  135. package/dist/chunk-Z5UECSNM.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ai/registry.ts","../src/ai/errors.ts","../src/ai/_generated.ts","../src/ai/examples.ts","../src/ai/syntax.ts","../src/ai/tools.ts"],"names":["parse","render"],"mappings":"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","file":"chunk-Z5UECSNM.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\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 // ── 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] as const;\n\nexport function getDiagramMeta(type: string): DiagramMeta | undefined {\n return DIAGRAM_REGISTRY.find((d) => d.type === type);\n}\n\nexport function getAllDiagramTypes(): DiagramType[] {\n return DIAGRAM_REGISTRY.map((d) => d.type);\n}\n","/**\n * Structured error type returned by the AI tool layer.\n *\n * The underlying per-diagram parsers each throw their own error class\n * (genogram.ParseError, SLDParseError, PedigreeParseError, ...). Some\n * carry line/column, some don't. {@link extractError} normalises any\n * thrown value into this shape via structural extraction — no parser\n * refactor required.\n */\nexport interface SchematexValidationError {\n /** 1-based line number where the error occurred, if the parser reported it. */\n line?: number;\n /** 1-based column, if reported. */\n column?: number;\n /** Source snippet from the offending line, if the parser captured it. */\n source?: string;\n /** Human-readable error message. */\n message: string;\n /** Optional remediation hint. */\n hint?: string;\n}\n\n/**\n * Extract a {@link SchematexValidationError} from any thrown value.\n *\n * Works across all per-diagram parser error classes because it reads\n * `.line`, `.column`, `.source` structurally when present. Unknown\n * throws (non-Error values) are coerced to a message-only error.\n */\nexport function extractError(err: unknown): SchematexValidationError {\n if (err instanceof Error) {\n const anyErr = err as Error & {\n line?: number;\n column?: number;\n source?: string;\n hint?: string;\n };\n return {\n line: typeof anyErr.line === \"number\" ? anyErr.line : undefined,\n column: typeof anyErr.column === \"number\" ? anyErr.column : undefined,\n source: typeof anyErr.source === \"string\" ? anyErr.source : undefined,\n message: err.message,\n hint: typeof anyErr.hint === \"string\" ? anyErr.hint : undefined,\n };\n }\n return { message: String(err) };\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-adaptive-cruise\",\n \"diagram\": \"block\",\n \"title\": \"Automotive adaptive cruise control (ACC)\",\n \"description\": \"Automotive ACC block diagram — radar range/range-rate, safety gap controller, speed controller, and powertrain plant — per ISO 15622.\",\n \"standard\": \"ISO 15622\",\n \"tags\": [\n \"block\",\n \"acc\",\n \"adaptive-cruise\",\n \"radar\",\n \"automotive\",\n \"iso15622\",\n \"safety\",\n \"gap-control\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"Automotive Adaptive Cruise Control (ACC)\\\"\\nv_set = signal(\\\"v_set (speed setpoint)\\\")\\nd_set = signal(\\\"d_set (desired gap)\\\")\\nradar = block(\\\"Radar Sensor\\\") [role: sensor]\\nd_actual = signal(\\\"d_actual (measured gap)\\\")\\nv_lead = signal(\\\"v_lead (lead vehicle speed)\\\")\\nHMI_override = signal(\\\"HMI override\\\")\\nerr_gap = sum(+d_set, -d_actual)\\nC_gap = block(\\\"Gap Controller\\\") [role: controller]\\nv_ref = signal(\\\"v_ref (speed reference)\\\")\\nerr_v = sum(+v_ref, -v_ego)\\nC_speed = block(\\\"Speed / Brake Controller\\\") [role: controller]\\na_cmd = signal(\\\"a_cmd (accel command)\\\")\\nG_powertrain = block(\\\"Engine + Brake + Vehicle Dynamics\\\") [role: plant]\\nv_ego = signal(\\\"v_ego (ego speed)\\\")\\nin -> v_set\\nin -> d_set\\nin -> HMI_override\\nradar -> d_actual\\nradar -> v_lead\\nd_set -> err_gap\\nd_actual -> err_gap\\nerr_gap -> C_gap\\nv_lead -> C_gap\\nHMI_override -> C_gap\\nC_gap -> v_ref\\nv_set -> C_gap\\nv_ref -> err_v\\nv_ego -> err_v\\nerr_v -> C_speed\\nHMI_override -> C_speed\\nC_speed -> a_cmd\\na_cmd -> G_powertrain\\nG_powertrain -> v_ego\\nv_ego -> err_v\",\n \"notes\": \"## Scenario\\n\\nISO 15622 defines the functional requirements for adaptive cruise control systems used in passenger cars and light trucks. An ACC system must maintain a safe headway gap to a lead vehicle while respecting the driver's commanded speed limit, handling cut-ins, and supporting driver override at any time. This block diagram represents the top-level functional decomposition that an ADAS systems engineer would draw during concept design.\\n\\n## Annotation key\\n\\n- `radar` — radar sensor block; outputs measured gap `d_actual` and lead vehicle speed `v_lead`\\n- `err_gap = sum(+d_set, -d_actual)` — gap error: difference between desired and actual following distance\\n- `C_gap` — gap controller; receives gap error and lead speed, outputs a speed reference `v_ref` bounded by `v_set`\\n- `C_speed` — speed/brake controller; inner loop tracking `v_ref`; also receives HMI override for driver intervention\\n- `G_powertrain` — combined powertrain plant: engine torque, brake system, and longitudinal vehicle dynamics\\n- `HMI_override` — driver override signal (brake pedal, throttle kick-down, or system disengage)\\n\\n## How to read\\n\\nThe driver's desired gap `d_set` and maximum speed `v_set` enter the gap controller, which also reads the radar-measured gap and lead vehicle speed. The gap controller outputs a target speed reference `v_ref` that is always bounded by `v_set`. The inner speed controller then drives the powertrain to track `v_ref`, closing the speed loop with `v_ego` feedback. Driver interventions via HMI override pre-empt both controllers, satisfying the ISO 15622 requirement that the driver always has priority. The two-loop cascade architecture lets the gap outer loop be tuned conservatively for comfort while the speed inner loop responds quickly to transient demands.\"\n },\n {\n \"slug\": \"block-cascade-control\",\n \"diagram\": \"block\",\n \"title\": \"Cascade temperature control\",\n \"description\": \"Two-loop cascade control for a heat exchanger — outer temperature loop sets the setpoint for the inner flow loop, reducing disturbance rejection time.\",\n \"standard\": \"Ogata control systems\",\n \"tags\": [\n \"block\",\n \"cascade\",\n \"temperature\",\n \"flow\",\n \"heat-exchanger\",\n \"feedback\",\n \"process-control\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"Cascade Temperature Control\\\"\\nr_temp = signal(\\\"r_temp (temp setpoint)\\\")\\nC_outer = block(\\\"Temp Controller C₁(s)\\\") [role: controller]\\nr_flow = signal(\\\"r_flow (inner setpoint)\\\")\\nC_inner = block(\\\"Flow Controller C₂(s)\\\") [role: controller]\\nvalve = block(\\\"Valve Actuator\\\") [role: actuator]\\nG_process = block(\\\"Heat Exchanger G(s)\\\") [role: plant]\\ny_temp = signal(\\\"y_temp (temperature)\\\")\\ny_flow = signal(\\\"y_flow (flow)\\\")\\nerr_outer = sum(+r_temp, -y_temp)\\nerr_inner = sum(+r_flow, -y_flow)\\nin -> r_temp\\nr_temp -> err_outer\\nerr_outer -> C_outer\\nC_outer -> r_flow\\nr_flow -> err_inner\\nerr_inner -> C_inner\\nC_inner -> valve\\nvalve -> G_process\\nG_process -> y_temp\\nG_process -> y_flow\\ny_temp -> err_outer\\ny_flow -> err_inner\",\n \"notes\": \"## Scenario\\n\\nCascade control appears in oil refineries, chemical reactors, and HVAC systems wherever a slow outer variable — temperature — must be decoupled from faster inner disturbances in flow or pressure. The outer loop generates a dynamic setpoint for the inner loop, so steam-flow upsets are rejected by the fast inner controller before they ever disturb the temperature sensor.\\n\\n## Annotation key\\n\\n- `err_outer = sum(+r_temp, -y_temp)` — outer summing junction computes temperature error\\n- `C_outer` — outer (primary) controller; its output `r_flow` becomes the inner loop's setpoint\\n- `err_inner = sum(+r_flow, -y_flow)` — inner summing junction computes flow error\\n- `C_inner` / `valve` — inner (secondary) controller driving the valve actuator\\n- `G_process -> y_flow` — flow measurement feedback closes the inner loop independently of temperature\\n\\n## How to read\\n\\nFollow the signal flow left to right. The operator's temperature setpoint `r_temp` enters the outer summing junction, which subtracts the measured temperature `y_temp` to produce a temperature error. The outer controller `C₁(s)` converts this error into a flow setpoint `r_flow`. The inner loop then tracks `r_flow` through its own summing junction, controller `C₂(s)`, and valve actuator, manipulating steam flow through the heat exchanger. Both feedback paths close independently, letting the inner loop reject flow disturbances roughly ten times faster than the outer loop can respond.\"\n },\n {\n \"slug\": \"block-feedforward-disturbance\",\n \"diagram\": \"block\",\n \"title\": \"Feedforward + feedback hybrid control\",\n \"description\": \"Feedforward disturbance compensation with PID feedback — the feedforward path cancels known load changes before they affect the output.\",\n \"standard\": \"Åström & Wittenmark\",\n \"tags\": [\n \"block\",\n \"feedforward\",\n \"feedback\",\n \"pid\",\n \"disturbance\",\n \"hybrid\",\n \"process-control\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"Feedforward + Feedback Hybrid Control\\\"\\nr = signal(\\\"r (setpoint)\\\")\\nd = signal(\\\"d (measurable disturbance)\\\")\\nC_ff = block(\\\"Feedforward Model C_ff(s)\\\") [role: model]\\nu_ff = signal(\\\"u_ff (feedforward action)\\\")\\nC_fb = block(\\\"PID Controller C_fb(s)\\\") [role: controller]\\nu_fb = signal(\\\"u_fb (feedback action)\\\")\\nG = block(\\\"Plant G(s)\\\") [role: plant]\\ny = signal(\\\"y (output)\\\")\\nerr = sum(+r, -y)\\nsum_u = sum(+u_ff, +u_fb)\\nin -> r\\nin -> d\\nd -> C_ff\\nC_ff -> u_ff\\nr -> err\\nerr -> C_fb\\nC_fb -> u_fb\\nu_ff -> sum_u\\nu_fb -> sum_u\\nsum_u -> G\\nd -> G\\nG -> y\\ny -> err\",\n \"notes\": \"## Scenario\\n\\nFeedforward control is used whenever a measurable disturbance — a load change, a feed-rate variation, or an ambient temperature shift — can be modeled and pre-cancelled before it propagates to the output. Pure feedback always reacts after the fact; the feedforward path acts simultaneously with the disturbance, ideally leaving zero steady-state offset for the PID loop to clean up.\\n\\n## Annotation key\\n\\n- `d` — measurable disturbance signal; enters both the feedforward model and the plant\\n- `C_ff` — feedforward model block; computes the control action needed to cancel `d` at the plant output\\n- `C_fb` — PID feedback controller; handles model errors, unmeasured disturbances, and setpoint tracking\\n- `sum_u = sum(+u_ff, +u_fb)` — summing junction that adds feedforward and feedback control actions\\n- `d -> G` — the disturbance also enters the plant directly, representing the real physical effect\\n\\n## How to read\\n\\nThe control signal `u` is the sum of two contributions: the feedforward action `u_ff`, computed directly from the measured disturbance `d` via the inverse plant model `C_ff(s)`, and the feedback action `u_fb` from the PID controller. When the feedforward model is accurate, `u_ff` cancels the disturbance effect at the plant input and the PID sees only residual error, dramatically reducing the load-change transient. The feedback loop remains essential to handle unmeasured disturbances and model inaccuracies.\"\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\": \"block-state-space-observer\",\n \"diagram\": \"block\",\n \"title\": \"Plant + Kalman observer (state estimator)\",\n \"description\": \"State-space system with a Kalman filter observer — the observer reconstructs unmeasured states x̂ from noisy output y for a GNC application.\",\n \"standard\": \"Kalman (1960) / modern control\",\n \"tags\": [\n \"block\",\n \"kalman\",\n \"observer\",\n \"state-space\",\n \"gnc\",\n \"aerospace\",\n \"estimator\"\n ],\n \"complexity\": 5,\n \"featured\": false,\n \"dsl\": \"blockdiagram \\\"State-Space Plant with Kalman Observer\\\"\\nu = signal(\\\"u (control input)\\\")\\nG_plant = block(\\\"Plant A, B, C, D\\\") [role: plant]\\ny = signal(\\\"y (noisy measurement)\\\")\\ny_hat = signal(\\\"ŷ (predicted output)\\\")\\nerr_obs = sum(+y, -y_hat)\\nK_obs = block(\\\"Kalman Observer L\\\") [role: observer]\\nx_hat = signal(\\\"x̂ (state estimate)\\\")\\nC_mat = block(\\\"Output Matrix C\\\") [role: model]\\nK_sf = block(\\\"State Feedback −K\\\") [role: controller]\\nin -> u\\nu -> G_plant\\nG_plant -> y\\ny -> err_obs\\nC_mat -> y_hat\\ny_hat -> err_obs\\nerr_obs -> K_obs\\nK_obs -> x_hat\\nu -> K_obs\\nx_hat -> C_mat\\nx_hat -> K_sf\\nK_sf -> u\",\n \"notes\": \"## Scenario\\n\\nGNC engineers, roboticists, and aerospace control designers routinely combine a state-space plant model with a Luenberger or Kalman observer to reconstruct full state vectors from partial, noisy measurements. This pattern is foundational in inertial navigation, attitude control, and autonomous vehicle state estimation — anywhere physical states (velocity, attitude rate, position) cannot all be measured directly.\\n\\n## Annotation key\\n\\n- `G_plant` — state-space plant defined by matrices A (dynamics), B (input), C (output), D (feedthrough)\\n- `K_obs` — Kalman observer (or Luenberger observer) with gain matrix L; corrects the state estimate using the innovation signal\\n- `err_obs = sum(+y, -y_hat)` — innovation: difference between measured output and predicted output\\n- `C_mat` — output matrix block; maps the estimated state x̂ to predicted output ŷ\\n- `K_sf` — state-feedback gain block; computes the control input u = −K x̂\\n\\n## How to read\\n\\nThe control input `u` drives both the real plant and the observer's internal model. The plant produces noisy measurement `y`; the observer predicts output `ŷ` from its own state estimate `x̂` via the output matrix `C`. The innovation `y − ŷ` is multiplied by the observer gain `L` and fed back to correct `x̂` continuously. The estimated state `x̂` then drives the state-feedback law `u = −K x̂`, closing the outer control loop. The separation principle guarantees that the observer and controller designs can be carried out independently.\"\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\": \"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\": \"circuit-555-astable\",\n \"diagram\": \"circuit\",\n \"title\": \"555 timer — astable LED blinker\",\n \"description\": \"NE555 astable oscillator driving a green LED at ~1 Hz — the classic maker circuit for learning timers, duty cycle, and RC time constants.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"555\",\n \"timer\",\n \"astable\",\n \"led\",\n \"blinker\",\n \"rc\",\n \"oscillator\",\n \"maker\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"circuit \\\"NE555 Astable LED Blinker (~1 Hz)\\\" netlist\\nV1 vcc 0 9V\\nU1 vcc vcc trig out rst ctrl dis thresh gnd 555_timer value=\\\"NE555\\\"\\nRa dis vcc 10k\\nRb dis thresh 68k\\nC1 thresh 0 10u\\nC2 ctrl 0 10n\\nRled out led_a 470\\nD1 led_a 0 led value=\\\"green\\\"\",\n \"notes\": \"## Scenario\\n\\nThe NE555 in astable mode is the first timer circuit every maker builds. It free-runs as an oscillator with no external trigger required. Ra and Rb charge capacitor C1; when C1 reaches 2/3 Vcc the 555 discharges it through Rb until it drops to 1/3 Vcc, then the cycle repeats. The result is a square wave at pin OUT that blinks the LED at approximately 1 Hz — visible to the human eye and ideal for learning about RC time constants and duty cycles.\\n\\n## Annotation key\\n\\n- `U1 ... 555_timer value=\\\"NE555\\\"` — NE555 timer IC; internally contains two comparators, an SR flip-flop, and a discharge transistor; the pin order is vcc, trig, out, rst, ctrl, dis, thresh, gnd\\n- `Ra dis vcc 10k` — charge resistor (10 kΩ) from Vcc to the discharge pin; limits charging current during the charging phase\\n- `Rb dis thresh 68k` — timing resistor (68 kΩ) between the discharge and threshold pins; used for both charging (with Ra) and discharging; larger Rb gives longer LOW time, controlling duty cycle\\n- `C1 thresh 0 10u` — 10 μF timing capacitor that charges and discharges between 1/3 Vcc and 2/3 Vcc; sets the oscillation period T ≈ 0.693 × (Ra + 2Rb) × C1 ≈ 1 s\\n- `C2 ctrl 0 10n` — 10 nF bypass capacitor on the control voltage pin (pin 5); filters noise that could modulate the timing thresholds\\n- `Rled out led_a 470` — current-limiting resistor (470 Ω) for the LED; limits forward current to ~(9V−2V)/470Ω ≈ 15 mA, a safe brightness level\\n- `D1 led_a 0 led value=\\\"green\\\"` — green LED (Vf ≈ 2.1 V); illuminates when OUT goes HIGH (~Vcc), dark when OUT is LOW\\n\\n## How to read\\n\\nThe circuit oscillates continuously without any external trigger. C1 charges through Ra + Rb toward Vcc. When the voltage at `thresh` crosses 2/3 Vcc the upper comparator sets the flip-flop, pulling `dis` low and allowing C1 to discharge through Rb alone to ground. When the voltage falls below 1/3 Vcc the lower comparator resets the flip-flop, `dis` goes high-impedance, and C1 starts charging again. The output pin (OUT) is HIGH during the charge phase and LOW during discharge. The HIGH period is t_high = 0.693 × (Ra + Rb) × C1 ≈ 0.54 s; the LOW period is t_low = 0.693 × Rb × C1 ≈ 0.47 s. The LED blinks with a duty cycle of ~53%.\"\n },\n {\n \"slug\": \"circuit-audio-preamp\",\n \"diagram\": \"circuit\",\n \"title\": \"Microphone preamp with phantom power\",\n \"description\": \"Balanced mic preamp circuit with +48V phantom power, differential input pair, and output buffer — the standard studio front-end per IEC 61938.\",\n \"standard\": \"IEC 61938 (phantom power)\",\n \"tags\": [\n \"preamp\",\n \"microphone\",\n \"phantom-power\",\n \"balanced\",\n \"audio\",\n \"differential\",\n \"studio\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Balanced Mic Preamp with +48V Phantom Power\\\" netlist\\nV48 phantom 0 48V\\nRph1 phantom xlr2 6.81k\\nRph2 phantom xlr3 6.81k\\nC1 xlr2 inp 47u\\nC2 xlr3 inn 47u\\nRterm1 inp 0 6.8k\\nRterm2 inn 0 6.8k\\nRg inp inn 390\\nU1 preout inp inn vcc vee instrumentation_amp value=\\\"INA217\\\"\\nRgain_set preout 0 1k\\nVcc vcc 0 15V\\nVee 0 vee 15V\\nC3 vcc 0 100n\\nC4 vee 0 100n\\nR_out preout vout 100\\nCout vout 0 10u\",\n \"notes\": \"## Scenario\\n\\nProfessional condenser microphones require two things from a preamp: +48 V phantom power delivered over the same XLR cable that carries the audio signal, and a differential (balanced) amplifier input that rejects the noise picked up by the cable. This circuit implements both per IEC 61938. The 6.81 kΩ phantom resistors supply DC bias to the microphone capsule while the coupling capacitors block that DC from the audio path. The INA217 instrumentation amplifier provides a gain of 1 + 6 kΩ/Rg = 100 (40 dB) with better than 80 dB CMRR, rejecting hum induced by long studio cable runs.\\n\\n## Annotation key\\n\\n- `Rph1, Rph2 phantom xlr2/3 6.81k` — precision 6.81 kΩ phantom feed resistors (IEC 61938 mandated value); supply equal +48 V to both XLR pins 2 and 3; equal voltage means no differential interference from the DC supply\\n- `C1, C2 ... 47u` — 47 μF DC-blocking coupling capacitors (electrolytic, non-polarized in practice); isolate the ±48 V phantom DC from the audio differential input while passing audio frequencies above ~50 Hz\\n- `Rterm1, Rterm2 inp/inn 0 6.8k` — 6.8 kΩ input termination resistors to ground; provide a DC return path for bias currents and define the source impedance seen by the INA\\n- `Rg inp inn 390` — external gain resistor for the INA217 (390 Ω); sets first-stage gain to 1 + 6 kΩ/390 ≈ 16.4×; combined with second stage total gain ≈ 100×\\n- `U1 ... instrumentation_amp value=\\\"INA217\\\"` — INA217 audio instrumentation amplifier; ultra-low noise (1 nV/√Hz), dual-supply ±15 V, designed for microphone preamp applications; rejects common-mode noise with >80 dB CMRR\\n- `C3, C4 vcc/vee 0 100n` — 100 nF decoupling capacitors on ±15 V rails; bypass high-frequency supply noise close to the IC pins\\n- `R_out / Cout` — output series resistor (100 Ω) and coupling capacitor (10 μF); isolate cable capacitance from the op-amp output and block DC from the next stage\\n\\n## How to read\\n\\nPhantom power is delivered by the +48 V rail through equal-value resistors to both XLR pins simultaneously. A condenser mic draws typically 5–10 mA DC through this path to polarize its capsule or power its internal JFET buffer. The audio signal is superimposed as a differential AC voltage (pin 2 in-phase, pin 3 out-of-phase) riding on the 48 V DC. Coupling capacitors C1 and C2 pass this AC to the differential inputs of the INA, blocking the 48 V DC entirely. The INA rejects the equal (common-mode) portion of any induced hum and amplifies only the difference — the actual microphone signal. The output is low-impedance buffered through R_out for driving long cable runs to the mixing console.\"\n },\n {\n \"slug\": \"circuit-buck-converter\",\n \"diagram\": \"circuit\",\n \"title\": \"Buck (step-down) SMPS\",\n \"description\": \"Synchronous buck converter with MOSFET switch, catch diode, inductor, and capacitor — produces regulated 3.3V from 12V at up to 3A.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"buck\",\n \"smps\",\n \"power-converter\",\n \"mosfet\",\n \"inductor\",\n \"step-down\",\n \"switching\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Buck (Step-Down) Converter 12V → 3.3V 3A\\\" netlist\\nVin vin 0 12V\\nCin vin 0 100u\\nM1 vin sw 0 nmos value=\\\"IRLZ44N\\\"\\nD1 sw 0 schottky value=\\\"SS34\\\"\\nL1 sw vout 22u\\nCout vout 0 220u\\nR1 vout fb 10k\\nR2 fb 0 3.83k\\nU1 sw gate fb vc vcc 0 dc_dc_converter value=\\\"LM2576-ADJ\\\"\\nRgate gate sw 10\\nVcc vcc 0 12V\",\n \"notes\": \"## Scenario\\n\\nThe buck converter is the workhouse of modern power electronics, used wherever a microcontroller, FPGA, or digital circuit needs a lower voltage from a higher supply. With Vin = 12 V and a duty cycle D ≈ 27.5%, the output is regulated to 3.3 V — the standard logic voltage for ARM Cortex-M, ESP32, and Raspberry Pi. Switching at 52 kHz (LM2576 internal oscillator) the inductor stores energy during the ON phase and releases it during the OFF phase, achieving efficiencies of 85–92%, far better than a linear regulator's maximum of 3.3/12 = 27.5%.\\n\\n## Annotation key\\n\\n- `M1 vin sw 0 nmos value=\\\"IRLZ44N\\\"` — N-channel MOSFET high-side switch (IRLZ44N, 55 V, 47 A, Rds_on = 22 mΩ); driven by PWM gate signal; ON for D fraction of each cycle\\n- `D1 sw 0 schottky value=\\\"SS34\\\"` — Schottky catch diode (SS34, 3 A, 40 V); conducts during the MOSFET OFF phase to provide a freewheeling current path for the inductor; Schottky chosen for low forward voltage (0.4 V) and fast recovery\\n- `L1 sw vout 22u` — 22 μH power inductor; stores energy as magnetic flux during ON phase, releases it during OFF phase; the key energy-storage element — larger L = smaller current ripple; rated for 3 A+ DC current without saturation\\n- `Cout vout 0 220u` — 220 μF low-ESR output capacitor; filters switching ripple; larger or lower-ESR cap reduces output ripple voltage ΔVout = ΔIL × ESR\\n- `R1, R2` — resistor divider (10 kΩ and 3.83 kΩ) from Vout to FB pin; sets output voltage Vout = 1.23 × (1 + R1/R2) ≈ 3.3 V\\n- `U1 ... dc_dc_converter value=\\\"LM2576-ADJ\\\"` — LM2576-ADJ PWM controller IC; senses FB voltage and adjusts duty cycle to regulate Vout; integrates oscillator, comparator, and driver\\n- `Rgate gate sw 10` — 10 Ω gate resistor; limits current during MOSFET switching to reduce EMI and gate ringing\\n\\n## How to read\\n\\nWhen M1 turns ON, current ramps up through L1, charging Cout and supplying the load. D1 is reverse-biased and off. When M1 turns OFF, the inductor's magnetic field collapses, inducing a voltage that forward-biases D1 and keeps current flowing through L1 to the load. The feedback divider R1/R2 tells U1's error amplifier whether Vout is above or below the 1.23 V reference. The controller increases duty cycle when Vout droops and decreases it when Vout rises. Energy conversion efficiency is high because M1 switches rather than dissipates: power loss is dominated by I²×Rds_on, diode forward drop, and inductor ESR rather than heat in a pass element.\"\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-full-wave-rectifier\",\n \"diagram\": \"circuit\",\n \"title\": \"Full-wave bridge rectifier\",\n \"description\": \"Diode bridge rectifier with filter capacitor and voltage regulator — converts AC mains to regulated DC, the power supply used in 90% of wall adapters.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"rectifier\",\n \"bridge\",\n \"diode\",\n \"filter\",\n \"power-supply\",\n \"ac-dc\",\n \"smoothing\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Full-Wave Bridge Rectifier with Regulator\\\" netlist\\nV1 ac1 ac2 ac 12V\\nT1 ac1 ac2 0 sec_p sec_n xfmr value=\\\"12:1\\\"\\nD1 sec_p rect 0 0 diode value=\\\"1N4007\\\"\\nD2 0 rect sec_n 0 diode value=\\\"1N4007\\\"\\nD3 sec_n rect 0 0 diode value=\\\"1N4007\\\"\\nD4 0 rect sec_p 0 diode value=\\\"1N4007\\\"\\nC1 rect 0 1000u\\nU1 rect vreg 0 reg value=\\\"LM7812\\\"\\nC2 vreg 0 10u\\nRload vreg 0 100\",\n \"notes\": \"## Scenario\\n\\nThe full-wave bridge rectifier converts both half-cycles of an AC waveform into pulsating DC, then smooths and regulates it. It is the most common power conversion topology — found in every linear bench supply, phone charger, and low-power wall adapter. T1 steps down mains AC; D1–D4 form the H-bridge; C1 smooths the 100 Hz ripple; the LM7812 regulator clamps the output to a stable 12 V regardless of load current up to 1 A.\\n\\n## Annotation key\\n\\n- `T1 ... xfmr value=\\\"12:1\\\"` — mains transformer stepping down 120 V AC to 12 V AC; isolates the secondary from the live mains\\n- `D1–D4 ... diode value=\\\"1N4007\\\"` — four 1N4007 silicon rectifier diodes (1 A, 1000 V PIV) arranged as an H-bridge; each conducts on alternate half-cycles, routing both polarities of the AC wave to the positive rail\\n- `C1 rect 0 1000u` — 1000 μF bulk filter capacitor; charges to the peak rectified voltage (~16.9 V) and discharges into the load between peaks, limiting ripple; larger capacitance = lower ripple\\n- `U1 rect vreg 0 reg value=\\\"LM7812\\\"` — three-terminal linear voltage regulator (LM7812); drops excess voltage as heat and outputs a stable 12 V; requires at least 2 V headroom (dropout voltage)\\n- `C2 vreg 0 10u` — output bypass capacitor (10 μF) on the regulator output; suppresses high-frequency oscillations and improves transient response\\n\\n## How to read\\n\\nDuring the positive AC half-cycle, D1 and D3 conduct, pushing current from `sec_p` through D1 to `rect`, then through the load, and back through D3 to `sec_n`. During the negative half-cycle, D2 and D4 conduct, reversing the secondary but still delivering current in the same direction to `rect`. The result is 100 Hz pulsating DC. C1 holds the voltage near the peak value between pulses. The LM7812 then regulates the rippled DC down to a clean 12 V output. Efficiency is limited by the two forward voltage drops (~1.4 V total across two diodes at once) and heat dissipation in the regulator.\"\n },\n {\n \"slug\": \"circuit-motor-driver\",\n \"diagram\": \"circuit\",\n \"title\": \"H-bridge DC motor driver\",\n \"description\": \"Dual H-bridge DC motor driver using L298N — forward, reverse, and brake modes via direction pins — for robotics and embedded control.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"h-bridge\",\n \"motor\",\n \"L298N\",\n \"driver\",\n \"robotics\",\n \"pwm\",\n \"dc-motor\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"circuit \\\"L298N H-Bridge DC Motor Driver\\\" netlist\\nVM vmot 0 12V\\nV5 vcc 0 5V\\nC1 vmot 0 100u\\nC2 vcc 0 100n\\nU1 vmot vcc in1 in2 ena out1 out2 0 generic_ic value=\\\"L298N\\\"\\nD1 out1 vmot 0 0 diode value=\\\"1N5819\\\"\\nD2 0 out1 0 0 diode value=\\\"1N5819\\\"\\nD3 out2 vmot 0 0 diode value=\\\"1N5819\\\"\\nD4 0 out2 0 0 diode value=\\\"1N5819\\\"\\nMotor out1 out2 motor value=\\\"DC 12V 2A\\\"\\nIn1 in1 mcu_in1 port value=\\\"IN1\\\"\\nIn2 in2 mcu_in2 port value=\\\"IN2\\\"\\nEna ena mcu_pwm port value=\\\"ENA PWM\\\"\",\n \"notes\": \"## Scenario\\n\\nThe L298N is the standard H-bridge driver for 3 V–46 V DC motors in robotics, CNC, and embedded projects. It contains two full H-bridges (only one used here), each capable of 2 A continuous. Direction is controlled by IN1 and IN2 logic inputs from a microcontroller; speed is controlled by applying PWM to ENA. Forward: IN1=HIGH, IN2=LOW. Reverse: IN1=LOW, IN2=HIGH. Brake: both HIGH or both LOW. The four Schottky diodes protect the bridge transistors from inductive kick-back when the motor coils resist switching.\\n\\n## Annotation key\\n\\n- `U1 ... generic_ic value=\\\"L298N\\\"` — L298N dual H-bridge driver IC; integrates four NPN Darlington transistors arranged as two full H-bridges; accepts 5 V logic inputs and switches a separate 12 V motor supply; max 46 V, 2 A per channel\\n- `VM vmot 0 12V` — motor supply rail (12 V); electrically separate from the logic supply to prevent motor switching noise from corrupting microcontroller operation\\n- `C1 vmot 0 100u` — 100 μF bulk decoupling capacitor on the motor supply; absorbs current spikes when the motor switches direction or stalls; prevents VMOT drooping and resetting the microcontroller\\n- `C2 vcc 0 100n` — 100 nF ceramic decoupling capacitor on the 5 V logic supply; high-frequency bypass close to the IC logic pins\\n- `D1–D4 ... diode value=\\\"1N5819\\\"` — four 1N5819 Schottky flyback diodes (1 A, 40 V, low forward voltage); one diode across each motor terminal to VMot and to GND; clamp the inductive spike when the H-bridge transistors switch off, protecting the IC from voltage transients that can exceed 100 V in an unprotected circuit\\n- `Motor out1 out2 motor value=\\\"DC 12V 2A\\\"` — 12 V DC motor; current flows from OUT1 to OUT2 for forward, OUT2 to OUT1 for reverse; motor speed is proportional to average voltage = Vm × duty_cycle\\n- `In1, In2, Ena` — port terminals from the microcontroller; IN1 and IN2 are 5 V logic signals; ENA is the PWM input that modulates average power to the motor\\n\\n## How to read\\n\\nThe L298N switches the 12 V motor supply through two transistor pairs. When IN1 is HIGH and IN2 is LOW, the top-left and bottom-right transistors turn on, connecting VMot to OUT1 and OUT2 to GND — motor spins forward. When both transistors of one polarity are off, the motor's inductive winding tries to maintain current flow; without the flyback diodes the resulting voltage spike (Ldi/dt) could reach hundreds of volts and destroy the IC. Schottky diodes D1–D4 provide an immediate return path for this energy back to VMot. PWM on ENA chops the drive voltage at a frequency the motor inductance can filter, giving smooth speed control from 0–100% without resistive power loss.\"\n },\n {\n \"slug\": \"circuit-opamp-instrumentation\",\n \"diagram\": \"circuit\",\n \"title\": \"3-op-amp instrumentation amplifier\",\n \"description\": \"Three-op-amp instrumentation amplifier with gain resistor Rg — the standard front-end for differential sensors and biomedical amplifiers.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"opamp\",\n \"instrumentation-amplifier\",\n \"differential\",\n \"biomedical\",\n \"sensor\",\n \"gain\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"circuit \\\"3-Op-Amp Instrumentation Amplifier\\\" netlist\\nV_pos vcc 0 15V\\nV_neg 0 vee 15V\\nVp vp 0 ac 5mV\\nVn vn 0 ac 0V\\nU1A u1a_out vn u1a_out vcc vee opamp value=\\\"OP07\\\"\\nU1B u1b_out vp u1b_out vcc vee opamp value=\\\"OP07\\\"\\nRg u1a_out u1b_out 2k\\nR1a u1a_out mid1 25k\\nR1b mid1 u2_out 25k\\nR2a u1b_out mid2 25k\\nR2b mid2 0 25k\\nU2 u2_out mid1 mid2 vcc vee opamp value=\\\"OP07\\\"\",\n \"notes\": \"## Scenario\\n\\nThe three-op-amp instrumentation amplifier (INA) extracts tiny differential signals — the voltage difference between two inputs — while rejecting common-mode noise that appears on both inputs simultaneously. It is the standard front-end for ECG electrodes, Wheatstone bridge pressure sensors, thermocouple interfaces, and any measurement where the signal source is floating or noisy. Gain = 1 + 50 kΩ/Rg; with Rg = 2 kΩ, Gain = 26.\\n\\n## Annotation key\\n\\n- `U1A / U1B` — the two input buffer op-amps; each unity-buffers one differential input while the shared Rg resistor between their outputs sets the gain\\n- `Rg u1a_out u1b_out 2k` — single gain-setting resistor; decreasing Rg increases gain (Gain = 1 + 50 kΩ/Rg); this is the only component to change when adjusting gain\\n- `R1a, R1b, R2a, R2b` — precision resistor divider network (matched 25 kΩ) forming the differential amplifier around U2; must be tightly matched for high CMRR\\n- `U2` — the output difference amplifier stage; subtracts the two buffered outputs and applies the fixed ×1 difference gain; the mid-point taps provide the subtraction node\\n\\n## How to read\\n\\nStage 1 (U1A and U1B) buffers each input terminal independently. The voltage across Rg equals the differential input voltage; because both op-amps force their inverting inputs to match their non-inverting inputs (virtual short), the gain current I = Vdiff/Rg flows through both R1a resistors, so each output shifts by Vdiff × R1/Rg. Stage 2 (U2 with matched R2 network) performs precision subtraction, rejecting any common-mode voltage that rides on both U1A and U1B outputs equally. The result at `u2_out` is the amplified differential signal with common-mode rejection ratios exceeding 100 dB in precision designs.\"\n },\n {\n \"slug\": \"circuit-opamp-inverting\",\n \"diagram\": \"circuit\",\n \"title\": \"Inverting op-amp amplifier\",\n \"description\": \"Inverting op-amp topology with input resistor Rin, feedback resistor Rf — gain = −Rf/Rin — the first op-amp circuit every EE student builds.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"opamp\",\n \"inverting\",\n \"amplifier\",\n \"feedback\",\n \"gain\",\n \"analog\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"circuit \\\"Inverting Op-Amp Amplifier (Gain = −10)\\\" netlist\\nVin in 0 1V\\nRin in inv 10k\\nRf out inv 100k\\nRbias ninv 0 9.1k\\nV_pos vcc 0 15V\\nV_neg 0 vee 15V\\nU1 out inv ninv vcc vee opamp value=\\\"LM741\\\"\",\n \"notes\": \"## Scenario\\n\\nThe inverting amplifier is the canonical op-amp circuit. A signal at `Vin` is amplified by a gain determined entirely by the ratio of two resistors: Gain = −Rf / Rin = −100 kΩ / 10 kΩ = −10. The negative sign indicates a 180° phase inversion. With Vin = 1 V the output is −10 V. The circuit is used wherever a precise, stable, negative gain is needed — audio mixing consoles, instrumentation signal conditioning, and ADC driver stages.\\n\\n## Annotation key\\n\\n- `Rin in inv 10k` — input resistor (10 kΩ) converts the input voltage into a current that flows into the inverting input; sets the input impedance seen by the source\\n- `Rf out inv 100k` — feedback resistor (100 kΩ) connects the output back to the inverting input; the ratio Rf/Rin sets the magnitude of gain\\n- `Rbias ninv 0 9.1k` — bias-compensation resistor at the non-inverting input; equals Rin ∥ Rf (≈ 9.1 kΩ) to cancel input bias current offset\\n- `U1 ... opamp value=\\\"LM741\\\"` — op-amp (LM741); virtual-ground principle forces both inputs to the same voltage, so inv ≈ 0 V\\n- `V_pos / V_neg` — dual ±15 V supply rails powering the op-amp\\n\\n## How to read\\n\\nThe op-amp's non-inverting input is tied to ground through Rbias. By the virtual-ground rule the inverting input is also held at 0 V by negative feedback. Therefore all of Vin appears across Rin, driving a current I = Vin/Rin into the summing node. The same current must flow through Rf (no current enters the ideal op-amp input), so the output adjusts to Vout = −I × Rf = −Vin × (Rf/Rin). Changing only Rf changes the gain without affecting input impedance. Multiple Rin/Vin pairs can be summed into the same node to build a weighted summing amplifier.\"\n },\n {\n \"slug\": \"circuit-rc-lowpass\",\n \"diagram\": \"circuit\",\n \"title\": \"RC low-pass filter\",\n \"description\": \"First-order RC low-pass filter with −3 dB corner frequency formula — the passive filter taught in every intro electronics course.\",\n \"standard\": \"IEEE 315\",\n \"tags\": [\n \"rc\",\n \"filter\",\n \"low-pass\",\n \"passive\",\n \"frequency\",\n \"-3db\",\n \"hobbyist\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"circuit \\\"RC Low-Pass Filter (fc = 1 kHz)\\\" netlist\\nVin in 0 ac 1V\\nR1 in out 10k\\nC1 out 0 15.9n\",\n \"notes\": \"## Scenario\\n\\nThe RC low-pass filter is the most fundamental passive filter in electronics. It passes low-frequency signals while attenuating frequencies above the corner frequency. With R1 = 10 kΩ and C1 = 15.9 nF the −3 dB corner frequency is exactly 1 kHz, calculated as fc = 1 / (2π × R × C). Below fc the output tracks the input; above fc the output rolls off at −20 dB/decade.\\n\\n## Annotation key\\n\\n- `Vin in 0 ac 1V` — AC voltage source: positive terminal at node `in`, negative at ground `0`, amplitude 1 V\\n- `R1 in out 10k` — series resistor R1 (10 kΩ) between the input node `in` and the intermediate node `out`; blocks high-frequency current\\n- `C1 out 0 15.9n` — shunt capacitor C1 (15.9 nF) from node `out` to ground; its reactance Xc = 1/(2πfC) decreases as frequency rises, diverting high-frequency energy to ground\\n\\n## How to read\\n\\nSignal enters at `in` and must pass through R1 before reaching `out`. C1 provides an impedance path to ground in parallel with the output load. At low frequencies C1 looks like an open circuit so nearly all signal appears at `out`. As frequency rises, C1's impedance drops and it shunts an increasing fraction of the signal to ground. At fc = 1 kHz the resistor and capacitor impedances are equal and output power is halved (−3 dB, voltage × 0.707). This RC combination is used everywhere: audio tone shaping, anti-aliasing before ADC inputs, power-supply decoupling, and noise filtering on sensor signals.\"\n },\n {\n \"slug\": \"decisiontree-buy-vs-lease-ev\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Buy vs. lease an electric vehicle\",\n \"description\": \"Howard-Raiffa expected-value tree for the buy/lease/used-EV decision — with resale probability and incentive chance nodes.\",\n \"standard\": \"Raiffa & Schlaifer (1961)\",\n \"tags\": [\n \"decision-analysis\",\n \"ev\",\n \"buy-vs-lease\",\n \"expected-value\",\n \"consumer\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:decision \\\"EV Acquisition Decision\\\"\\n\\ndecision \\\"Which acquisition path?\\\"\\n choice \\\"Buy new EV\\\"\\n chance \\\"Federal tax credit eligible?\\\"\\n prob 0.7 chance \\\"Resale market in 5yr (w/ credit)\\\"\\n prob 0.55 end \\\"Strong resale + credit\\\" payoff=28500\\n prob 0.45 end \\\"Weak resale + credit\\\" payoff=16000\\n prob 0.3 chance \\\"Resale market in 5yr (no credit)\\\"\\n prob 0.55 end \\\"Strong resale, no credit\\\" payoff=21000\\n prob 0.45 end \\\"Weak resale, no credit\\\" payoff=8500\\n choice \\\"Lease EV 3yr\\\"\\n end \\\"Predictable lease cost\\\" payoff=14000\\n choice \\\"Buy used EV\\\"\\n chance \\\"Battery health ≥ 80%?\\\"\\n prob 0.6 end \\\"Good battery — low TCO\\\" payoff=22000\\n prob 0.4 end \\\"Battery replacement needed\\\" payoff=8000\",\n \"notes\": \"## Scenario\\n\\nA household is choosing between three electric vehicle acquisition paths: buying new (eligible for a $7,500 federal tax credit with 70% probability, depending on income and vehicle MSRP cap), leasing for three years at a fixed all-in cost, or buying used. The buy-new path carries two sequential chance nodes — credit eligibility then a five-year resale market outcome — while used carries battery-health uncertainty. Payoffs represent net five-year economic value (savings versus equivalent ICE ownership, residual value, minus acquisition and maintenance costs).\\n\\n## Annotation key\\n\\n- `decision \\\"…\\\"` — decision node; actor chooses a branch\\n- `choice \\\"…\\\"` — label on a decision branch\\n- `chance \\\"…\\\"` — chance node; nature chooses; `prob N` on children must sum to 1\\n- `end \\\"…\\\" payoff=N` — terminal leaf with net five-year economic value in dollars\\n- `prob N` — probability (0–1) on a chance branch\\n- EV rollback: chance = probability-weighted sum; decision = max child EV\\n\\n## How to read\\n\\nRoll back from leaves to root. Buy-new EV (with credit branch): 0.55 × 28,500 + 0.45 × 16,000 = **24,075**; without credit: 0.55 × 21,000 + 0.45 × 8,500 = **19,275**. Combined: 0.7 × 24,075 + 0.3 × 19,275 = **22,635**. Lease: flat **14,000**. Used EV: 0.6 × 22,000 + 0.4 × 8,000 = **16,400**. Under these assumptions *Buy new EV* dominates, largely because the 70% credit probability shifts the overall EV substantially upward. Sensitivity analysis on credit eligibility probability and the five-year resale spread is where the real MBA discussion lives.\"\n },\n {\n \"slug\": \"decisiontree-go-nogo-product\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Product launch go/no-go decision\",\n \"description\": \"Stage-gate launch decision with market-size chance node, competitor-response chance, and NPV terminal values for a PM strategy review.\",\n \"standard\": \"Raiffa & Schlaifer (1961)\",\n \"tags\": [\n \"launch\",\n \"go-nogo\",\n \"npv\",\n \"strategy\",\n \"product\",\n \"chance\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:decision \\\"Product Launch Strategy\\\"\\n\\ndecision \\\"Launch strategy?\\\"\\n choice \\\"Launch Q1 (full)\\\"\\n chance \\\"Market reception\\\"\\n prob 0.4 chance \\\"Competitor copies within 6mo? (strong)\\\"\\n prob 0.5 end \\\"Strong + copied\\\" payoff=3200000\\n prob 0.5 end \\\"Strong + defended\\\" payoff=5800000\\n prob 0.35 chance \\\"Competitor copies within 6mo? (moderate)\\\"\\n prob 0.5 end \\\"Moderate + copied\\\" payoff=1400000\\n prob 0.5 end \\\"Moderate + defended\\\" payoff=2600000\\n prob 0.25 end \\\"Weak reception\\\" payoff=400000\\n choice \\\"Launch Q3 (scoped)\\\"\\n chance \\\"Market reception (scoped)\\\"\\n prob 0.45 end \\\"Strong scoped\\\" payoff=3100000\\n prob 0.35 end \\\"Moderate scoped\\\" payoff=1800000\\n prob 0.20 end \\\"Weak scoped\\\" payoff=600000\\n choice \\\"No launch\\\"\\n end \\\"Saved development cost\\\" payoff=900000\",\n \"notes\": \"## Scenario\\n\\nA PM team is evaluating three paths ahead of an annual planning cycle: a full Q1 launch with the complete feature set, a scoped Q3 launch targeting the highest-confidence segments, and a no-launch option that recovers the estimated development spend. The Q1 full-launch path carries two sequential chance nodes — market reception (strong/moderate/weak) followed, for the non-weak outcomes, by a competitor-response chance (copies vs. defends). Payoffs are five-year NPV estimates in dollars, net of launch and ongoing operating costs.\\n\\n## Annotation key\\n\\n- `decision \\\"…\\\"` — decision node; PM team chooses a branch\\n- `choice \\\"…\\\"` — label on a decision branch\\n- `chance \\\"…\\\"` — chance node; market or competitor behavior; `prob N` sums to 1 per node\\n- `end \\\"…\\\" payoff=N` — terminal leaf with five-year NPV in dollars\\n- `prob N` — probability (0–1) on a chance branch\\n- EV rollback: chance = probability-weighted sum; decision = max child EV\\n\\n## How to read\\n\\nFor Q1 full launch: strong-reception EV = 0.5 × 3,200,000 + 0.5 × 5,800,000 = **4,500,000**; moderate EV = 0.5 × 1,400,000 + 0.5 × 2,600,000 = **2,000,000**. Full-launch EV = 0.40 × 4,500,000 + 0.35 × 2,000,000 + 0.25 × 400,000 = **2,600,000**. Scoped-Q3 EV = 0.45 × 3,100,000 + 0.35 × 1,800,000 + 0.20 × 600,000 = **2,118,000**. No launch: **900,000**. Q1 full launch produces the highest EV, but the moderate-reception + copied scenario at $1.4M is a painful downside worth stress-testing — reducing competitor copy probability from 0.5 to 0.3 in that branch raises the EV meaningfully and may justify a launch accelerator investment.\"\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-sklearn\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Iris species classifier (scikit-learn CART)\",\n \"description\": \"The classic sklearn Iris CART decision tree — three species, two splits on petal length and width, rendered from a functional ML-tree description.\",\n \"standard\": \"Breiman CART (1984)\",\n \"tags\": [\n \"cart\",\n \"sklearn\",\n \"iris\",\n \"classification\",\n \"ml\",\n \"decision-tree\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"decisiontree:ml \\\"Iris Classifier\\\"\\n\\nsplit \\\"petal length (cm) ≤ 2.45\\\"\\n true leaf \\\"Setosa\\\" [support=50, impurity=0.0, class=setosa]\\n false split \\\"petal width (cm) ≤ 1.75\\\"\\n true leaf \\\"Versicolor\\\" [support=47, impurity=0.168, class=versicolor]\\n false leaf \\\"Virginica\\\" [support=45, impurity=0.043, class=virginica]\",\n \"notes\": \"## Scenario\\n\\nThe Iris dataset — 150 samples of three species (Iris setosa, versicolor, and virginica) measured across four features — is the canonical teaching example for classification. A CART tree trained with scikit-learn `DecisionTreeClassifier(max_depth=2)` produces exactly this two-level tree. Setosa is perfectly linearly separable on petal length alone; versicolor and virginica require a second split on petal width. The resulting tree achieves ~96% cross-validated accuracy.\\n\\n## Annotation key\\n\\n- `split \\\"condition\\\"` — internal node; routes left (`true`) when condition holds, right (`false`) when it does not\\n- `true` / `false` — branch direction prefix indicating which child is reached when the split condition evaluates to that boolean\\n- `leaf \\\"label\\\"` — terminal classification node\\n- `[support=N]` — number of training samples reaching this leaf\\n- `[impurity=N]` — Gini impurity at the node (0 = pure, 0.5 = maximally impure for binary)\\n- `[class=…]` — majority class label at the leaf\\n\\n## How to read\\n\\nStart at the root split. If petal length ≤ 2.45 cm, the sample is classified as **Setosa** immediately (Gini = 0, perfectly pure — all 50 setosa training samples land here). Otherwise, evaluate petal width: ≤ 1.75 cm predicts **Versicolor** (47 samples, Gini = 0.168 — a small number of virginica blur this boundary); > 1.75 cm predicts **Virginica** (45 samples, Gini = 0.043 — nearly pure). This tree is shallow enough to fit on an index card and remains the first model every ML course deploys.\"\n },\n {\n \"slug\": \"decisiontree-is-it-mammal\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Is it a mammal? — taxonomy key\",\n \"description\": \"Biology identification key for mammals vs. other vertebrates — warm-blooded, hair, milk — the canonical taxonomy decision tree for K-12 science.\",\n \"standard\": \"Linnaean taxonomy\",\n \"tags\": [\n \"taxonomy\",\n \"mammal\",\n \"biology\",\n \"classification\",\n \"k12\",\n \"teaching\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"decisiontree:taxonomy \\\"Is it a mammal?\\\"\\n\\nquestion \\\"Is it a vertebrate?\\\"\\n no: answer \\\"Not a mammal (invertebrate)\\\"\\n yes: question \\\"Is it warm-blooded?\\\"\\n no: answer \\\"Not a mammal (reptile, fish, or amphibian)\\\"\\n yes: question \\\"Does it have hair or fur?\\\"\\n no: answer \\\"Not a mammal (likely a bird)\\\"\\n yes: question \\\"Does the female nurse young with milk?\\\"\\n no: answer \\\"Not a mammal\\\"\\n yes: question \\\"Does it lay eggs?\\\"\\n yes: answer \\\"Monotreme (e.g. platypus, echidna)\\\"\\n no: question \\\"Does it have a pouch for young?\\\"\\n yes: answer \\\"Marsupial (e.g. kangaroo, opossum)\\\"\\n no: answer \\\"Placental mammal\\\"\",\n \"notes\": \"## Scenario\\n\\nThis is the classic dichotomous identification key taught in K-12 biology to introduce students to the class Mammalia. Working through four shared mammalian characteristics — vertebrate skeleton, endothermy (warm-bloodedness), hair or fur, and lactation — eliminates all other vertebrate classes before arriving at the three mammalian subclasses: Monotremata (egg-laying), Marsupialia (pouched), and Placentalia (placental). The key is deliberately top-down so students can stop as soon as they reach a leaf, rather than having to memorize all five criteria upfront.\\n\\n## Annotation key\\n\\n- `question \\\"…\\\"` — internal node; student or teacher evaluates the criterion for the observed animal\\n- `answer \\\"…\\\"` — terminal classification leaf\\n- `yes:` / `no:` — branch taken based on the presence or absence of the stated trait\\n- Indentation (2 spaces per level) defines parent-child nesting\\n- All five yes-branches must be traversed to reach a placental mammal leaf\\n\\n## How to read\\n\\nStart at the root. An earthworm exits immediately at the first node (not a vertebrate). A salmon exits at the second (cold-blooded). A sparrow exits at the third (no hair — feathers instead). A dog passes all four shared-mammal criteria and reaches the egg-laying question: dogs do not lay eggs, and they lack a pouch, so the leaf is *Placental mammal*. A duck-billed platypus passes all mammal criteria but exits at the egg-laying question as a *Monotreme* — making it the classic counterexample teachers use to show students that classification rules encode real biology, not just intuition.\"\n },\n {\n \"slug\": \"decisiontree-litigation-settle\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Litigation vs. settlement analysis\",\n \"description\": \"Expected-value analysis of settling a $2M breach-of-contract claim vs. going to trial — with verdict probability and appeal chance nodes.\",\n \"standard\": \"Raiffa & Schlaifer (1961)\",\n \"tags\": [\n \"litigation\",\n \"settlement\",\n \"legal\",\n \"expected-value\",\n \"trial\",\n \"appeal\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:decision \\\"Litigation Strategy\\\"\\n\\ndecision \\\"Litigation strategy?\\\"\\n choice \\\"Settle now\\\"\\n end \\\"Settlement payment\\\" payoff=-350000\\n choice \\\"Proceed to trial\\\"\\n chance \\\"Verdict\\\"\\n prob 0.55 chance \\\"Plaintiff appeals? (defense wins)\\\"\\n prob 0.3 chance \\\"Appeal outcome\\\"\\n prob 0.4 end \\\"Reversed on appeal\\\" payoff=0\\n prob 0.6 end \\\"Upheld on appeal\\\" payoff=-2200000\\n prob 0.7 end \\\"No appeal — defense prevails\\\" payoff=0\\n prob 0.45 end \\\"Plaintiff verdict — damages + fees\\\" payoff=-2000000\",\n \"notes\": \"## Scenario\\n\\nA corporate defendant faces a $2 million breach-of-contract claim. Outside counsel has assessed a 55% probability of a defense verdict at trial and a 45% probability of a plaintiff verdict (full damages plus attorney fees). If the defense wins, there is a 30% chance the plaintiff appeals; an appeal resolves with a 40% probability of reversal (cost: zero) and a 60% probability of affirmance, which adds appellate costs bringing total exposure to $2.2M. The client can alternatively settle immediately for $350,000. All payoffs are expressed as costs to the defendant (negative = outflow).\\n\\n## Annotation key\\n\\n- `decision \\\"…\\\"` — decision node; counsel and client choose the path\\n- `choice \\\"…\\\"` — label on a decision branch\\n- `chance \\\"…\\\"` — chance node; court or opposing party behavior; `prob N` sums to 1\\n- `end \\\"…\\\" payoff=N` — terminal leaf; negative values represent costs to defendant\\n- `prob N` — probability (0–1) on a chance branch\\n- EV rollback: chance = probability-weighted sum; decision = max child EV (least negative)\\n\\n## How to read\\n\\nRoll back from leaves. Appeal-outcome EV: 0.4 × 0 + 0.6 × −2,200,000 = **−1,320,000**. Defense-wins-verdict branch EV: 0.3 × −1,320,000 + 0.7 × 0 = **−396,000**. Trial EV: 0.55 × −396,000 + 0.45 × −2,000,000 = **−1,117,800**. Settlement: **−350,000**. Under these probability estimates, settling for $350,000 is the rational choice — it avoids the −$1.12M expected cost of going to trial. The key sensitivity is the defense-verdict probability: if counsel is more than ~75% confident of winning at trial, the EV of proceeding drops below −350,000 and trial becomes preferred.\"\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\": \"decisiontree-triage-chest-pain\",\n \"diagram\": \"decisiontree\",\n \"title\": \"ED chest pain triage\",\n \"description\": \"Emergency department chest-pain triage algorithm — HEART score pathway, STEMI/NSTEMI rule-out, and disposition decision for the ED physician.\",\n \"standard\": \"AHA/ACC 2021 Chest Pain Guidelines\",\n \"tags\": [\n \"triage\",\n \"chest-pain\",\n \"ed\",\n \"stemi\",\n \"heart-score\",\n \"clinical\",\n \"aha\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"decisiontree:taxonomy \\\"ED Chest Pain Triage\\\"\\n\\nquestion \\\"ECG: ST elevation present?\\\"\\n yes: answer \\\"Activate cath lab — STEMI protocol\\\"\\n no: question \\\"Troponin elevated at 0h or 3h?\\\"\\n yes: question \\\"Dynamic troponin rise (≥ 3 ng/L delta)?\\\"\\n yes: answer \\\"NSTEMI confirmed — cardiology consult, anticoagulate\\\"\\n no: answer \\\"Possible NSTEMI — repeat troponin at 6h\\\"\\n no: question \\\"HEART score ≥ 4?\\\"\\n yes: answer \\\"High risk — observation unit + stress test or CTA\\\"\\n no: question \\\"All low-risk features present?\\\"\\n yes: answer \\\"Discharge — outpatient follow-up within 72h\\\"\\n no: answer \\\"Observation — shared decision making with patient\\\"\",\n \"notes\": \"## Scenario\\n\\nChest pain accounts for roughly 8 million ED visits per year in the United States. The AHA/ACC 2021 Chest Pain Guidelines provide a tiered rule-out pathway: first exclude STEMI via ECG, then use high-sensitivity troponin at 0h and 3h to distinguish NSTEMI from unstable angina or non-cardiac causes, and finally apply the HEART score (History, ECG, Age, Risk factors, Troponin) to stratify remaining patients into high-risk observation vs. safe discharge. This tree encodes the core algorithmic structure for a busy ED attending.\\n\\n## Annotation key\\n\\n- `question \\\"…\\\"` — internal clinical decision node; physician evaluates the criterion\\n- `answer \\\"…\\\"` — terminal disposition or action\\n- `yes:` / `no:` — branch label indicating the clinical finding\\n- HEART score: 0–3 low risk, 4–6 moderate, 7–10 high risk\\n- Dynamic troponin: delta ≥ 3 ng/L between 0h and 3h draws meets ESC high-sensitivity criterion\\n\\n## How to read\\n\\nEntry is the 12-lead ECG. ST elevation routes directly to cath-lab activation — time is myocardium and no further branching is needed. Absence of ST elevation triggers the troponin pathway: a positive draw at either time point prompts delta assessment to distinguish true NSTEMI from a chronic elevation; a negative troponin advances to HEART score stratification. A score of 4 or higher mandates observation-unit admission with functional testing; a score below 4 with all low-risk clinical features present supports discharge with prompt outpatient follow-up. The final branch — observation with shared decision making — captures the borderline-HEART-score patient where physician judgment, patient preference, and social circumstances all contribute to disposition.\"\n },\n {\n \"slug\": \"decisiontree-xgboost-churn\",\n \"diagram\": \"decisiontree\",\n \"title\": \"Customer churn prediction tree (XGBoost)\",\n \"description\": \"One tree from an XGBoost churn model — days since last login, MRR tier, support tickets — showing how gradient boosting splits differ from CART.\",\n \"standard\": \"Chen & Guestrin XGBoost (2016)\",\n \"tags\": [\n \"xgboost\",\n \"churn\",\n \"ml\",\n \"gradient-boosting\",\n \"saas\",\n \"prediction\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"decisiontree:ml \\\"Churn Prediction Tree (XGBoost)\\\"\\n\\nsplit \\\"days_since_login > 21\\\"\\n true split \\\"mrr_tier < 2\\\"\\n true leaf \\\"High churn risk\\\" [score=0.72, class=churn]\\n false leaf \\\"Medium risk — monitor\\\" [score=0.41, class=churn]\\n false split \\\"support_tickets_30d > 3\\\"\\n true leaf \\\"Medium risk — support-driven\\\" [score=0.38, class=churn]\\n false leaf \\\"Low churn risk\\\" [score=0.09, class=retain]\",\n \"notes\": \"## Scenario\\n\\nA SaaS company trains an XGBoost churn model on 90 days of product usage data. This is one representative tree from the ensemble, illustrating the three strongest churn signals in the dataset: recency of login (days since last login > 21 is the dominant split), MRR tier (lower-tier accounts churn faster when disengaged), and recent support ticket volume (elevated tickets correlate with frustration even among recently active users). Unlike a standalone CART tree, XGBoost trees output raw scores (log-odds contributions) that are summed across the ensemble before sigmoid transformation — the `score` values shown are per-tree contributions, not final probabilities.\\n\\n## Annotation key\\n\\n- `split \\\"condition\\\"` — internal split node; `true` branch when condition holds\\n- `true` / `false` — branch direction prefix\\n- `leaf \\\"label\\\"` — terminal node with a descriptive risk label\\n- `[score=N]` — raw XGBoost leaf score (log-odds contribution from this tree)\\n- `[class=…]` — dominant class assignment at this leaf\\n- XGBoost does not use Gini/entropy impurity; splits are chosen to maximize second-order gradient gain\\n\\n## How to read\\n\\nStart at the root. Accounts with more than 21 days since last login are immediately flagged: if they are also on MRR tier 0 or 1 (lowest-value tiers), the leaf score is 0.72 — the highest churn signal in this tree. High-tier disengaged accounts score 0.41, indicating meaningful but lower risk, consistent with higher switching costs. For recently active accounts (login ≤ 21 days), elevated support tickets (> 3 in 30 days) push score to 0.38 — a product-experience alert — while accounts that are both active and support-quiet score 0.09, the healthiest segment. In production, this tree's scores are summed with hundreds of sibling trees and passed through a sigmoid to yield a final churn probability between 0 and 1.\"\n },\n {\n \"slug\": \"ecomap-elderly-caregiver\",\n \"diagram\": \"ecomap\",\n \"title\": \"Aging-in-place caregiver support network\",\n \"description\": \"Ecomap for an 81-year-old woman aging-in-place: family caregivers, home health aide, Medicare, faith community, and senior center connections.\",\n \"standard\": \"Hartman 1978\",\n \"tags\": [\n \"ecomap\",\n \"elderly\",\n \"caregiver\",\n \"aging-in-place\",\n \"geriatric\",\n \"medicare\",\n \"social-work\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"ecomap \\\"Margaret, age 81 — Aging-in-Place Assessment\\\"\\n center: client [label: \\\"Margaret, 81\\\"]\\n daughter [label: \\\"Daughter (primary caregiver)\\\", category: family]\\n son [label: \\\"Son (out of state)\\\", category: family]\\n aide [label: \\\"Home Health Aide (3×/wk)\\\", category: health]\\n pcp [label: \\\"Primary Care MD\\\", category: health]\\n cardiologist [label: \\\"Cardiologist\\\", category: health]\\n medicare [label: \\\"Medicare Part A/B\\\", category: financial]\\n church [label: \\\"Grace Lutheran Church\\\", category: spiritual]\\n senior_center [label: \\\"Oak Park Senior Center\\\", category: community]\\n neighbor [label: \\\"Neighbor Mrs. Kim\\\", category: social]\\n daughter === client [label: \\\"daily visits — caregiver burden high\\\"]\\n son --- client [label: \\\"monthly calls — geographic distance\\\"]\\n aide === client [label: \\\"bathing, meals, medication reminders\\\"]\\n pcp <-> client [label: \\\"quarterly — telehealth since 2023\\\"]\\n cardiologist --> client [label: \\\"CHF management — 6-month follow-up\\\"]\\n medicare --> client [label: \\\"covers home health — 60-day cert\\\"]\\n church --> client [label: \\\"weekly visitor volunteer\\\"]\\n senior_center --- client [label: \\\"transport lapsed — no longer attending\\\"]\\n neighbor --> client [label: \\\"grocery errands — informal\\\"]\",\n \"notes\": \"## Scenario\\n\\nA geriatric social worker draws this ecomap during a home assessment for Margaret, an 81-year-old living alone with congestive heart failure and early-stage cognitive impairment. The daughter has requested a care plan review because she is the sole in-person caregiver and is showing signs of burnout. The ecomap immediately surfaces two risks: the lapsed senior center connection (a key social resource that has gone dormant) and the son's minimal involvement despite being a potential remote-support resource. It becomes the basis for the care conference agenda.\\n\\n## Annotation key\\n\\n- `===` — strong connection; high-quality, frequent, reliable\\n- `---` — tenuous connection; infrequent, geographically limited, or at risk of lapsing\\n- `-->` — directional support flowing toward Margaret; she is the recipient\\n- `<->` — reciprocal relationship; mutual engagement (e.g., PCP telehealth where Margaret actively participates)\\n- `[label: \\\"...\\\"]` — edge label adds clinical context: frequency, mode, and quality notes\\n- `category: health / financial / spiritual / community / social / family` — determines node color and cluster in the rendered diagram\\n\\n## How to read\\n\\nMargaret's strongest support systems are her daughter (strong tie, daily visits) and home health aide (strong tie, three visits per week). Both are showing strain signals: the edge label on daughter notes high caregiver burden. The PCP relationship is reciprocal and active via telehealth; the cardiologist provides directional specialist management. Medicare covers the home health certification (60-day limit — a renewal flag for the social worker). Two systems have weakened: the son's connection is tenuous due to geographic distance, and the senior center connection has lapsed entirely because transport is no longer arranged. Mrs. Kim provides informal grocery support — an unformalized community asset. The care plan recommendation: restore senior center transport, formally engage the son in remote care coordination tasks, and refer the daughter to a caregiver support group.\"\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 — grantor trust + LLC holding\",\n \"description\": \"Multi-generational wealth structure: grantor trust, irrevocable trust, Delaware LLC holding, and operating entities — for the estate planning attorney.\",\n \"standard\": \"ACTEC / IRC §671–677\",\n \"tags\": [\n \"entity\",\n \"family-office\",\n \"trust\",\n \"grantor\",\n \"irrevocable\",\n \"llc\",\n \"estate-planning\",\n \"actec\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Smith Family Office\\\"\\nentity grantor \\\"John Smith (Grantor)\\\" trust@CA\\nentity spouse \\\"Jane Smith (Spouse)\\\" trust@CA\\nentity child1 \\\"Child 1 (Beneficiary)\\\" trust@CA\\nentity child2 \\\"Child 2 (Beneficiary)\\\" trust@CA\\nentity rev_trust \\\"Smith Revocable Living Trust\\\" trust@CA [note: \\\"IRC §671 — grantor trust\\\"]\\nentity irrev_trust \\\"Smith 2021 Irrevocable Trust\\\" trust@DE [note: \\\"IRC §677 — completed gift\\\"]\\nentity holding_llc \\\"Smith Family Holdings LLC\\\" llc@DE [note: \\\"Pass-through entity\\\"]\\nentity op_co \\\"Smith Operating Co. LLC\\\" llc@CA [note: \\\"Active trading\\\"]\\nentity re_llc \\\"Smith RE Holdings LLC\\\" llc@CA [note: \\\"Real estate portfolio\\\"]\\nentity invest_acct \\\"Investment Portfolio\\\" fund@DE [note: \\\"Schwab brokerage\\\"]\\ngrantor -> rev_trust : 100%\\nspouse --> rev_trust\\nrev_trust -> irrev_trust : 100%\\nirrev_trust -> holding_llc : 100%\\nholding_llc -> op_co : 80%\\nholding_llc -> re_llc : 100%\\nholding_llc -> invest_acct : 100%\\nirrev_trust --> child1\\nirrev_trust --> child2\",\n \"notes\": \"## Scenario\\n\\nAn estate planning attorney drafts this structure for a client family during an initial engagement or annual review. The diagram captures the full wealth architecture in one view: who owns what, which trusts are grantor-taxed versus completed gifts, and which entities pass income through to the family's Schedule K-1s. It is the first document attached to a family office memo, estate plan update, or IRS audit response.\\n\\n## Annotation key\\n\\n- `trust@CA / trust@DE` — trust entity in the stated jurisdiction; California for revocable (grantor-state situs), Delaware for irrevocable (favorable trust laws)\\n- `->` — equity ownership or trust corpus contribution\\n- `-->` — beneficial interest or management control without outright ownership\\n- `[note: \\\"...\\\"]` — annotates the entity with the controlling IRC section or role\\n- `llc@CA / llc@DE` — limited liability company; single-member LLCs disregarded for federal tax\\n- `fund@DE` — brokerage account held as an entity interest\\n\\n## How to read\\n\\nJohn Smith (grantor) funds the revocable living trust, which is disregarded for income tax purposes under IRC §671 — all income flows to his Form 1040. On death or an intentional gift event, assets transfer to the Delaware irrevocable trust (a completed gift under §677), removing future appreciation from the taxable estate. The irrevocable trust owns 100% of Smith Family Holdings LLC, which in turn holds the operating company (80% — the remaining 20% may be held by key employees or a management LLC), the real estate portfolio, and the investment account. Child 1 and Child 2 are named beneficiaries of the irrevocable trust with no current income rights until distribution events defined in the trust instrument.\"\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-private-fund\",\n \"diagram\": \"entity\",\n \"title\": \"Private equity fund structure\",\n \"description\": \"Closed-end PE fund: GP management company, carry vehicle, LP investor classes, and three portfolio company investments — ILPA convention.\",\n \"standard\": \"ILPA standards\",\n \"tags\": [\n \"entity\",\n \"private-equity\",\n \"fund\",\n \"gp\",\n \"lp\",\n \"carry\",\n \"ilpa\",\n \"portco\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Capital Fund III\\\"\\nentity mgmt_co \\\"GP Management LLC\\\" llc@DE [note: \\\"Registered investment adviser\\\"]\\nentity gp_vehicle \\\"GP Vehicle LLC\\\" llc@DE [note: \\\"General partner entity\\\"]\\nentity carry_vehicle \\\"Carried Interest Vehicle LLC\\\" llc@DE [note: \\\"20% carry — IRC §1061 PFIC\\\"]\\nentity fund \\\"Acme Capital Fund III LP\\\" lp@DE [note: \\\"Closed-end — 10-year term\\\"]\\nentity inst_lps \\\"Institutional LPs\\\" trust@NY [note: \\\"Pensions, endowments — 65%\\\"]\\nentity hni_lps \\\"HNI & Family Office LPs\\\" trust@CA [note: \\\"High-net-worth — 34%\\\"]\\nentity portco_a \\\"Portfolio Co. A\\\" corp@DE [note: \\\"Control — software vertical\\\"]\\nentity portco_b \\\"Portfolio Co. B\\\" corp@DE [note: \\\"Majority — industrial services\\\"]\\nentity portco_c \\\"Portfolio Co. C\\\" corp@DE [note: \\\"Control — healthcare SaaS\\\"]\\nmgmt_co -> gp_vehicle : 100%\\nmgmt_co --> carry_vehicle\\ngp_vehicle -> fund : 1%\\ninst_lps -> fund : 65%\\nhni_lps -> fund : 34%\\nfund -> portco_a : 60%\\nfund -> portco_b : 45%\\nfund -> portco_c : 80%\",\n \"notes\": \"## Scenario\\n\\nA fund administrator prepares this entity diagram for the annual ILPA reporting package, limited partner quarterly statement cover page, and auditor workpapers. The ILPA Principles require transparent disclosure of the GP economic structure — specifically the separation of the management company (fee income), GP vehicle (fund economics), and carried interest vehicle (profit participation) — so LPs can assess conflicts of interest and economics independently.\\n\\n## Annotation key\\n\\n- `lp@DE` — Delaware limited partnership; the universal vehicle for closed-end PE funds; provides flow-through taxation and LP liability protection\\n- `mgmt_co` — registered investment adviser that employs investment professionals and earns the 2% management fee; separate from fund economics\\n- `gp_vehicle` — the formal general partner of the fund LP; holds 1% GP commitment and the right to the carried interest\\n- `carry_vehicle` — isolated entity for allocating 20% carried interest to individual partners; structured for IRC §1061 (3-year hold to qualify for long-term capital gains) treatment\\n- `-->` — management/control relationship without direct equity ownership\\n- `portco` ownership percentages — 45–80% reflects control or majority buyout positions typical of a mid-market PE fund\\n\\n## How to read\\n\\nThe management company owns the GP vehicle, which is the formal 1% general partner of Fund III. Institutional LPs (pensions, endowments) and high-net-worth LPs contribute 99% of capital. The fund deploys into three portfolio companies at control or majority positions: Portfolio Co. A (60%, software), Portfolio Co. B (45%, industrial services, minority-plus-control board rights), and Portfolio Co. C (80%, healthcare SaaS). At exit, each portfolio company sale distributes proceeds through the LP waterfall: return of capital → preferred return (typically 8% IRR hurdle) → GP catch-up → 80/20 profit split. The carried interest vehicle receives the GP's 20% and allocates it to individual partners per their carry agreements.\"\n },\n {\n \"slug\": \"entity-qsbs-rollup\",\n \"diagram\": \"entity\",\n \"title\": \"QSBS restructure — §1202 eligible multi-entity\",\n \"description\": \"Pre/post restructure for QSBS eligibility: C-corps per founder, clean C-corp parent, and non-qualifying IP subsidiary excluded from §1202 stack.\",\n \"standard\": \"IRC §1202\",\n \"tags\": [\n \"entity\",\n \"qsbs\",\n \"1202\",\n \"restructure\",\n \"c-corp\",\n \"startup\",\n \"tax\",\n \"esop\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Inc. — QSBS Stack\\\"\\nentity founder1 \\\"Founder 1\\\" trust@CA [note: \\\"IRC §1202 — original shareholder\\\"]\\nentity founder2 \\\"Founder 2\\\" trust@CA [note: \\\"IRC §1202 — original shareholder\\\"]\\nentity esop_trust \\\"ESOP Trust\\\" trust@DE [note: \\\"IRC §1042 — ESOP rollover\\\"]\\nentity op_corp \\\"Acme Inc. (C-Corp)\\\" corp@DE [note: \\\"QSBS issuer — active business test\\\"]\\nentity ip_sub \\\"IP HoldCo LLC\\\" llc@DE [note: \\\"Non-QSBS — excluded from §1202 stack\\\"]\\nentity saas_sub \\\"SaaS Operations Inc.\\\" corp@DE [note: \\\"QSBS eligible — §1202 subsidiary\\\"]\\nfounder1 -> op_corp : 45%\\nfounder2 -> op_corp : 40%\\nesop_trust -> op_corp : 15%\\nop_corp -> ip_sub : 100%\\nop_corp -> saas_sub : 100%\",\n \"notes\": \"## Scenario\\n\\nA startup tax attorney structures the entity stack before a Series A closing to maximize the founders' §1202 exclusion. The key constraint: QSBS gain exclusion (up to $10M or 10× basis per taxpayer) applies only to original-issue stock in a domestic C-corp that meets the active business test and gross-asset limits at time of issuance. IP holding companies and pass-through entities are excluded. This diagram maps the qualifying versus non-qualifying layers so counsel can confirm clean §1202 eligibility before the closing.\\n\\n## Annotation key\\n\\n- `corp@DE` — Delaware C-corporation; the required entity form for §1202 QSBS eligibility\\n- `llc@DE` — pass-through LLC; deliberately isolated from the QSBS stack\\n- `->` — equity ownership; percentages must reflect the actual cap table at issuance\\n- `[note: \\\"...\\\"]` — calls out the controlling IRC provision or exclusion rationale\\n- `trust@CA` — grantor trusts are treated as individuals for §1202 purposes; eligible holders\\n- ESOP at 15% — combined founder + ESOP must stay under §1202 gross-asset ceiling ($50M at issuance)\\n\\n## How to read\\n\\nFounders 1 and 2 own 45% and 40% of Acme Inc. directly; the ESOP holds 15%. All three are §1202 eligible holders. Acme Inc. (the QSBS issuer) owns two subsidiaries: the IP HoldCo LLC is intentionally isolated as a pass-through and excluded from the §1202 qualification analysis, while SaaS Operations Inc. is a qualifying C-corp sub that inherits QSBS eligibility through the parent. The dashed exclusion boundary makes it immediately clear to the audit team which entities sit inside and outside the §1202 stack. At exit, gain allocated to qualifying shares in op_corp and saas_sub may be excluded from federal capital gains tax up to the §1202 limits per taxpayer.\"\n },\n {\n \"slug\": \"entity-real-estate-syndication\",\n \"diagram\": \"entity\",\n \"title\": \"Real estate syndication — GP/LP + SPV per property\",\n \"description\": \"Private real estate syndication: sponsor GP, investor LP interests, and separate SPV per property with senior lender — for the real estate syndicator.\",\n \"standard\": \"SEC Reg D / partnership law\",\n \"tags\": [\n \"entity\",\n \"real-estate\",\n \"syndication\",\n \"gp\",\n \"lp\",\n \"spv\",\n \"lender\",\n \"sec-regd\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Real Estate Fund I\\\"\\nentity sponsor \\\"Sponsor LLC\\\" llc@DE [note: \\\"Deal originator\\\"]\\nentity gp_entity \\\"GP Entity LLC\\\" llc@DE [note: \\\"1% GP commit + promote\\\"]\\nentity investors \\\"LP Investors (Reg D 506(b))\\\" trust@CA [note: \\\"Accredited investors\\\"]\\nentity fund_lp \\\"Acme Real Estate Fund I LP\\\" lp@DE [note: \\\"Closed-end fund\\\"]\\nentity spv1 \\\"123 Main St. LLC\\\" llc@CA [note: \\\"Multifamily — 48 units\\\"]\\nentity spv2 \\\"456 Oak Ave. LLC\\\" llc@TX [note: \\\"Mixed-use — retail + office\\\"]\\nentity lender1 \\\"Senior Lender A\\\" corp@NY [note: \\\"First lien — 65% LTV\\\"]\\nentity lender2 \\\"Senior Lender B\\\" corp@TX [note: \\\"First lien — 70% LTV\\\"]\\nsponsor -> gp_entity : 100%\\ngp_entity -> fund_lp : 1%\\ninvestors -> fund_lp : 99%\\nfund_lp -> spv1 : 100%\\nfund_lp -> spv2 : 100%\\nlender1 --> spv1\\nlender2 --> spv2\",\n \"notes\": \"## Scenario\\n\\nA real estate syndicator (sponsor) creates this entity map for the private placement memorandum (PPM) and investor onboarding package. Accredited investors investing under Reg D Rule 506(b) require a clear picture of the ownership stack, fee flows, and lender priority before wiring funds. Each property is isolated in its own SPV to ring-fence liability: a default on one asset cannot trigger cross-collateralization with another.\\n\\n## Annotation key\\n\\n- `lp@DE` — Delaware limited partnership; the standard vehicle for real estate funds; LP interests are passive investments\\n- `llc@DE / llc@CA / llc@TX` — single-asset SPV LLCs in the property's state for local tax and liability purposes\\n- `->` — equity ownership; GP commit is typically 1–5% of the fund to align incentives\\n- `-->` — lender relationship (senior debt, not equity); lenders have first-lien priority over LP equity\\n- `: 1% / : 99%` — GP/LP economic split; promote (carried interest) typically 20–30% of profits above preferred return\\n\\n## How to read\\n\\nThe sponsor controls the GP entity (100%) which holds the 1% general partner interest in the fund, giving the sponsor full management authority and the carried interest promote. LP investors contribute 99% of equity capital as passive limited partners with no management rights. The fund owns each property in its own isolated LLC — 123 Main St. (California multifamily, 48 units) and 456 Oak Ave. (Texas mixed-use). Senior lenders provide non-recourse debt at 65–70% LTV, sitting ahead of all equity in the capital stack. At exit, proceeds flow: lender repayment → LP return of capital → LP preferred return (e.g., 8% IRR) → GP promote on excess profits.\"\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\": \"entity-spac-merger\",\n \"diagram\": \"entity\",\n \"title\": \"SPAC de-SPAC merger structure\",\n \"description\": \"SPAC sponsor, trust, target company, PIPE investors, and post-merger pubco — the standard de-SPAC structure per SEC S-4 filing conventions.\",\n \"standard\": \"SEC S-4 / DGCL\",\n \"tags\": [\n \"entity\",\n \"spac\",\n \"de-spac\",\n \"merger\",\n \"pipe\",\n \"trust\",\n \"sponsor\",\n \"sec-s4\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"entity-structure \\\"Acme Acquisition Corp — de-SPAC\\\"\\nentity sponsor \\\"Sponsor LLC\\\" llc@DE [note: \\\"20% founder shares (promote)\\\"]\\nentity spac \\\"Acme Acquisition Corp (SPAC)\\\" corp@DE [note: \\\"NYSE: ACMX — blank-check company\\\"]\\nentity trust \\\"IPO Proceeds Trust\\\" fund@DE [note: \\\"$200M held in trust — T-bills\\\"]\\nentity ipo_investors \\\"Public IPO Shareholders\\\" trust@NY [note: \\\"80% of SPAC shares + warrants\\\"]\\nentity target \\\"Target Co.\\\" corp@DE [note: \\\"Private operating company\\\"]\\nentity merger_sub \\\"Merger Sub Inc.\\\" corp@DE [note: \\\"Wholly-owned — merges into Target\\\"]\\nentity pubco \\\"Acme Holdings Inc. (PubCo)\\\" corp@DE [note: \\\"NYSE: ACMX post-closing\\\"]\\nentity pipe_investors \\\"PIPE Investors\\\" trust@NY [note: \\\"$50M private placement — closing condition\\\"]\\nsponsor -> spac : 20%\\nipo_investors -> spac : 80%\\ntrust --> spac\\nspac -> merger_sub : 100%\\nmerger_sub --> target\\ntarget -> pubco\\nspac -> pubco\\npipe_investors -> pubco : 15%\",\n \"notes\": \"## Scenario\\n\\nAn investment banking analyst drafts this structure diagram for the S-4 registration statement or the investor roadshow deck. The de-SPAC process merges a blank-check company (SPAC) with a private target, taking the target public without a traditional IPO. The diagram must clearly show the pre-closing SPAC structure, the forward-merger mechanics through the merger subsidiary, and the post-closing cap table split among sponsor, public shareholders, and PIPE investors.\\n\\n## Annotation key\\n\\n- `corp@DE (SPAC)` — blank-check company with no operating business; formed solely to acquire a target within 18–24 months\\n- `fund@DE (Trust)` — IPO proceeds held in a trust account invested in T-bills; released only at closing or redemption\\n- `-->` — non-equity structural relationship (trust custodianship; merger mechanics)\\n- `merger_sub` — wholly-owned subsidiary of the SPAC that merges into Target; the legal mechanism that makes Target the surviving entity and SPAC shareholders become PubCo shareholders\\n- PIPE — Private Investment in Public Equity; committed concurrently with the merger agreement to provide minimum cash certainty if SPAC shareholders redeem\\n\\n## How to read\\n\\nPre-closing: the sponsor holds 20% founder shares (the \\\"promote\\\"); public IPO shareholders hold 80% of SPAC units plus warrants. The $200M IPO proceeds sit in trust. The SPAC creates a merger subsidiary. At closing: merger sub merges into Target (Target survives), converting Target equity holders into PubCo shareholders; SPAC shareholders who did not redeem become PubCo shareholders; PIPE investors inject $50M for new shares. Post-closing PubCo cap table approximation: legacy Target shareholders ~65%, public SPAC holders ~20%, sponsor ~15% (post-dilution from PIPE and redemptions vary by deal). The NYSE ticker ACMX carries over from SPAC to PubCo.\"\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-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\": \"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-food-safety-recall\",\n \"diagram\": \"fishbone\",\n \"title\": \"Food safety recall — HACCP deviation analysis\",\n \"description\": \"HACCP-based fishbone for a pathogen contamination incident in a ready-to-eat deli meat line — the food safety RCA required before FDA corrective action.\",\n \"standard\": \"HACCP / FDA FSMA\",\n \"tags\": [\n \"fishbone\",\n \"food-safety\",\n \"haccp\",\n \"recall\",\n \"listeria\",\n \"fsma\",\n \"fda\",\n \"rca\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"Listeria monocytogenes Contamination RCA — Deli Meat Recall\\\"\\n\\neffect \\\"Lm-positive product — Class I voluntary recall, 48,000 lb affected\\\"\\n\\ncategory machine \\\"Equipment\\\"\\ncategory method \\\"Method\\\"\\ncategory material \\\"Material\\\"\\ncategory man \\\"Personnel\\\"\\ncategory measurement \\\"Measurement\\\"\\ncategory environment \\\"Environment\\\"\\n\\nmachine : \\\"Slicer blade guard harboring Listeria in inaccessible niche\\\"\\nmachine : \\\"Floor drain biofilm not fully removed by routine CIP — design flaw\\\"\\nmachine : \\\"Condenser drip pan overflow — standing water on RTE processing floor\\\"\\nmachine : \\\"Conveyor belt splice joint — harborage point not in sanitation SOP\\\"\\n\\nmethod : \\\"Sanitation SOP frequency reduced from daily to 3×/week to cut costs\\\"\\nmethod : \\\"Pre-operational inspection checklist signed off without physical walk\\\"\\nmethod : \\\"Master sanitation schedule not updated after equipment line extension\\\"\\nmethod : \\\"CIP chemical dwell time shortened — insufficient contact time at pH\\\"\\n\\nmaterial : \\\"Incoming raw pork shoulder — positive environmental swab at supplier\\\"\\nmaterial : \\\"Packaging seal failure — modified atmosphere integrity compromised\\\"\\nmaterial : \\\"Sanitizer concentration below 200 ppm due to dilution system fault\\\"\\n\\nman : \\\"New overnight sanitation crew — no documented SSOP training on file\\\"\\nman : \\\"Line supervisor overrode reject hold on positive environmental zone-3 swab\\\"\\nman : \\\"Sanitation lead position vacant 6 weeks — responsibilities distributed informally\\\"\\n\\nmeasurement : \\\"Environmental swab program quarterly — FSMA §117 requires risk-based frequency\\\"\\nmeasurement : \\\"Finished product testing not at HACCP CCP for Lm — gap in food safety plan\\\"\\nmeasurement : \\\"Zone-1 positive swab result not escalated per written recall procedure\\\"\\n\\nenvironment : \\\"Cold room floor drain shared between raw and RTE processing areas\\\"\\nenvironment : \\\"Floor slope inadequate — pooling adjacent to slicer base\\\"\\nenvironment : \\\"Condensation on ceiling above packaging line — roof insulation failure\\\"\",\n \"notes\": \"## Scenario\\n\\nA food safety quality manager leads a mandatory FDA FSMA corrective action investigation after an environmental monitoring positive for Listeria monocytogenes is linked to shipped product. The six-category fishbone is the required root-cause analysis exhibit in the FDA Form 483 response and the firm's CAPA (Corrective and Preventive Action) submission. The HACCP team must demonstrate systematic analysis — not just the proximate harborage point — to satisfy the agency and prevent further enforcement action.\\n\\n## Annotation key\\n\\n- **Equipment** — physical harborage points and design deficiencies that prevent effective sanitation\\n- **Method** — sanitation procedure gaps: frequency, dwell time, verification steps\\n- **Material** — incoming ingredient risk, sanitizer failure, and packaging integrity\\n- **Personnel** — training gaps, unauthorized decision overrides, and staffing vacancies\\n- **Measurement** — monitoring program frequency, CCP coverage, and escalation failures\\n- **Environment** — facility design, drainage, and condensation factors that enable pathogen persistence\\n- Listeria monocytogenes is a persistent environmental pathogen; recall root causes are almost always multi-factorial, not attributable to a single point\\n\\n## How to read\\n\\nThe Class I recall (48,000 lb of ready-to-eat deli meat, highest FDA severity) is the effect. The six causal branches reveal the systemic failure: a harborage point in the slicer niche was enabled by a cost-driven reduction in sanitation frequency (method), a new untrained crew that did not physically complete the pre-op inspection (personnel), and an environmental swab program running quarterly instead of the risk-based frequency FSMA requires (measurement). A line supervisor's override of a zone-3 positive swab — which should have triggered a hold and investigation — is the most critical personnel finding and requires immediate CAPA. The corrective action plan must address all six branches; the FDA will reject a response that addresses only the harborage point without the systemic SSOP and training corrective actions.\"\n },\n {\n \"slug\": \"fishbone-manufacturing-defect\",\n \"diagram\": \"fishbone\",\n \"title\": \"Welding defect root-cause analysis (6M)\",\n \"description\": \"Ishikawa 6M analysis of weld porosity defects in an automotive stamping plant — Machine, Method, Material, Man, Measurement, Mother-Nature.\",\n \"standard\": \"Ishikawa 1968 / ASQ 6M\",\n \"tags\": [\n \"fishbone\",\n \"manufacturing\",\n \"welding\",\n \"defect\",\n \"6m\",\n \"ishikawa\",\n \"rca\",\n \"quality\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"Weld Porosity Defect RCA — Automotive Stamping Plant\\\"\\n\\neffect \\\"Weld porosity defects exceeding 2% reject rate\\\"\\n\\ncategory machine \\\"Machine\\\"\\ncategory method \\\"Method\\\"\\ncategory material \\\"Material\\\"\\ncategory man \\\"Man\\\"\\ncategory measurement \\\"Measurement\\\"\\ncategory environment \\\"Mother Nature\\\"\\n\\nmachine : \\\"MIG welder calibration drift (±15 A)\\\"\\nmachine : \\\"Wire feeder speed inconsistent\\\"\\nmachine : \\\"Contact tip worn — arc instability\\\"\\nmachine : \\\"Nozzle spatter buildup restricting gas flow\\\"\\n\\nmethod : \\\"Wrong shielding gas mix (75/25 vs. 90/10 required)\\\"\\nmethod : \\\"Travel speed too fast — insufficient fusion\\\"\\nmethod : \\\"Pre-heat not applied on thick-gauge stock\\\"\\nmethod : \\\"Joint gap tolerance not enforced at fit-up\\\"\\n\\nmaterial : \\\"Base metal surface moisture from storage\\\"\\nmaterial : \\\"Wire spool contamination — oil from feeder\\\"\\nmaterial : \\\"Wrong filler alloy lot — ER70S-3 vs. ER70S-6\\\"\\nmaterial : \\\"Galvanized coating not ground off at weld zone\\\"\\n\\nman : \\\"Welder certification lapsed — 18 months overdue\\\"\\nman : \\\"End-of-shift fatigue — porosity rate 3× higher at hour 10\\\"\\nman : \\\"Inconsistent torch angle technique across operators\\\"\\n\\nmeasurement : \\\"Porosity inspection gauge not calibrated in 6 months\\\"\\nmeasurement : \\\"Radiographic sample rate 5% — too low for detection\\\"\\nmeasurement : \\\"Reject threshold 2% set above ASME Section IX limit\\\"\\n\\nenvironment : \\\"Shop relative humidity exceeding 85% during rainy season\\\"\\nenvironment : \\\"Wind draft from loading dock door disrupting shielding gas\\\"\",\n \"notes\": \"## Scenario\\n\\nA QA engineer facilitates a kaizen event after the stamping plant's monthly weld audit reveals a 2.3% porosity reject rate — above the ASME Section IX contractual limit of 2.0%. The team uses the 6M fishbone to structure a cross-functional root-cause brainstorm before ordering expensive radiographic inspection equipment. The completed diagram is attached to the 8D corrective action report submitted to the OEM customer.\\n\\n## Annotation key\\n\\n- `effect \\\"...\\\"` — the nonconformance statement; should reference a measurable threshold (2% reject rate) not just a vague symptom\\n- 6M categories: **Machine** (equipment), **Method** (process/procedure), **Material** (inputs), **Man** (personnel), **Measurement** (inspection), **Mother Nature** (environment/conditions)\\n- Each cause should be specific enough to assign an owner and a verification test\\n- Bold causes in the workshop session are those that can be tested and confirmed within one shift\\n\\n## How to read\\n\\nThe effect (weld porosity exceeding the 2% limit) sits at the head. Six causal ribs branch from the spine. In the workshop, the team voted: the highest-probability primary causes were shielding gas mix error (Method), welder certification lapse (Man), and wire spool contamination (Material). These became the immediate corrective actions: re-certify all welders, audit gas supply specifications, and implement incoming inspection for wire spools. The environmental causes (humidity, dock-door draft) were addressed with a capital request for a secondary containment curtain — a corrective action assigned to facilities.\"\n },\n {\n \"slug\": \"fishbone-never-event-surgical\",\n \"diagram\": \"fishbone\",\n \"title\": \"Wrong-site surgery — root-cause analysis\",\n \"description\": \"Joint Commission RCA of a wrong-site surgical never-event using healthcare 5P categories — People, Process, Plant, Policies, Pathogens/External.\",\n \"standard\": \"Joint Commission RCA² Framework\",\n \"tags\": [\n \"fishbone\",\n \"never-event\",\n \"rca\",\n \"surgery\",\n \"patient-safety\",\n \"joint-commission\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"Wrong-Site Surgery RCA — Joint Commission Required\\\"\\n\\neffect \\\"Wrong-site surgery performed (left knee, consent for right)\\\"\\n\\ncategory people \\\"People\\\"\\ncategory process \\\"Process\\\"\\ncategory plant \\\"Plant / Equipment\\\"\\ncategory policy \\\"Policies\\\"\\ncategory external \\\"External Factors\\\"\\n\\npeople : \\\"Attending surgeon fatigue — 14-hour shift, fourth case\\\"\\npeople : \\\"Surgical resident did not speak up when site inconsistency noted\\\"\\npeople : \\\"Circulating nurse unfamiliar with Universal Protocol timeout\\\"\\npeople : \\\"Pre-op nurse documented laterality from verbal order — not chart\\\"\\n\\nprocess : \\\"Surgical timeout not fully performed — attestation incomplete\\\"\\nprocess : \\\"Surgeon did not personally mark the operative site pre-scrub\\\"\\nprocess : \\\"Consent form laterality field left ambiguous (checkboxes not filled)\\\"\\nprocess : \\\"Imaging hung in OR without laterality verification step\\\"\\n\\nplant : \\\"OR scheduling board displayed outdated version of OR schedule\\\"\\nplant : \\\"Imaging display system showed prior patient's study for 4 minutes\\\"\\nplant : \\\"Physical consent document not available in OR — scanned copy only\\\"\\n\\npolicy : \\\"Site-marking policy not enforced — no escalation path for omission\\\"\\npolicy : \\\"Timeout checklist voluntary for cases under 30 minutes — loophole\\\"\\npolicy : \\\"No mandatory second-check requirement for laterality by scrub tech\\\"\\n\\nexternal : \\\"Staffing agency circulating nurse — first shift at this facility\\\"\\nexternal : \\\"OR scheduling system race condition created duplicate booking\\\"\",\n \"notes\": \"## Scenario\\n\\nA patient safety officer leads a mandatory Joint Commission Root Cause Analysis² (RCA²) following a wrong-site never-event. The RCA² framework requires the hospital to identify all contributing causes — not just the proximate error — and submit a corrective action plan within 45 days. This fishbone structures the multidisciplinary team's findings across five healthcare-adapted categories. The completed diagram is a required exhibit in the sentinel event report.\\n\\n## Annotation key\\n\\n- Healthcare 5P categories: **People** (workforce factors), **Process** (workflow and procedure), **Plant/Equipment** (physical environment and technology), **Policies** (rules and their enforcement), **External Factors** (system or supply factors outside direct control)\\n- The Joint Commission distinguishes contributing causes (present but not sufficient alone) from root causes (necessary for the event to occur) — this diagram captures all contributing causes for team review\\n- Never-event RCAs must produce at least one strong systemic action (policy or process change), not just individual retraining\\n\\n## How to read\\n\\nThe sentinel event (wrong-site surgery on the left knee when consent was for the right) sits at the head. Five causal ribs surface the layered failure: the circulating nurse was agency staff unfamiliar with the Universal Protocol, the timeout was not completed, the surgeon did not mark the site personally, the consent form had an ambiguous laterality field, and the OR imaging system briefly displayed a prior patient's study. No single cause was sufficient — the event required the simultaneous failure of four independent safety barriers. The corrective action plan must address at minimum: mandatory site marking by the attending before scrub, a hard-stop in the EMR if laterality is blank on consent, and mandatory Universal Protocol training before any agency nurse is permitted in an OR.\"\n },\n {\n \"slug\": \"fishbone-nps-decline\",\n \"diagram\": \"fishbone\",\n \"title\": \"NPS score decline — customer experience RCA\",\n \"description\": \"Fishbone for a 12-point NPS decline over Q3 — product, support, onboarding, pricing, competition, and communication root causes.\",\n \"standard\": \"Ishikawa 1968\",\n \"tags\": [\n \"fishbone\",\n \"nps\",\n \"customer-experience\",\n \"saas\",\n \"rca\",\n \"retention\",\n \"support\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"NPS Decline RCA — Q3 Customer Experience Review\\\"\\n\\neffect \\\"NPS drop: 52 → 40 over Q3 (12-point decline, 186 survey responses)\\\"\\n\\ncategory product \\\"Product\\\"\\ncategory support \\\"Support\\\"\\ncategory onboarding \\\"Onboarding\\\"\\ncategory pricing \\\"Pricing\\\"\\ncategory competition \\\"Competition\\\"\\ncategory comms \\\"Communication\\\"\\n\\nproduct : \\\"Three regressions shipped in 6 weeks affecting core workflow\\\"\\nproduct : \\\"Mobile app performance degraded on Android — P95 render 4.2 s\\\"\\nproduct : \\\"Top-requested feature cancelled without customer notice\\\"\\nproduct : \\\"API rate limits tightened — broke integrations for 38 accounts\\\"\\n\\nsupport : \\\"Ticket median first-response rose from 2 h to 9 h in July\\\"\\nsupport : \\\"Support team understaffed — 2 FTE departed, not backfilled\\\"\\nsupport : \\\"Chat widget removed — customers routed to email only\\\"\\n\\nonboarding : \\\"New onboarding flow confusing for non-technical admins\\\"\\nonboarding : \\\"Checklist items not localized for EU customers (GDPR steps missing)\\\"\\nonboarding : \\\"In-app tours broken after UI redesign — no fallback\\\"\\n\\npricing : \\\"Surprise overage charges not warned in-app before threshold\\\"\\npricing : \\\"Annual price increase announced with 14-day notice — no grace period\\\"\\npricing : \\\"Grandfathered plan removed — 120 accounts forced to upgrade\\\"\\n\\ncompetition : \\\"Primary competitor launched feature parity at 20% lower price\\\"\\ncompetition : \\\"Competitor offered free migration service for churned accounts\\\"\\n\\ncomms : \\\"Status page not updated for 3 hours during August outage\\\"\\ncomms : \\\"Changelog not published in 6 weeks — users unaware of fixes\\\"\\ncomms : \\\"Account managers not notified before pricing change announcement\\\"\",\n \"notes\": \"## Scenario\\n\\nA customer experience lead presents this fishbone at the Q3 CX review after the Promoter score drops 12 points — from 52 to 40. The NPS survey verbatim comments are coded into six categories matching the fishbone branches. The diagram makes visible what the summary NPS number hides: the decline is not driven by any single factor but by simultaneous failures in product quality, support capacity, and pricing communication. It becomes the brief for the cross-functional Q4 CX recovery sprint.\\n\\n## Annotation key\\n\\n- **Product** — regressions, performance problems, cancelled features, and API changes that degraded existing workflows\\n- **Support** — response-time degradation, channel reduction, and staffing gaps\\n- **Onboarding** — friction for new users that produced early detractors before value was realized\\n- **Pricing** — billing surprise and plan changes that damaged trust among tenured accounts\\n- **Competition** — market-level factors that amplified every other dissatisfaction\\n- **Communication** — information gaps that prevented customers from managing expectations\\n\\n## How to read\\n\\nThe 12-point NPS drop (52 → 40) is the effect. The six causal branches reveal a compounding pattern: product quality degraded (regressions, Android performance), support capacity shrank (two FTE departures, longer response times), and two pricing changes created surprise billing — all in the same quarter. Competition amplified the damage by offering a lower-cost alternative at feature parity, giving dissatisfied customers a viable exit. The highest-leverage corrective actions are: restore first-response SLA to under 2 hours (support hire or tier routing), enforce 30-day notice for pricing changes with in-app warnings, and ship a public regression post-mortem to rebuild trust with affected accounts.\"\n },\n {\n \"slug\": \"fishbone-sla-breach-incident\",\n \"diagram\": \"fishbone\",\n \"title\": \"API SLA breach post-mortem\",\n \"description\": \"SRE post-mortem fishbone for a 6-hour API SLA breach — infrastructure, code, process, people, external, and monitoring categories.\",\n \"standard\": \"Ishikawa 1968\",\n \"tags\": [\n \"fishbone\",\n \"sla\",\n \"incident\",\n \"post-mortem\",\n \"sre\",\n \"api\",\n \"saas\",\n \"rca\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"fishbone \\\"API SLA Breach Post-Mortem — 6-Hour P99 Latency Incident\\\"\\n\\neffect \\\"6-hour API SLA breach — P99 latency sustained above 2,000 ms\\\"\\n\\ncategory infra \\\"Infrastructure\\\"\\ncategory code \\\"Code\\\"\\ncategory process \\\"Process\\\"\\ncategory people \\\"People\\\"\\ncategory external \\\"External\\\"\\ncategory monitoring \\\"Monitoring\\\"\\n\\ninfra : \\\"Database connection pool exhausted — pool size 20, peak demand 85\\\"\\ninfra : \\\"Redis OOM — eviction policy set to noeviction in production\\\"\\ninfra : \\\"Auto-scaling trigger lag 8 minutes — scale-out too slow for spike\\\"\\ninfra : \\\"Read replica replication lag 40 s — queries falling back to primary\\\"\\n\\ncode : \\\"N+1 query introduced in v2.14.1 release — 47 queries per request\\\"\\ncode : \\\"Missing composite index on reports.user_id + reports.created_at\\\"\\ncode : \\\"Unbounded pagination — page size limit removed in refactor\\\"\\ncode : \\\"Synchronous PDF generation blocking API worker threads\\\"\\n\\nprocess : \\\"Staging database 10× smaller than production — N+1 not detected\\\"\\nprocess : \\\"No load test step in release pipeline — only unit and integration\\\"\\nprocess : \\\"Feature flag rollout 100% immediate — no canary stage\\\"\\n\\npeople : \\\"On-call engineer missed PagerDuty alert — Slack notification silenced\\\"\\npeople : \\\"Runbook for connection pool exhaustion not updated after Q2 migration\\\"\\npeople : \\\"Escalation path unclear — 40-minute delay before incident commander paged\\\"\\n\\nexternal : \\\"CDN provider BGP reroute added 180 ms baseline latency — not SLA-covered\\\"\\n\\nmonitoring : \\\"P99 latency alert threshold set to 5,000 ms — too loose to catch breach\\\"\\nmonitoring : \\\"No alert on database connection pool depth or wait queue length\\\"\\nmonitoring : \\\"Redis memory alert only at 95% — no warning at 80% threshold\\\"\",\n \"notes\": \"## Scenario\\n\\nAn SRE lead runs a post-mortem blameless review 48 hours after a P1 incident that breached the 99.9% monthly uptime SLA. Six categories of contributing causes are identified by the on-call team and mapped to this fishbone before the incident report is sent to enterprise customers. The diagram becomes the basis for the corrective action roadmap: immediate mitigations, 30-day engineering fixes, and 90-day process changes.\\n\\n## Annotation key\\n\\n- **Infrastructure** — platform and configuration decisions made outside the code path\\n- **Code** — bugs or regressions introduced in application code\\n- **Process** — gaps in the SDLC, release pipeline, or operational procedures\\n- **People** — human factors: awareness, communication, skills, and on-call readiness\\n- **External** — third-party provider failures outside the team's control; relevant for SLA attribution\\n- **Monitoring** — gaps in observability that delayed detection or escalation\\n- All causes are recorded without blame; the goal is systemic improvement, not individual accountability\\n\\n## How to read\\n\\nThe P99 latency breach (sustained above 2,000 ms for 6 hours) sits at the head. Six contributing branches are mapped. The proximate cause was an N+1 query regression in v2.14.1 that overwhelmed the connection pool. The systemic causes were a staging environment 10× undersized for load testing, an auto-scaler too slow to respond, and monitoring thresholds set too conservatively to detect the degradation early. The CDN BGP reroute added a baseline latency penalty that pushed a marginal P99 over the SLA threshold faster than it would have otherwise. Action items with the highest leverage: parity load testing in CI, dynamic connection pool sizing, and a tighter P99 alert at 1,500 ms with a 2-minute sustained window.\"\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-algo-binary-search\",\n \"diagram\": \"flowchart\",\n \"title\": \"Binary search algorithm\",\n \"description\": \"Iterative binary search over a sorted array — the classic CS teaching flowchart, from array + target input to found/not-found output.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"algorithm\",\n \"binary-search\",\n \"teaching\",\n \"cs\",\n \"sorted-array\",\n \"iterative\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"flowchart TD\\n input([Input: sorted array A, target T]) --> init[low = 0, high = n − 1]\\n init --> loopcheck{low ≤ high?}\\n loopcheck -->|No| notfound([Return −1 — target not found])\\n loopcheck -->|Yes| mid[mid = floor((low + high) / 2)]\\n mid --> eqcheck{A[mid] == T?}\\n eqcheck -->|Yes| found([Return mid — target found at index mid])\\n eqcheck -->|No| ltcheck{A[mid] < T?}\\n ltcheck -->|Yes — search right half| newlow[low = mid + 1]\\n newlow --> loopcheck\\n ltcheck -->|No — search left half| newhigh[high = mid − 1]\\n newhigh --> loopcheck\",\n \"notes\": \"## Scenario\\n\\nA CS teacher is preparing lecture slides on divide-and-conquer algorithms and wants a textbook-quality flowchart students can annotate alongside the pseudocode. The iterative formulation makes the loop invariant — the search space halving each iteration — visually explicit, and the two boundary-update branches give students a concrete mental model for why the algorithm runs in O(log n) time.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; algorithm entry with inputs and terminal return values\\n- `{…}` — diamond; loop-continuation test and value-comparison decisions\\n- `[…]` — rectangle; variable initialization and index update assignments\\n- `-->|label|` — branch labels stating the condition outcome and which half is selected\\n- Back edges from `newlow` and `newhigh` to `loopcheck` form the iterative loop body\\n\\n## How to read\\n\\nThe algorithm initializes two index pointers — `low` at zero and `high` at the last index — then enters the main loop gate. If `low` exceeds `high` the search space is exhausted and −1 is returned. Otherwise `mid` is computed as the floor average of the two pointers and the element at that index is compared to the target. An exact match terminates with the index; a mismatch routes to the less-than check, which moves `low` one past `mid` to discard the left half, or moves `high` one below `mid` to discard the right half. Either update sends control back to the loop gate, halving the remaining search space on every iteration.\"\n },\n {\n \"slug\": \"flowchart-approval-bpmn\",\n \"diagram\": \"flowchart\",\n \"title\": \"Purchase order approval\",\n \"description\": \"Employee submits PO → manager review → finance approval → payment — BPMN gateway shapes for a business approval workflow.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"approval\",\n \"bpmn\",\n \"purchase-order\",\n \"workflow\",\n \"finance\",\n \"gateway\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"flowchart TD\\n submit([Employee submits purchase order]) --> amtcheck{Amount > $10,000?}\\n amtcheck -->|Yes — CFO track| cfo[CFO review queue]\\n amtcheck -->|No — standard track| mgr[Department manager review]\\n mgr --> mapproved{Manager approved?}\\n mapproved -->|No| revise[Request revision from employee]\\n revise --> submit\\n mapproved -->|Yes| cfo\\n cfo --> capproved{CFO approved?}\\n capproved -->|No| reject([Reject PO — notify employee with reason])\\n capproved -->|Yes| finance[Finance processes payment]\\n finance --> vendor[Send payment confirmation to vendor]\\n vendor --> done([PO closed — archived to ERP])\",\n \"notes\": \"## Scenario\\n\\nA business analyst is documenting a company's purchase order workflow to support an ERP implementation and audit readiness review. The diagram makes explicit the dollar-amount threshold that gates which approval track a PO enters, the revision loop that keeps rejected items in flight rather than discarding them, and the two possible terminal outcomes — closed PO or formal rejection with written rationale.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; employee-initiated event and terminal closure or rejection nodes\\n- `{…}` — diamond; BPMN-style exclusive gateways branching on amount threshold or approval decision\\n- `[…]` — rectangle; human review steps and system actions (payment, notification, archival)\\n- `-->|label|` — branch label showing threshold condition or approval outcome\\n- Loop from `revise` back to `submit` keeps the PO in flight through the standard track after revision\\n\\n## How to read\\n\\nEvery PO enters the amount-check gateway immediately after submission. Orders above ten thousand dollars skip manager review and go directly to the CFO queue; orders at or below the threshold must first receive manager approval. A manager rejection sends the PO back to the employee for revision, which re-enters the same gateway — the amount does not change, so revised orders under the threshold loop through manager review again. Once the CFO approves (either from the high-value track or an escalated standard-track PO), finance executes payment and notifies the vendor, closing the PO in the ERP. A CFO rejection terminates the flow with a formal notice to the employee.\"\n },\n {\n \"slug\": \"flowchart-auth-flow\",\n \"diagram\": \"flowchart\",\n \"title\": \"OAuth 2.0 authorization code + PKCE\",\n \"description\": \"OAuth 2.0 authorization code flow with PKCE — the recommended grant for SPAs and mobile apps, per RFC 7636.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"oauth\",\n \"pkce\",\n \"authorization-code\",\n \"security\",\n \"spa\",\n \"rfc7636\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"flowchart LR\\n subgraph \\\"Client App\\\"\\n start([User initiates login]) --> gen[Generate code verifier + SHA-256 challenge]\\n gen --> redirect[Redirect to authorization endpoint with challenge + state]\\n callback[Receive authorization code] --> exchange[POST /token — code + code verifier]\\n tokens[Store access + refresh tokens] --> bearer[Attach Bearer token to API request]\\n end\\n subgraph \\\"Authorization Server\\\"\\n redirect --> login[Present login + consent UI]\\n login --> consent{User consents?}\\n consent -->|No| deny([Authorization denied — redirect with error])\\n consent -->|Yes| issue[Issue authorization code — redirect to callback]\\n issue --> callback\\n exchange --> verify{code_challenge matches verifier hash?}\\n verify -->|No| err([400 Bad Request — PKCE mismatch])\\n verify -->|Yes| mint[Mint access token + refresh token]\\n mint --> tokens\\n end\\n subgraph \\\"Resource Server\\\"\\n bearer --> validate{Bearer token valid + not expired?}\\n validate -->|No| unauth([401 Unauthorized])\\n validate -->|Yes| data([Return protected resource])\\n end\",\n \"notes\": \"## Scenario\\n\\nA security engineer is reviewing a team's SPA authentication implementation against RFC 7636 to verify that the implicit grant has been fully removed in favor of authorization code with PKCE. The diagram makes the cryptographic handshake — code verifier generated client-side, challenge sent to the authorization server, verifier submitted at token exchange — visible alongside the three distinct server boundaries, helping reviewers confirm that no secret is ever stored in browser memory.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; user-initiated events and terminal success/error responses\\n- `{…}` — diamond; server-side validation gates (consent, PKCE hash match, token validity)\\n- `[…]` — rectangle; client or server processing steps\\n- `subgraph \\\"…\\\"` — trust boundary lanes for Client App, Authorization Server, and Resource Server\\n- `-->|label|` — branch labels showing consent outcome or validation result\\n\\n## How to read\\n\\nThe flow starts in the Client App lane where the application generates a random code verifier and derives its SHA-256 challenge before redirecting the user. In the Authorization Server lane the user authenticates and consents; the server returns an authorization code bound to the challenge. The client then submits the original verifier in the token exchange request — the Authorization Server hashes it and compares it to the stored challenge, rejecting mismatches with a 400. Valid exchanges produce short-lived access and refresh tokens. The Resource Server lane shows the final step: every API call presents the Bearer token and the server validates its signature and expiry before returning data, enforcing a clean separation between authorization and resource access.\"\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-etl-pipeline\",\n \"diagram\": \"flowchart\",\n \"title\": \"ETL data pipeline\",\n \"description\": \"Source extraction through transform, validation, load, and warehouse notification — the standard data-engineering pipeline diagram.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"etl\",\n \"pipeline\",\n \"data\",\n \"warehouse\",\n \"validation\",\n \"transform\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"flowchart LR\\n subgraph \\\"Sources\\\"\\n pg[(PostgreSQL)] --> extract\\n s3[(S3 bucket)] --> extract\\n api[REST API] --> extract\\n end\\n extract[Extract to raw staging] --> clean[Clean — strip nulls, deduplicate]\\n clean --> normalize[Normalize — cast types, unify schemas]\\n normalize --> enrich[Enrich — join lookup tables]\\n enrich --> validate{Error rate > 1%?}\\n validate -->|Yes| quarantine[Quarantine bad rows]\\n quarantine --> notify[Alert data-quality Slack channel]\\n notify --> retry{Retry batch?}\\n retry -->|Yes| extract\\n retry -->|No| abort([Abort run — log to incident tracker])\\n validate -->|No| load[Load to data warehouse]\\n load --> qcheck[Run row-count and sum reconciliation]\\n qcheck --> passed{Reconciliation passed?}\\n passed -->|No| rollback[Rollback warehouse load]\\n rollback --> abort\\n passed -->|Yes| publish[Publish partition metadata]\\n publish --> downstream([Notify downstream consumers — dbt, BI, ML])\",\n \"notes\": \"## Scenario\\n\\nA data engineer is documenting a nightly batch ETL job that ingests transactional records from three heterogeneous sources into a central warehouse. The diagram serves as both a runbook and a stakeholder communication artifact, showing data-quality enforcement points that prevent silent corruption from propagating to reporting dashboards and machine-learning feature stores.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; terminal run outcomes (abort, notify consumers)\\n- `{…}` — diamond; quality gates with quantitative thresholds\\n- `[…]` — rectangle; processing steps or system actions\\n- `[(…)]` — cylinder; external data stores\\n- `subgraph \\\"Sources\\\"` — groups the three ingestion connectors into one tier\\n- Loop from `retry -->|Yes|` back to `extract` models full-batch reprocessing after quarantine\\n\\n## How to read\\n\\nThe pipeline fans in from three source connectors into a single extract step that writes to raw staging. The transform chain — clean, normalize, enrich — runs sequentially; each step narrows and standardizes the data before passing it forward. The validation gate measures the bad-row error rate: if it exceeds one percent, bad rows are quarantined, an alert fires, and the operator decides whether to retry or abort the run. Rows that pass validation are loaded to the warehouse, then verified with a row-count and sum reconciliation; a failed reconciliation triggers a rollback and abort rather than leaving inconsistent data in place. A successful reconciliation publishes partition metadata and fans out notifications to downstream consumers.\"\n },\n {\n \"slug\": \"flowchart-incident-response\",\n \"diagram\": \"flowchart\",\n \"title\": \"On-call incident response\",\n \"description\": \"SRE on-call decision tree from alert page through triage, escalation, mitigation, and post-mortem — BPMN-shaped TD flow.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"incident\",\n \"sre\",\n \"on-call\",\n \"escalation\",\n \"mitigation\",\n \"postmortem\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"flowchart TD\\n page([Alert fires — on-call paged]) --> ack{Acknowledged within 5 min?}\\n ack -->|No| escalate[Escalate to secondary on-call]\\n escalate --> sev\\n ack -->|Yes| sev{Severity assessment}\\n sev -->|SEV1 — customer-facing outage| sev1[Wake CTO + open war room bridge]\\n sev -->|SEV2 — degraded service| sev2[Notify team lead + Slack channel]\\n sev -->|SEV3 — internal only| sev3[Self-resolve within shift]\\n sev1 --> mitigate[Apply mitigation — rollback or hotfix]\\n sev2 --> mitigate\\n sev3 --> mitigate\\n mitigate --> health{Service health restored?}\\n health -->|No| mitigate\\n health -->|Yes| resolved([Incident resolved — close bridge])\\n resolved --> postmortem{SEV1 or SEV2?}\\n postmortem -->|Yes| pm[Write post-mortem within 48 h]\\n postmortem -->|No| log[Log in incident tracker]\\n pm --> done([Done])\\n log --> done\",\n \"notes\": \"## Scenario\\n\\nAn SRE team uses this flowchart as the canonical on-call runbook embedded in their incident-management wiki. When an alert fires at 3 AM the responder can follow the diagram top to bottom without improvising, ensuring that acknowledgment, severity triage, escalation paths, and post-mortem obligations are never skipped regardless of who is on duty.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; trigger events and terminal closure nodes\\n- `{…}` — diamond; time-boxed decisions and severity gates\\n- `[…]` — rectangle; prescribed human actions (escalate, notify, mitigate, document)\\n- `-->|label|` — branch label showing condition or severity band\\n- Loop back from `health -->|No|` to `mitigate` represents the retry-until-resolved mitigation cycle\\n\\n## How to read\\n\\nThe flow begins the moment an alert fires. The first gate enforces the five-minute acknowledgment SLA; a miss immediately escalates to the secondary responder who then re-enters the severity triage diamond. Severity determines the escalation audience — SEV1 wakes executive leadership, SEV2 notifies the team lead, SEV3 is self-contained. All three paths converge on the mitigation loop, which repeats until health is restored. The final diamond routes only SEV1 and SEV2 incidents to a formal post-mortem; SEV3 incidents close with a tracker log entry.\"\n },\n {\n \"slug\": \"flowchart-microservices-request\",\n \"diagram\": \"flowchart\",\n \"title\": \"Microservices request flow\",\n \"description\": \"API gateway routing a request through auth, rate-limit, and three backend services to a shared DB — LR subgraph layout.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"microservices\",\n \"api-gateway\",\n \"request-flow\",\n \"backend\",\n \"subgraph\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"flowchart LR\\n subgraph \\\"API Layer\\\"\\n client([Client request]) --> gateway[API Gateway]\\n gateway --> auth{Auth valid?}\\n auth -->|No| reject([401 Unauthorized])\\n auth -->|Yes| rate{Rate limit ok?}\\n rate -->|No| throttle([429 Too Many Requests])\\n end\\n subgraph \\\"Services\\\"\\n rate -->|Yes| route{Route by path}\\n route -->|/users| user[User Service]\\n route -->|/orders| order[Order Service]\\n order --> notify[Notification Service]\\n end\\n subgraph \\\"Data\\\"\\n user --> db[(PostgreSQL)]\\n order --> db\\n end\\n user -->|200 response| client\\n order -->|200 response| client\\n db -->|query error| dberr([500 DB Error])\",\n \"notes\": \"## Scenario\\n\\nA backend engineer is documenting the runtime topology of a decomposed e-commerce platform so that new team members can trace a request end to end without reading source code. The diagram exposes the two pre-routing gates (authentication and rate limiting) and the downstream fan-out to specialized services, making it clear why a client might receive a 401, 429, or 500 before any business logic executes.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; entry points and terminal error/success nodes\\n- `{…}` — diamond; routing and policy decision gates\\n- `[…]` — rectangle; service or infrastructure processing step\\n- `[(…)]` — cylinder; persistent data store\\n- `-->|label|` — labeled directed edge showing condition or path name\\n- `subgraph \\\"name\\\"` — swimlane grouping API, service, and data tiers\\n\\n## How to read\\n\\nStart at *Client request* and follow the arrow into the API Layer subgraph. The request must clear two sequential gates — authentication then rate limiting — before reaching the route diamond. The route diamond dispatches to *User Service* or *Order Service* based on the URL path; an order request additionally triggers the *Notification Service* asynchronously. Both services share the same *PostgreSQL* store; a database error at that layer surfaces as a 500 terminal node independent of which service triggered the query.\"\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\": \"flowchart-prisma-systematic-review\",\n \"diagram\": \"flowchart\",\n \"title\": \"PRISMA 2020 systematic review flow\",\n \"description\": \"Canonical PRISMA 2020 flow diagram for a systematic review — records identified across databases, screened, assessed for eligibility, and included in synthesis.\",\n \"standard\": \"PRISMA 2020 (Page et al., BMJ 2021)\",\n \"tags\": [\n \"flowchart\",\n \"prisma\",\n \"systematic-review\",\n \"meta-analysis\",\n \"research\",\n \"evidence-synthesis\"\n ],\n \"complexity\": 3,\n \"featured\": true,\n \"dsl\": \"flowchart TD\\n classDef excluded fill:#fef2f2,stroke:#b91c1c,stroke-width:1px,color:#7f1d1d\\n\\n subgraph ID [\\\"Identification\\\"]\\n pubmed[\\\"PubMed (n = 482)\\\"]\\n embase[\\\"Embase (n = 314)\\\"]\\n cochrane[\\\"Cochrane (n = 91)\\\"]\\n registers[\\\"Trial registers (n = 38)\\\"]\\n end\\n\\n subgraph SCREEN [\\\"Screening\\\"]\\n dedup[\\\"After duplicates removed (n = 712)\\\"]\\n titles[\\\"Title and abstract screened (n = 712)\\\"]\\n excl_titles[\\\"Records excluded (n = 598)\\\"]\\n fulltext[\\\"Full-text sought (n = 114)\\\"]\\n retrieved[\\\"Assessed for eligibility (n = 109)\\\"]\\n not_retrieved[\\\"Not retrieved (n = 5)\\\"]\\n end\\n\\n subgraph ELIG [\\\"Eligibility\\\"]\\n assessed[\\\"Full-text articles assessed (n = 109)\\\"]\\n excl_reasons[\\\"Excluded with reasons (n = 60)\\\"]\\n r1[\\\"Wrong population (n = 18)\\\"]\\n r2[\\\"Wrong intervention (n = 22)\\\"]\\n r3[\\\"Wrong outcome (n = 11)\\\"]\\n r4[\\\"Conference abstract only (n = 9)\\\"]\\n end\\n\\n included([\\\"Studies in qualitative synthesis (n = 49)\\\"])\\n meta([\\\"Studies in meta-analysis (n = 31)\\\"])\\n\\n pubmed --> dedup\\n embase --> dedup\\n cochrane --> dedup\\n registers --> dedup\\n dedup --> titles\\n titles -->|excluded| excl_titles\\n titles -->|kept| fulltext\\n fulltext --> retrieved\\n fulltext -->|paywall / no response| not_retrieved\\n retrieved --> assessed\\n assessed -->|excluded with reasons| excl_reasons\\n excl_reasons --> r1\\n excl_reasons --> r2\\n excl_reasons --> r3\\n excl_reasons --> r4\\n assessed -->|met inclusion criteria| included\\n included --> meta\\n\\n class excl_titles,not_retrieved,excl_reasons,r1,r2,r3,r4 excluded\",\n \"notes\": \"## Scenario\\n\\nA research librarian working with a clinical team produces the PRISMA 2020 flow diagram for an upcoming Cochrane review submission. The journal **requires** the diagram in this exact four-phase structure (Identification → Screening → Eligibility → Included), with the count `(n = …)` shown explicitly in every box and the excluded-with-reasons box itemizing rejection reasons. Authoring this in a DSL (rather than redrawing in Word or BioRender) means the counts can be regenerated as the screening team updates the search.\\n\\n## Annotation key\\n\\n- **Subgraphs** name the four PRISMA phases: `subgraph ID [\\\"Identification\\\"]`, etc. — the rendered output groups boxes inside a labeled cluster border.\\n- **`(n = N)` inline** — keep the count in the same label (PRISMA 2020 requires the count to be visible in every box; inline is the simplest layout that survives wide labels).\\n- **`classDef excluded`** + **`class A,B excluded`** — applies the red-tinted class to the \\\"records excluded\\\" boxes so the eliminated stream is visually separated from the surviving stream.\\n- **Edge labels** (`-->|excluded|`, `-->|met inclusion criteria|`) annotate the screening decision on each fork.\\n- **Stadium nodes** (`([\\\"…\\\"])`) mark the two terminal outcomes (qualitative synthesis count, meta-analysis count) so readers' eyes land there.\\n\\n## How to read\\n\\nTop to bottom, the four phases mirror the PRISMA 2020 template exactly:\\n\\n1. **Identification** — every database and register the team searched, with raw record counts before deduplication.\\n2. **Screening** — after deduplication, records pass through title/abstract screening (most are excluded here), then eligible records advance to full-text retrieval. Records lost at retrieval (paywall, no response from authors) are split into a separate \\\"not retrieved\\\" box per PRISMA 2020 reporting requirements.\\n3. **Eligibility** — full-text articles are assessed against inclusion/exclusion criteria. Exclusions **must** be itemized with reasons — this is the box reviewers most often flag if missing.\\n4. **Included** — final study count for the qualitative synthesis, with a sub-count for studies that contributed to the meta-analysis (not all included studies always do).\\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. The flow-diagram template lives at [prisma-statement.org/prisma-2020-flow-diagram](https://www.prisma-statement.org/prisma-2020-flow-diagram).\"\n },\n {\n \"slug\": \"flowchart-user-onboarding\",\n \"diagram\": \"flowchart\",\n \"title\": \"User onboarding flow\",\n \"description\": \"Signup through email verification, profile setup, first-action tutorial, and activation milestone — a product manager's north-star flow.\",\n \"standard\": \"ISO 5807:1985\",\n \"tags\": [\n \"onboarding\",\n \"activation\",\n \"signup\",\n \"tutorial\",\n \"user-flow\",\n \"product\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"flowchart TD\\n signup([User submits signup form]) --> email[Send verification email]\\n email --> verified{Email verified?}\\n verified -->|No — after 24 h| resend[Resend verification email]\\n resend --> verified\\n verified -->|Yes| profile[Profile setup wizard]\\n profile --> skipped{Wizard completed?}\\n skipped -->|Skip| tour[Feature tour — 3 tooltip steps]\\n skipped -->|Complete| tour\\n tour --> action{First core action taken?}\\n action -->|No — after 48 h| nudge[Send nudge email with shortcut link]\\n nudge --> action\\n action -->|Yes| activate[Record activation event]\\n activate --> welcome([Welcome milestone reached])\",\n \"notes\": \"## Scenario\\n\\nA product manager is mapping the critical path from sign-up to activation to align engineering, growth, and design on what \\\"activated user\\\" means. The diagram makes every drop-off risk visible — email verification friction, wizard abandonment, and first-action hesitation — so each team can own the metric that corresponds to their part of the funnel.\\n\\n## Annotation key\\n\\n- `([…])` — stadium; user-triggered entry and milestone terminal nodes\\n- `{…}` — diamond; binary or conditional state checks\\n- `[…]` — rectangle; system or product actions (send email, show wizard, record event)\\n- `-->|label|` — branch labels showing condition, time trigger, or user choice\\n- Loop edges from `resend` and `nudge` model retry cycles that resolve when the user acts\\n\\n## How to read\\n\\nThe flow starts at form submission and immediately hits the email verification gate. Users who do not verify within 24 hours loop through a resend step; this loop continues until verification succeeds. Once verified, all users — whether they complete the profile wizard or skip it — enter the three-step feature tour. The first-action gate determines activation: users who have not acted within 48 hours receive a nudge email that links directly to the core feature, shortening the path back into the loop. Activation fires a single analytics event that marks the user as \\\"activated\\\" and terminates the onboarding sequence.\"\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-divorce-blended\",\n \"diagram\": \"genogram\",\n \"title\": \"Divorce, remarriage, and blended family\",\n \"description\": \"Two-household blended family genogram — divorce, remarriage, step-siblings, and half-sibling from new partner — for the family therapist.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"genogram\",\n \"divorce\",\n \"remarriage\",\n \"blended-family\",\n \"step-siblings\",\n \"mcgoldrick\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"genogram \\\"Blended Family — Post-Divorce\\\"\\n gf1 [male, 1940, deceased, label: \\\"Mat. GF\\\"]\\n gm1 [female, 1943, label: \\\"Mat. GM\\\"]\\n gf1 -- gm1\\n mom [female, 1968, label: \\\"Mom\\\"]\\n gf2 [male, 1938, deceased, label: \\\"Pat. GF\\\"]\\n gm2 [female, 1941, label: \\\"Pat. GM\\\"]\\n gf2 -- gm2\\n dad [male, 1965, label: \\\"Dad\\\"]\\n dad =/ mom\\n bio_child1 [female, 1995, index, label: \\\"Emma\\\"]\\n bio_child2 [male, 1998, label: \\\"Liam\\\"]\\n stepfather [male, 1966, label: \\\"Stepfather\\\"]\\n mom -- stepfather\\n bio_child1 [household: mom]\\n bio_child2 [household: mom]\\n stepmother [female, 1970, label: \\\"Stepmother\\\"]\\n stepmother =/ ex_partner [male, 1968, label: \\\"Ex\\\"]\\n step_child [male, 1996, label: \\\"Step-son\\\"]\\n dad -- stepmother\\n step_child [household: dad]\\n bio_child1 [household: dad, visits]\\n bio_child2 [household: dad, visits]\\n half_sibling [female, 2005, label: \\\"Half-sister\\\"]\",\n \"notes\": \"## Scenario\\n\\nA family therapist meets Emma (age 29, index), referred for anxiety she attributes to loyalty conflicts between her two households. Her biological parents divorced when she was seven; both have since remarried. Emma and her brother Liam split time between Mom's home — where Stepfather has no prior children — and Dad's home, where Stepmother brought a son from a previous relationship and later had a biological daughter (Emma's half-sister) with Dad. Drawing the full blended system in one diagram allows the therapist to map household boundaries, loyalty binds, and triangulation patterns at intake.\\n\\n## Annotation key\\n\\n- `=/` — divorced couple; double-slash through the couple line per McGoldrick 2020\\n- `-- stepfather` / `-- stepmother` — remarriage horizontal line; descent lines from each union are kept separate to clarify biological vs. step relationships\\n- `[household: mom]` / `[household: dad]` — assigns a child to a primary residential household without moving their position on the biological-parent descent line\\n- `[visits]` — secondary placement indicating shared-custody visits to the non-primary household\\n- `[foster]` / `[step_child household: dad]` — step-child redeclared under Dad's household as current caregiver (dotted secondary link)\\n- `half_sibling` — child appearing under Dad's second union; shares one biological parent with Emma and Liam\\n- `deceased` — diagonal slash; paternal and maternal grandfathers are deceased\\n- `index` — proband arrow on Emma, the presenting client\\n\\n## How to read\\n\\nThe top generation shows both sets of grandparents. The central couple line with double-slash marks the divorce between Mom and Dad. Each subsequent coupling line to the right (Mom + Stepfather; Dad + Stepmother) represents a remarriage. Children are drawn descending from the biological-parent coupling; household-boundary notation shows where they actually live. Emma and Liam appear in both households via the `visits` annotation. The half-sibling (born 2005) descends only from Dad + Stepmother, sharing exactly one parent with Emma and Liam. The stepson descends from Stepmother's prior union, making him a step-sibling to Emma and Liam with no biological connection. Tracking the two household clouds simultaneously reveals the structural complexity that Emma experiences as a daily loyalty conflict.\"\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-lgbtq-inclusive\",\n \"diagram\": \"genogram\",\n \"title\": \"LGBTQ+-inclusive family — Bennett 2022 symbols\",\n \"description\": \"Three-generation LGBTQ+-affirming genogram with AMAB/AFAB notation, same-sex couple, trans member, and chosen family — Bennett 2022 symbol set.\",\n \"standard\": \"Bennett 2022 (LGBTQ+-inclusive genogram symbols)\",\n \"tags\": [\n \"genogram\",\n \"lgbtq\",\n \"trans\",\n \"non-binary\",\n \"same-sex\",\n \"bennett-2022\",\n \"inclusive\",\n \"chosen-family\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"genogram \\\"Rivera Family — LGBTQ+-Affirming\\\"\\n gp1 [female, 1945, label: \\\"Abuela\\\"]\\n gp2 [male, 1943, label: \\\"Abuelo\\\"]\\n gp1 -- gp2\\n parent1 [female, 1972, label: \\\"Mom\\\", conditions: depression(half-left, #3498db)]\\n parent2 [male, 1970, label: \\\"Dad\\\"]\\n parent1 =/ parent2\\n child1 [male, 1998, index, label: \\\"Marco\\\"]\\n child2 [gender: non-binary, 2001, label: \\\"Sage\\\"]\\n child3 [female, 2004, label: \\\"Lucia\\\"]\\n parent3 [gender: trans-female, 1975, label: \\\"Valentina\\\"]\\n parent1 .. parent3\\n child1 [household: parent1]\\n child2 [household: parent1]\\n child3 [household: parent1]\\n chosen1 [male, 1997, label: \\\"Jordan\\\"]\\n chosen2 [gender: trans-male, 1999, label: \\\"River\\\"]\\n child1 -- chosen1\\n child1 -- chosen2\",\n \"notes\": \"## Scenario\\n\\nA therapist specializing in LGBTQ+-affirming family therapy draws a three-generation genogram for Marco (age 28, index), who presents with anxiety related to family-of-origin and chosen-family boundary conflicts. Marco's parents divorced when he was a child; his mother, who has a history of depression, is now in a cohabiting same-sex relationship with Valentina, a trans woman. Marco's younger sibling Sage identifies as non-binary. Marco's closest support system is his chosen family: Jordan and River (a trans man), with whom he has a committed three-person partnership. The genogram uses Bennett 2022 LGBTQ+-inclusive symbols so that every family member's gender identity is rendered accurately without forcing binary defaults.\\n\\n## Annotation key\\n\\n- `[gender: non-binary]` — triangle symbol per Bennett 2022; used for Sage, who uses they/them pronouns; AMAB/AFAB note can be added as a label\\n- `[gender: trans-female]` — circle with arrow-cross overlay per Bennett 2022; used for Valentina (AMAB, identifies as woman)\\n- `[gender: trans-male]` — square with arrow overlay per Bennett 2022; used for River (AFAB, identifies as man)\\n- `..` — cohabiting (common-law/unmarried) couple line; used for Mom and Valentina's same-sex partnership\\n- `=/` — divorced couple; double-slash marks the ended marriage between Mom and Dad\\n- `conditions: depression(half-left, #3498db)` — left-half blue fill; indicates Mom's diagnosed major depressive disorder\\n- `child1 -- chosen1` / `child1 -- chosen2` — relationship lines from Marco to chosen-family members; rendered without descent lines (no shared children) to distinguish from biological family\\n- `[household: parent1]` — all three children reside primarily with Mom\\n- `index` — proband arrow on Marco, the presenting client\\n\\n## How to read\\n\\nGeneration I (grandparents) shows a traditional married couple. Generation II reflects the divorce and subsequent same-sex remarriage: Mom's depression (blue half-fill) predates the divorce. The cohabiting same-sex couple line (dotted) connects Mom and Valentina; all three children are in Mom's household. Sage's non-binary triangle and River's trans-male square signal that Bennett 2022 symbols are active for this diagram — AMAB/AFAB biological sex at birth is available as label annotation when clinically relevant. Marco's chosen-family relationships (solid lines to Jordan and River, without a descent line) represent his primary adult attachment network. The therapist's clinical task is to help Marco navigate loyalty between these two constellations: the family he grew up in and the family he built.\"\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\": \"genogram-substance-use-3gen\",\n \"diagram\": \"genogram\",\n \"title\": \"Substance use disorder — three-generation pattern\",\n \"description\": \"Three-generation genogram showing alcohol use disorder and opioid dependence inheritance pattern, with emotional cutoffs — for the addiction counselor.\",\n \"standard\": \"McGoldrick 2020\",\n \"tags\": [\n \"genogram\",\n \"substance-use\",\n \"alcohol\",\n \"opioid\",\n \"three-generation\",\n \"emotional-cutoff\",\n \"addiction\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"genogram \\\"Substance Use — Three-Generation Pattern\\\"\\n gf [male, 1930, 1995, deceased, label: \\\"Grandfather\\\", conditions: alcohol(full, #c0392b)]\\n gm [female, 1935, 2010, deceased, label: \\\"Grandmother\\\"]\\n gf -- gm\\n father [male, 1958, label: \\\"Father\\\", conditions: alcohol(full, #c0392b) + opioid(half-right, #8e44ad)]\\n aunt [female, 1962, label: \\\"Aunt\\\"]\\n uncle [male, 1965, label: \\\"Uncle\\\", conditions: alcohol(half-left, #c0392b)]\\n mother [female, 1960, label: \\\"Mother\\\"]\\n father ~/~ mother\\n patient [male, 1988, index, label: \\\"Patient\\\", conditions: opioid(full, #8e44ad)]\\n sister [female, 1990, label: \\\"Sister\\\"]\\n brother [male, 1993, label: \\\"Brother\\\", conditions: alcohol(half-left, #c0392b)]\\n patient ~/~ father\",\n \"notes\": \"## Scenario\\n\\nAn addiction counselor conducts a three-generation substance-use assessment for a 36-year-old male patient (index) presenting for opioid use disorder treatment. The genogram reveals that the patient's grandfather had alcohol use disorder; his father has both alcohol use disorder and opioid dependence; his paternal uncle has alcohol use disorder; and his younger brother is showing early-stage hazardous drinking. The patient reports a conflicted, largely cut-off relationship with his father. This multi-generational pattern helps the counselor identify biological risk factors, model family transmission pathways, and target family-systems interventions alongside pharmacotherapy.\\n\\n## Annotation key\\n\\n- `conditions: alcohol(full, #c0392b)` — full red fill; indicates alcohol use disorder (AUD), clinically diagnosed\\n- `conditions: opioid(full, #8e44ad)` — full purple fill; indicates opioid use disorder (OUD), clinically diagnosed\\n- `conditions: alcohol(full, #c0392b) + opioid(half-right, #8e44ad)` — split fill; father carries both AUD (dominant) and OUD (secondary), encoded side-by-side in right half\\n- `conditions: alcohol(half-left, #c0392b)` — left-half fill; uncle and brother show alcohol use disorder without secondary diagnosis\\n- `~/~` — conflicted relationship; zigzag line between the patient and his father reflects emotional cutoff with episodic conflict\\n- `deceased` — diagonal slash; both grandparents are deceased\\n- `index` — proband arrow on the presenting patient\\n\\n## How to read\\n\\nTrace the red (alcohol) fill from grandfather → father → uncle → brother: four males across three generations affected by AUD. The purple (opioid) fill first appears in the father (right half) and then dominates the patient (full fill) — reflecting escalation from alcohol-primary to opioid-primary dependence across generations. The conflicted couple line between father and mother explains the household disruption during the patient's adolescence, a documented environmental risk factor. The sister (open circle) is the only Generation III member currently without a substance-use diagnosis, which may reflect protective factors worth exploring. The emotional cutoff between patient and father (~/~) is both a relational wound and a potential barrier to family-involved treatment.\"\n },\n {\n \"slug\": \"ladder-bottling-line\",\n \"diagram\": \"ladder\",\n \"title\": \"Bottling line — fill, cap, label, reject\",\n \"description\": \"Sequential fill → cap → label → reject-kick sequence for a beverage bottling PLC — count-based bottle detect with vision-system reject gate.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"bottling\",\n \"sequential\",\n \"fill\",\n \"cap\",\n \"label\",\n \"reject\",\n \"counter\",\n \"plc\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Bottling Line Control\\\"\\n\\nrung 1 \\\"Fill valve — open when bottle present, close on timeout or fault\\\":\\n XIC(BOTTLE_PRESENT_FILL, \\\"IN 1.0\\\", name=\\\"Bottle Present at Fill\\\")\\n XIO(FILL_TIMEOUT.DN, \\\"BIT 4.15\\\", name=\\\"Fill Timer Done\\\")\\n XIO(LINE_FAULT, \\\"IN 1.7\\\", name=\\\"Line Fault\\\")\\n OTE(FILL_VALVE, \\\"OUT 2.0\\\", name=\\\"Fill Valve\\\")\\n\\nrung 2 \\\"Fill timer — tracks fill dwell time, 3 s preset\\\":\\n XIC(FILL_VALVE, \\\"OUT 2.0\\\", name=\\\"Fill Valve Open\\\")\\n TON(FILL_TIMEOUT, \\\"TMR 4.0\\\", name=\\\"Fill Dwell Timer\\\", preset=3000)\\n\\nrung 3 \\\"Cap station — apply cap when bottle present and cap magazine has stock\\\":\\n XIC(BOTTLE_PRESENT_CAP, \\\"IN 1.1\\\", name=\\\"Bottle Present at Capper\\\")\\n XIC(CAP_AVAILABLE, \\\"IN 1.2\\\", name=\\\"Cap Magazine Stock\\\")\\n XIO(LINE_FAULT, \\\"IN 1.7\\\", name=\\\"Line Fault\\\")\\n OTE(CAPPER_CMD, \\\"OUT 2.1\\\", name=\\\"Capper Command\\\")\\n\\nrung 4 \\\"Label apply — energize labeler when bottle indexed to label station\\\":\\n XIC(BOTTLE_PRESENT_LABEL, \\\"IN 1.3\\\", name=\\\"Bottle Present at Labeler\\\")\\n XIO(LINE_FAULT, \\\"IN 1.7\\\", name=\\\"Line Fault\\\")\\n OTE(LABELER_CMD, \\\"OUT 2.2\\\", name=\\\"Labeler Command\\\")\\n\\nrung 5 \\\"Vision reject latch — set when vision system signals a bad bottle\\\":\\n XIC(VISION_REJECT_SIGNAL, \\\"IN 1.4\\\", name=\\\"Vision System Reject\\\")\\n OTL(REJECT_LATCH, \\\"BIT 3.0\\\", name=\\\"Reject Latch\\\")\\n\\nrung 6 \\\"Reject kicker — fire kicker when latched reject reaches reject station, then clear latch\\\":\\n XIC(REJECT_LATCH, \\\"BIT 3.0\\\", name=\\\"Reject Latch\\\")\\n XIC(BOTTLE_AT_REJECT, \\\"IN 1.5\\\", name=\\\"Bottle At Reject Station\\\")\\n OTE(REJECT_KICKER, \\\"OUT 2.3\\\", name=\\\"Reject Kicker Solenoid\\\")\\n\\nrung 7 \\\"Clear reject latch after kicker fires\\\":\\n XIC(REJECT_KICKER, \\\"OUT 2.3\\\", name=\\\"Reject Kicker Active\\\")\\n OTU(REJECT_LATCH, \\\"BIT 3.0\\\", name=\\\"Reject Latch\\\")\\n\\nrung 8 \\\"Production counter — increment on each labeled bottle\\\":\\n XIC(BOTTLE_PRESENT_LABEL, \\\"IN 1.3\\\", name=\\\"Bottle Present at Label\\\")\\n XIO(LABEL_PREV, \\\"BIT 3.1\\\", name=\\\"Label Station Previous Scan\\\")\\n CTU(PROD_CTU, \\\"CNT 5.0\\\", name=\\\"Production Counter\\\", preset=10000)\\n\\nrung 9 \\\"Label previous-scan latch — one-shot for counter rising edge\\\":\\n XIC(BOTTLE_PRESENT_LABEL, \\\"IN 1.3\\\", name=\\\"Bottle Present at Label\\\")\\n OTE(LABEL_PREV, \\\"BIT 3.1\\\", name=\\\"Label Station Previous Scan\\\")\\n\\nrung 10 \\\"Shift count alarm — alert supervisor when 10 000 bottles reached\\\":\\n XIC(PROD_CTU.DN, \\\"BIT 5.15\\\", name=\\\"Production Counter Done\\\")\\n OTE(SHIFT_ALARM, \\\"OUT 2.4\\\", name=\\\"Shift Count Alarm\\\")\\n\\nrung 11 \\\"Cap magazine low alarm — alert when no caps available\\\":\\n XIO(CAP_AVAILABLE, \\\"IN 1.2\\\", name=\\\"Cap Magazine Stock\\\")\\n OTE(CAP_LOW_ALARM, \\\"OUT 2.5\\\", name=\\\"Cap Low Alarm\\\")\",\n \"notes\": \"## Scenario\\n\\nA small-format beverage bottling line in a food and beverage plant runs at up to 200 bottles per minute across four processing stations: fill, cap, label, and reject. Each station has an inductive or photoelectric bottle-present sensor wired to a PLC digital input. A machine-vision camera downstream of the label station inspects label placement, fill level, and cap seating — any failure asserts the VISION_REJECT_SIGNAL input, which the PLC latches and carries forward until the bad bottle reaches the physical reject station 600 ms later (accounting for conveyor travel at the current line speed). The reject kicker is a pneumatic solenoid that pushes the bad bottle off the conveyor into a reject bin, then clears the latch. Production counting at the label station gives the shift supervisor a real-time unit count, with a configurable alarm at 10 000 bottles for shift reporting. The fill overtime guard (TON FILL_TIMEOUT, 3 s) closes the fill valve if the bottle is not indexed away within the fill dwell window, preventing overflow and spillage. All output rungs are gated by a master LINE_FAULT bit tied to the safety relay circuit.\\n\\n## Annotation key\\n\\n- `XIC(BOTTLE_PRESENT_X, ...)` — photoelectric sensor closes (bit = 1) when a bottle is positioned under the station head\\n- `XIO(FILL_TIMEOUT.DN, ...)` — timer Done bit used as a NC contact: the fill valve de-energizes if the timer completes before the bottle indexes away, preventing overflow\\n- `XIC(CAP_AVAILABLE, ...)` — discrete input from a cap-magazine stack sensor; the capper will not fire without confirmed cap stock\\n- `OTL(REJECT_LATCH, ...)` — latches the reject event at the camera inspection point so the kicker fires at the correct physical station one conveyor pitch later\\n- `OTU(REJECT_LATCH, ...)` — clears the latch immediately after the kicker fires (Rung 7) so it is ready for the next reject event\\n- `CTU(PROD_CTU, preset=10000)` — Count Up counter; the one-shot pattern (Rungs 8–9 with LABEL_PREV) ensures only one count per bottle regardless of how long the sensor stays asserted\\n\\n## How to read\\n\\nStations operate independently in parallel — the PLC scans all rungs every cycle, so fill, cap, and label can be active simultaneously on different bottles. The fill valve (Rung 1) opens when a bottle arrives and closes either on the 3-second timeout or when the bottle indexes away (sensor drops). The cap and label stations (Rungs 3–4) are simpler momentary outputs: active only while the bottle is present. The reject sequence (Rungs 5–7) is a two-rung latch-and-fire: the camera latches the bad-bottle flag at detection time, and the kicker fires when that same bottle reaches the reject station sensor a conveyor pitch downstream. The production counter (Rungs 8–9) uses the classic XIO-of-previous-scan one-shot to count exactly one rising edge per bottle arrival.\"\n },\n {\n \"slug\": \"ladder-conveyor-interlock\",\n \"diagram\": \"ladder\",\n \"title\": \"Multi-conveyor interlock with permissive\",\n \"description\": \"Three-conveyor interlock: downstream conveyor must run before upstream starts — prevents backlog pileup in a warehousing pick-and-pack line.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"interlock\",\n \"conveyor\",\n \"permissive\",\n \"seal-in\",\n \"warehouse\",\n \"plc\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Multi-Conveyor Interlock\\\"\\n\\nrung 1 \\\"Conveyor C (discharge) — start with seal-in\\\":\\n parallel:\\n branch:\\n XIC(CONV_C_START_PB, \\\"IN 1.2\\\", name=\\\"Conv C Start Button\\\")\\n branch:\\n XIC(CONV_C_AUX, \\\"BIT 3.2\\\", name=\\\"Conv C Aux Contact\\\")\\n XIO(CONV_C_STOP_PB, \\\"IN 1.5\\\", name=\\\"Conv C Stop Button\\\")\\n XIO(ESTOP, \\\"IN 1.7\\\", name=\\\"E-Stop\\\")\\n OTE(CONV_C_CMD, \\\"OUT 2.2\\\", name=\\\"Conv C Command\\\")\\n\\nrung 2 \\\"Conveyor B — permissive: C must run first\\\":\\n XIC(CONV_C_RUNNING, \\\"BIT 3.2\\\", name=\\\"Conv C Running\\\")\\n parallel:\\n branch:\\n XIC(CONV_B_START_PB, \\\"IN 1.1\\\", name=\\\"Conv B Start Button\\\")\\n branch:\\n XIC(CONV_B_AUX, \\\"BIT 3.1\\\", name=\\\"Conv B Aux Contact\\\")\\n XIO(CONV_B_STOP_PB, \\\"IN 1.4\\\", name=\\\"Conv B Stop Button\\\")\\n XIO(ESTOP, \\\"IN 1.7\\\", name=\\\"E-Stop\\\")\\n OTE(CONV_B_CMD, \\\"OUT 2.1\\\", name=\\\"Conv B Command\\\")\\n\\nrung 3 \\\"Conveyor A (infeed) — permissive: B must run first\\\":\\n XIC(CONV_B_RUNNING, \\\"BIT 3.1\\\", name=\\\"Conv B Running\\\")\\n parallel:\\n branch:\\n XIC(CONV_A_START_PB, \\\"IN 1.0\\\", name=\\\"Conv A Start Button\\\")\\n branch:\\n XIC(CONV_A_AUX, \\\"BIT 3.0\\\", name=\\\"Conv A Aux Contact\\\")\\n XIO(CONV_A_STOP_PB, \\\"IN 1.3\\\", name=\\\"Conv A Stop Button\\\")\\n XIO(ESTOP, \\\"IN 1.7\\\", name=\\\"E-Stop\\\")\\n OTE(CONV_A_CMD, \\\"OUT 2.0\\\", name=\\\"Conv A Command\\\")\\n\\nrung 4 \\\"Aux contact mirror bits for downstream permissive logic\\\":\\n XIC(CONV_C_CMD, \\\"OUT 2.2\\\", name=\\\"Conv C Command\\\")\\n OTE(CONV_C_RUNNING, \\\"BIT 3.2\\\", name=\\\"Conv C Running\\\")\",\n \"notes\": \"## Scenario\\n\\nIn a warehousing pick-and-pack line, product travels from an infeed conveyor (A) through a sorter (B) to a discharge conveyor (C) that feeds the shipping dock. If the discharge belt stops while upstream belts keep running, product piles up at the transfer points — jams, falls, and potential injury. The IEC 61131-3 permissive interlock pattern solves this by enforcing a downstream-first start sequence: C must be confirmed running before B can start, and B must be confirmed running before A can start. A single E-stop contact (XIO ESTOP, wired normally-closed) threads through all three rungs so any emergency cut kills all belts simultaneously.\\n\\n## Annotation key\\n\\n- `XIC(CONV_C_RUNNING, ...)` — the permissive contact: passes only when the downstream conveyor aux bit is true (motor confirmed running via MCC feedback)\\n- `XIC(CONV_X_AUX, ...)` — seal-in contact that holds the rung true after the momentary start button releases\\n- `XIO(ESTOP, \\\"IN 1.7\\\", ...)` — E-stop wired normally-closed; opens on any emergency event, dropping all three OTE coils simultaneously\\n- `OTE(CONV_X_CMD, ...)` — energizes the motor starter contactor via the output module\\n- Rung 4 mirrors the CMD output bit into a RUNNING status bit used by upstream permissives; in real practice this bit would typically come from an MCC auxiliary contact feedback input rather than a mirrored output bit\\n\\n## How to read\\n\\nStart from the discharge end. Press Conv C start (Rung 1): the seal-in closes and CONV_C_RUNNING energizes. Now Rung 2 sees its permissive closed — pressing Conv B start latches B, which enables CONV_B_RUNNING for Rung 3. Finally Rung 3 allows Conv A to start. If any belt trips (aux contact drops) its RUNNING bit clears, immediately dropping the permissive for the next upstream belt and cascading a controlled stop without the operator touching anything.\"\n },\n {\n \"slug\": \"ladder-elevator-cab\",\n \"diagram\": \"ladder\",\n \"title\": \"Elevator call/destination with door interlock\",\n \"description\": \"Single-cab elevator: call-button latching, door-closed safety interlock, travel permissive, and overtravel limit-switch protection — IEC 61131-3 standard.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"elevator\",\n \"door-interlock\",\n \"limit-switch\",\n \"safety\",\n \"latch\",\n \"building\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Elevator Cab Control\\\"\\n\\nrung 1 \\\"Floor 1 call latch — set on button press, reset when cab arrives\\\":\\n XIC(FLOOR1_CALL_PB, \\\"IN 1.0\\\", name=\\\"Floor 1 Call Button\\\")\\n XIO(AT_FLOOR1, \\\"BIT 3.0\\\", name=\\\"Cab At Floor 1\\\")\\n OTL(FLOOR1_CALL, \\\"BIT 5.0\\\", name=\\\"Floor 1 Call Latch\\\")\\n\\nrung 2 \\\"Floor 1 call reset when cab arrives\\\":\\n XIC(AT_FLOOR1, \\\"BIT 3.0\\\", name=\\\"Cab At Floor 1\\\")\\n OTU(FLOOR1_CALL, \\\"BIT 5.0\\\", name=\\\"Floor 1 Call Latch\\\")\\n\\nrung 3 \\\"Floor 2 call latch — set on button press, reset when cab arrives\\\":\\n XIC(FLOOR2_CALL_PB, \\\"IN 1.1\\\", name=\\\"Floor 2 Call Button\\\")\\n XIO(AT_FLOOR2, \\\"BIT 3.1\\\", name=\\\"Cab At Floor 2\\\")\\n OTL(FLOOR2_CALL, \\\"BIT 5.1\\\", name=\\\"Floor 2 Call Latch\\\")\\n\\nrung 4 \\\"Floor 2 call reset when cab arrives\\\":\\n XIC(AT_FLOOR2, \\\"BIT 3.1\\\", name=\\\"Cab At Floor 2\\\")\\n OTU(FLOOR2_CALL, \\\"BIT 5.1\\\", name=\\\"Floor 2 Call Latch\\\")\\n\\nrung 5 \\\"Travel UP — permissive: door closed, not at top limit, no overload, floor 2 called\\\":\\n XIC(FLOOR2_CALL, \\\"BIT 5.1\\\", name=\\\"Floor 2 Call Latch\\\")\\n XIO(AT_FLOOR2, \\\"BIT 3.1\\\", name=\\\"Already At Floor 2\\\")\\n XIC(DOOR_CLOSED_SW, \\\"IN 1.4\\\", name=\\\"Door Closed Switch\\\")\\n XIO(AT_TOP_LIMIT, \\\"IN 1.5\\\", name=\\\"Top Overtravel Limit\\\")\\n XIO(OVERLOAD, \\\"IN 1.6\\\", name=\\\"Motor Overload\\\")\\n XIO(EMERG_STOP, \\\"IN 1.7\\\", name=\\\"Emergency Stop\\\")\\n OTE(TRAVEL_UP, \\\"OUT 2.0\\\", name=\\\"Travel Up Command\\\")\\n\\nrung 6 \\\"Travel DOWN — permissive: door closed, not at bottom limit, no overload, floor 1 called\\\":\\n XIC(FLOOR1_CALL, \\\"BIT 5.0\\\", name=\\\"Floor 1 Call Latch\\\")\\n XIO(AT_FLOOR1, \\\"BIT 3.0\\\", name=\\\"Already At Floor 1\\\")\\n XIC(DOOR_CLOSED_SW, \\\"IN 1.4\\\", name=\\\"Door Closed Switch\\\")\\n XIO(AT_BOT_LIMIT, \\\"IN 1.2\\\", name=\\\"Bottom Overtravel Limit\\\")\\n XIO(OVERLOAD, \\\"IN 1.6\\\", name=\\\"Motor Overload\\\")\\n XIO(EMERG_STOP, \\\"IN 1.7\\\", name=\\\"Emergency Stop\\\")\\n OTE(TRAVEL_DOWN, \\\"OUT 2.1\\\", name=\\\"Travel Down Command\\\")\\n\\nrung 7 \\\"Door open command — cab stopped at a floor, hold door open 5 s\\\":\\n XIC(AT_FLOOR, \\\"BIT 3.2\\\", name=\\\"Cab At Any Floor\\\")\\n XIO(TRAVEL_UP, \\\"OUT 2.0\\\", name=\\\"Travel Up\\\")\\n XIO(TRAVEL_DOWN, \\\"OUT 2.1\\\", name=\\\"Travel Down\\\")\\n TON(DOOR_HOLD_TMR, \\\"TMR 4.0\\\", name=\\\"Door Hold Timer\\\", preset=5000)\\n\\nrung 8 \\\"Door open output — energize while timer has not completed\\\":\\n XIC(AT_FLOOR, \\\"BIT 3.2\\\", name=\\\"Cab At Any Floor\\\")\\n XIO(DOOR_HOLD_TMR.DN, \\\"BIT 4.15\\\", name=\\\"Door Hold Timer Done\\\")\\n XIO(TRAVEL_UP, \\\"OUT 2.0\\\", name=\\\"Travel Up\\\")\\n XIO(TRAVEL_DOWN, \\\"OUT 2.1\\\", name=\\\"Travel Down\\\")\\n OTE(DOOR_OPEN_CMD, \\\"OUT 2.2\\\", name=\\\"Door Open Command\\\")\\n\\nrung 9 \\\"Safety alarm — emergency stop active or overload tripped\\\":\\n parallel:\\n branch:\\n XIC(EMERG_STOP, \\\"IN 1.7\\\", name=\\\"Emergency Stop\\\")\\n branch:\\n XIC(OVERLOAD, \\\"IN 1.6\\\", name=\\\"Motor Overload\\\")\\n OTE(SAFETY_ALARM, \\\"OUT 2.3\\\", name=\\\"Safety Alarm\\\")\",\n \"notes\": \"## Scenario\\n\\nA single-cab, two-floor freight elevator in a light industrial facility must satisfy three layers of safety: mechanical (overtravel limit switches at top and bottom of the shaft), electrical (door-closed interlock wired to the motor contactor permissive circuit), and control logic (emergency stop and overload relay contacts wired through the PLC input module). Call buttons latch so that pressing Floor 2 while the cab is already moving holds the request until the cab arrives and the arrival sensor clears it. The door-closed switch (normally-open, closes when doors are fully seated) is wired in series with both travel commands — the cab physically cannot move with doors open regardless of the PLC output state, and the PLC additionally enforces this in software. Overtravel limit switches (normally-closed, hardwired in series with the motor drive AND through the PLC input) provide dual-channel overtravel protection per EN 81-20.\\n\\n## Annotation key\\n\\n- `OTL(FLOORX_CALL, ...)` — latches the call request; the bit remains set even after the button is released\\n- `OTU(FLOORX_CALL, ...)` — clears the call latch when the AT_FLOOR sensor confirms arrival\\n- `XIC(DOOR_CLOSED_SW, ...)` — door interlock contact; normally-open switch closes only when both door panels are fully seated in the closed position\\n- `XIO(AT_TOP_LIMIT, ...)` and `XIO(AT_BOT_LIMIT, ...)` — normally-closed overtravel switches; XIO passes only when the bit is 0 (switch not tripped)\\n- `TON(DOOR_HOLD_TMR, preset=5000)` — 5 000 ms (5 s) door-hold timer; door stays open until the timer completes or a new travel command is issued\\n- `XIO(EMERG_STOP, ...)` — E-stop wired normally-closed to the input module; a pressed E-stop opens the circuit, drops the input bit to 0, and the XIO contact in travel rungs opens\\n\\n## How to read\\n\\nCall buttons latch immediately (Rungs 1 and 3) and unlatch on arrival (Rungs 2 and 4). Travel rungs (5 and 6) are pure permissive gates: they require a pending call, door closure, no overtravel, no overload, and no E-stop — all conditions must be true simultaneously. When the cab arrives at a floor (AT_FLOOR bit set), travel outputs drop, the door-hold timer starts (Rung 7), and the door open command fires (Rung 8) for 5 seconds. After 5 seconds, the door output de-energizes and the door-close mechanism can operate, after which the door-closed switch re-enables travel. Rung 9 provides an independent alarm output for SCADA/BAS notification on any safety event.\"\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-control\",\n \"diagram\": \"ladder\",\n \"title\": \"Tank level control — fill pump with float switch\",\n \"description\": \"Water-treatment tank level controller: high float inhibits fill, low float enables fill pump, with timer-based fill-cycle limiting and alarm.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"tank\",\n \"level\",\n \"float\",\n \"pump\",\n \"timer\",\n \"alarm\",\n \"water-treatment\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"ladder \\\"Tank Level Control\\\"\\n\\nrung 1 \\\"Fill pump — enable when low float set, inhibit at high float\\\":\\n XIC(FLOAT_LOW, \\\"IN 1.0\\\", name=\\\"Low Float Switch\\\")\\n XIO(FLOAT_HIGH, \\\"IN 1.1\\\", name=\\\"High Float Switch\\\")\\n XIO(PUMP_FAULT, \\\"IN 1.2\\\", name=\\\"Pump Fault\\\")\\n parallel:\\n branch:\\n XIC(PUMP_CMD, \\\"OUT 2.0\\\", name=\\\"Pump Command Seal-In\\\")\\n branch:\\n XIC(PUMP_AUX, \\\"BIT 3.0\\\", name=\\\"Pump Aux Contact\\\")\\n OTE(PUMP_CMD, \\\"OUT 2.0\\\", name=\\\"Fill Pump Command\\\")\\n\\nrung 2 \\\"Fill timer — tracks continuous pump run time\\\":\\n XIC(PUMP_CMD, \\\"OUT 2.0\\\", name=\\\"Fill Pump Running\\\")\\n TON(FILL_TMR, \\\"TMR 4.0\\\", name=\\\"Fill Cycle Timer\\\", preset=600000)\\n\\nrung 3 \\\"Overtime alarm — pump running too long suggests leak or low supply\\\":\\n XIC(FILL_TMR.DN, \\\"BIT 4.15\\\", name=\\\"Fill Timer Done\\\")\\n OTE(FILL_ALARM, \\\"OUT 2.1\\\", name=\\\"Fill Overtime Alarm\\\")\\n\\nrung 4 \\\"Pump start counter — tracks cycle frequency, alarm at 20 starts\\\":\\n XIC(PUMP_CMD, \\\"OUT 2.0\\\", name=\\\"Pump Command\\\")\\n XIO(PUMP_PREV, \\\"BIT 3.1\\\", name=\\\"Pump Previous Scan\\\")\\n CTU(PUMP_CTU, \\\"CNT 5.0\\\", name=\\\"Pump Start Counter\\\", preset=20)\\n\\nrung 5 \\\"Pump previous-scan latch — one-shot rising edge for counter\\\":\\n XIC(PUMP_CMD, \\\"OUT 2.0\\\", name=\\\"Pump Command\\\")\\n OTE(PUMP_PREV, \\\"BIT 3.1\\\", name=\\\"Pump Previous Scan\\\")\\n\\nrung 6 \\\"Cycle count alarm — too many starts per hour indicates hunting\\\":\\n XIC(PUMP_CTU.DN, \\\"BIT 5.15\\\", name=\\\"Pump Counter Done\\\")\\n OTE(CYCLE_ALARM, \\\"OUT 2.2\\\", name=\\\"Pump Cycle Alarm\\\")\",\n \"notes\": \"## Scenario\\n\\nMunicipal and industrial water treatment plants rely on simple float-switch level control for storage and process tanks. The fill pump must start when the tank drops to the low-float setpoint and stop when the high-float setpoint is reached. Two failure modes require alarm coverage: an overtime run (pump exceeds 10 continuous minutes) signals a supply shortage or tank leak; excessive start-stop cycling (more than 20 starts counted in a shift) signals float switch hunting or a check-valve failure that causes the pump to short-cycle. Both alarms feed the SCADA HMI and can page the on-call operator without requiring manual inspection.\\n\\n## Annotation key\\n\\n- `XIC(FLOAT_LOW, ...)` — low float switch closes (bit = 1) when water level drops below the low setpoint, enabling the pump\\n- `XIO(FLOAT_HIGH, ...)` — high float switch wired normally-closed; opens (bit = 0) when water reaches the high setpoint, breaking the rung and stopping the pump\\n- `XIO(PUMP_FAULT, ...)` — motor protection relay wired normally-closed; any thermal or overload trip de-energizes the coil\\n- `TON(FILL_TMR, preset=600000)` — Timer On Delay with 600 000 ms (10 min) preset; DN bit sets if the pump runs continuously beyond that duration\\n- `CTU(PUMP_CTU, preset=20)` — Count Up counter; incremented on each pump start rising edge via the one-shot PUMP_PREV pattern; DN bit sets at 20 counts\\n\\n## How to read\\n\\nRung 1 is the core control: power flows only if the low float is set AND the high float is not yet reached AND no fault exists. The seal-in (PUMP_CMD parallel with PUMP_AUX) holds the pump on after the low float clears due to rising water, until the high float finally opens the rung. Rung 2 starts a 10-minute timer whenever the pump is running; Rung 3 turns on the overtime alarm when that timer completes. Rungs 4–5 form a rising-edge one-shot: PUMP_PREV stores the previous scan state so the counter only increments once per pump start event. Rung 6 alarms when the cycle count reaches 20.\"\n },\n {\n \"slug\": \"ladder-traffic-light\",\n \"diagram\": \"ladder\",\n \"title\": \"4-way traffic light state machine\",\n \"description\": \"Four-way signalized intersection using sequential timer-based state bits — green/yellow/red cycling with pedestrian walk-button permissive.\",\n \"standard\": \"IEC 61131-3\",\n \"tags\": [\n \"ladder\",\n \"traffic-light\",\n \"state-machine\",\n \"timer\",\n \"pedestrian\",\n \"sequential\",\n \"municipal\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"ladder \\\"4-Way Traffic Signal\\\"\\n\\nrung 1 \\\"NS green phase — 30 s, then transition to NS yellow\\\":\\n XIC(NS_GREEN, \\\"BIT 5.0\\\", name=\\\"NS Green State\\\")\\n TON(NS_GREEN_TMR, \\\"TMR 4.0\\\", name=\\\"NS Green Timer\\\", preset=30000)\\n\\nrung 2 \\\"NS green timer done — clear NS green, set NS yellow\\\":\\n XIC(NS_GREEN_TMR.DN, \\\"BIT 4.15\\\", name=\\\"NS Green Timer Done\\\")\\n parallel:\\n branch:\\n OTU(NS_GREEN, \\\"BIT 5.0\\\", name=\\\"NS Green State\\\")\\n branch:\\n OTL(NS_YELLOW, \\\"BIT 5.1\\\", name=\\\"NS Yellow State\\\")\\n\\nrung 3 \\\"NS yellow phase — 5 s, then transition to EW green\\\":\\n XIC(NS_YELLOW, \\\"BIT 5.1\\\", name=\\\"NS Yellow State\\\")\\n TON(NS_YELLOW_TMR, \\\"TMR 4.1\\\", name=\\\"NS Yellow Timer\\\", preset=5000)\\n\\nrung 4 \\\"NS yellow done — clear NS yellow, set EW green\\\":\\n XIC(NS_YELLOW_TMR.DN, \\\"BIT 4.31\\\", name=\\\"NS Yellow Timer Done\\\")\\n parallel:\\n branch:\\n OTU(NS_YELLOW, \\\"BIT 5.1\\\", name=\\\"NS Yellow State\\\")\\n branch:\\n OTL(EW_GREEN, \\\"BIT 5.2\\\", name=\\\"EW Green State\\\")\\n\\nrung 5 \\\"EW green phase — 30 s (or shortened by ped button), then EW yellow\\\":\\n XIC(EW_GREEN, \\\"BIT 5.2\\\", name=\\\"EW Green State\\\")\\n TON(EW_GREEN_TMR, \\\"TMR 4.2\\\", name=\\\"EW Green Timer\\\", preset=30000)\\n\\nrung 6 \\\"EW green done — clear EW green, set EW yellow\\\":\\n XIC(EW_GREEN_TMR.DN, \\\"BIT 4.47\\\", name=\\\"EW Green Timer Done\\\")\\n parallel:\\n branch:\\n OTU(EW_GREEN, \\\"BIT 5.2\\\", name=\\\"EW Green State\\\")\\n branch:\\n OTL(EW_YELLOW, \\\"BIT 5.3\\\", name=\\\"EW Yellow State\\\")\\n\\nrung 7 \\\"EW yellow phase — 5 s, then back to NS green\\\":\\n XIC(EW_YELLOW, \\\"BIT 5.3\\\", name=\\\"EW Yellow State\\\")\\n TON(EW_YELLOW_TMR, \\\"TMR 4.3\\\", name=\\\"EW Yellow Timer\\\", preset=5000)\\n\\nrung 8 \\\"EW yellow done — clear EW yellow, set NS green (cycle restart)\\\":\\n XIC(EW_YELLOW_TMR.DN, \\\"BIT 4.63\\\", name=\\\"EW Yellow Timer Done\\\")\\n parallel:\\n branch:\\n OTU(EW_YELLOW, \\\"BIT 5.3\\\", name=\\\"EW Yellow State\\\")\\n branch:\\n OTL(NS_GREEN, \\\"BIT 5.0\\\", name=\\\"NS Green State\\\")\\n\\nrung 9 \\\"NS red output — active when not NS green and not NS yellow\\\":\\n XIO(NS_GREEN, \\\"BIT 5.0\\\", name=\\\"NS Green State\\\")\\n XIO(NS_YELLOW, \\\"BIT 5.1\\\", name=\\\"NS Yellow State\\\")\\n OTE(NS_RED_LAMP, \\\"OUT 2.0\\\", name=\\\"NS Red Lamp\\\")\\n\\nrung 10 \\\"EW red output — active when not EW green and not EW yellow\\\":\\n XIO(EW_GREEN, \\\"BIT 5.2\\\", name=\\\"EW Green State\\\")\\n XIO(EW_YELLOW, \\\"BIT 5.3\\\", name=\\\"EW Yellow State\\\")\\n OTE(EW_RED_LAMP, \\\"OUT 2.3\\\", name=\\\"EW Red Lamp\\\")\\n\\nrung 11 \\\"Pedestrian WALK signal — active during EW red (NS phase)\\\":\\n XIC(NS_GREEN, \\\"BIT 5.0\\\", name=\\\"NS Green State\\\")\\n XIC(PED_BUTTON, \\\"IN 1.0\\\", name=\\\"Pedestrian Push Button\\\")\\n OTE(PED_WALK_LAMP, \\\"OUT 2.6\\\", name=\\\"Walk Signal Lamp\\\")\",\n \"notes\": \"## Scenario\\n\\nA four-way signalized intersection in a municipal traffic management system runs a fixed-time North-South / East-West phase cycle mandated by the local department of transportation. The PLC program must implement a state-machine cycle — NS green → NS yellow → EW green → EW yellow → repeat — using retentive latched state bits so that a PLC power cycle or scan watchdog reset re-enters the cycle in a known state. Red outputs are derived by Boolean complement: a direction shows red whenever it holds neither a green nor a yellow state bit. The pedestrian walk signal is permitted only during the NS green phase when the push button is pressed, keeping pedestrians out of the EW travel path.\\n\\n## Annotation key\\n\\n- `OTL / OTU` — latched Set/Reset coils; state bits persist across PLC scan even if the energizing rung goes false, giving the state machine memory between timer firings\\n- `TON(X_TMR, preset=N)` — Timer On Delay; DN bit (`.DN`) asserts after N milliseconds of continuous rung-true; the timer resets automatically when its rung goes false\\n- `XIC(X_TMR.DN, ...)` — contacts the timer Done bit to trigger the state transition rung\\n- Rungs 9–10 compute red lamps by Boolean complement: if neither green nor yellow state is active, the red lamp energizes — no extra state bit required\\n- `XIC(PED_BUTTON, \\\"IN 1.0\\\", ...)` — pedestrian push button wired to a digital input; the walk lamp only energizes if both the NS green state is active AND the button is pressed\\n\\n## How to read\\n\\nThe state machine cycles through four latched bits: NS_GREEN → NS_YELLOW → EW_GREEN → EW_YELLOW → back to NS_GREEN. Each state bit starts its own TON timer. When the timer's DN bit asserts, a transition rung fires: it unlatches the current state and latches the next. Rungs 9 and 10 are output-only rungs that derive the red lamps from the absence of green and yellow state bits. Rung 11 gates the pedestrian walk signal behind both the NS green state and an explicit button press — pedestrians cannot walk during the EW green phase regardless of button presses.\"\n },\n {\n \"slug\": \"logic-4bit-comparator\",\n \"diagram\": \"logic\",\n \"title\": \"4-bit magnitude comparator\",\n \"description\": \"4-bit magnitude comparator — generates A>B, A=B, A<B outputs from four A and four B input bits using XOR-based equality detection and cascaded AND/OR logic.\",\n \"standard\": \"IEEE 91\",\n \"tags\": [\n \"logic\",\n \"comparator\",\n \"4-bit\",\n \"xor\",\n \"and\",\n \"or\",\n \"combinational\",\n \"magnitude\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"logic \\\"4-bit Magnitude Comparator\\\"\\ninput A3, A2, A1, A0, B3, B2, B1, B0\\noutput GT, EQ, LT\\n\\neq3 = XNOR(A3, B3)\\neq2 = XNOR(A2, B2)\\neq1 = XNOR(A1, B1)\\neq0 = XNOR(A0, B0)\\n\\nEQ = AND(eq3, eq2, eq1, eq0)\\n\\ng3 = AND(A3, NOT(B3))\\ng2 = AND(eq3, A2, NOT(B2))\\ng1 = AND(eq3, eq2, A1, NOT(B1))\\ng0 = AND(eq3, eq2, eq1, A0, NOT(B0))\\nGT = OR(g3, g2, g1, g0)\\n\\nLT = AND(NOT(GT), NOT(EQ))\",\n \"notes\": \"## Scenario\\n\\nA digital logic student or hardware designer needs the combinational logic that forms the core of a 74HC85-style 4-bit magnitude comparator — a fundamental building block used in address decoders, priority encoders, and ALU condition-code generation. This implementation uses XNOR gates for bit-wise equality detection and a priority-encoded AND-OR tree for the greater-than output, then derives less-than from the complement of the other two outputs.\\n\\n## Annotation key\\n\\n- `eq3`–`eq0` — XNOR of each bit pair; XNOR output is 1 when both inputs are equal (0=0 or 1=1)\\n- `EQ = AND(eq3, eq2, eq1, eq0)` — all four bit pairs must be equal for A=B\\n- `g3` — A>B contribution from MSB: A3=1 and B3=0 (A3 AND NOT B3)\\n- `g2`–`g0` — cascaded greater-than terms: bits 3 down to k must be equal, and at position k, Ak=1, Bk=0; priority order ensures the MSB difference dominates\\n- `GT = OR(g3, g2, g1, g0)` — A&gt;B if any of the priority-ordered greater-than conditions is true\\n- `LT = AND(NOT(GT), NOT(EQ))` — A&lt;B is derived: neither A&gt;B nor A=B; avoids re-implementing the symmetric AND-OR tree\\n\\n## How to read\\n\\nThe circuit operates in two independent paths. The equality path XNORs each bit pair and ANDs all four results together — EQ is 1 only when all four bit pairs match. The greater-than path uses a priority tree: the MSB difference (bit 3) overrides all lower bits, bit 2 is evaluated only when bits 3 are equal, and so on down to bit 0. The four AND terms feed an OR gate, producing GT=1 when A is lexicographically greater. LT is then simply the NOR of GT and EQ. This three-output structure matches the SN74LS85 TTL IC and can be cascaded for wider comparisons by connecting the cascade inputs of successive stages.\"\n },\n {\n \"slug\": \"logic-full-adder-iec\",\n \"diagram\": \"logic\",\n \"title\": \"1-bit full adder — IEC 60617 symbols\",\n \"description\": \"Same 1-bit full adder as the ANSI example but rendered with IEC 60617 rectangular symbols — for European curriculum and DIN standards compliance.\",\n \"standard\": \"IEC 60617\",\n \"tags\": [\n \"logic\",\n \"iec\",\n \"full-adder\",\n \"iec60617\",\n \"rectangular\",\n \"din\",\n \"european\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"logic \\\"1-bit Full Adder (IEC 60617)\\\"\\nstyle: iec\\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\\nEuropean engineering curricula, DIN-standard technical documentation, and IEC-compliant industrial datasheets use the rectangular gate symbols defined in IEC 60617-12 rather than the distinctive curved shapes of IEEE/ANSI 91. A student or engineer trained on European textbooks expects an XOR gate to show a rectangular box with the label \\\"=1\\\", an AND with \\\"&\\\", and an OR with \\\"≥1\\\" — this example produces exactly that representation from the same logical description as the ANSI full adder.\\n\\n## Annotation key\\n\\n- `style: iec` — switches all gate symbols from IEEE/ANSI curved shapes to IEC 60617 rectangular boxes with qualifier labels\\n- XOR box labeled `=1` — IEC notation: output is 1 when exactly one input is 1 (odd parity)\\n- AND box labeled `&` — IEC notation: output is 1 when all inputs are 1\\n- OR box labeled `≥1` — IEC notation: output is 1 when one or more inputs are 1\\n- Signal names, connections, and intermediate nodes are identical to the ANSI version — only the rendering changes\\n\\n## How to read\\n\\nThe logic function is identical to the standard full adder: two XOR gates compute the sum bit (A⊕B⊕Cin) and two AND gates feeding an OR gate compute the carry-out. The IEC rendering places all gates as equal-sized rectangles with standardized qualifier text inside each box. This makes the symbol set visually consistent across an entire schematic and unambiguous for any engineer who has learned from IEC-compliant references. Comparing this diagram to the ANSI version (`logic-full-adder`) illustrates how the same DSL produces output for two international standards by changing a single style flag.\"\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\": \"logic-parity-generator\",\n \"diagram\": \"logic\",\n \"title\": \"Even-parity generator (XOR tree)\",\n \"description\": \"4-bit even-parity generator using a three-level XOR tree — the standard error-detection circuit for serial communication and memory systems.\",\n \"standard\": \"IEEE 91\",\n \"tags\": [\n \"logic\",\n \"parity\",\n \"xor-tree\",\n \"error-detection\",\n \"even-parity\",\n \"serial\",\n \"communication\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"logic \\\"4-bit Even Parity Generator\\\"\\ninput D3, D2, D1, D0\\noutput P\\n\\nx1 = XOR(D3, D2)\\nx2 = XOR(D1, D0)\\nP = XOR(x1, x2)\",\n \"notes\": \"## Scenario\\n\\nParity generation is the simplest form of error detection used in UART serial frames, ECC memory, RAID-3 disk arrays, and CAN bus frames. An even-parity generator outputs a single parity bit P such that the total number of 1s in the data word plus P is always even, allowing the receiver to detect any single-bit error. The XOR tree structure makes this function fast (only two gate levels) and naturally scalable to wider data buses.\\n\\n## Annotation key\\n\\n- `x1 = XOR(D3, D2)` — first stage: XOR of the two most-significant data bits; output is 1 when D3 ≠ D2\\n- `x2 = XOR(D1, D0)` — first stage: XOR of the two least-significant data bits; output is 1 when D1 ≠ D0\\n- `P = XOR(x1, x2)` — second stage: XOR of the two partial-parity results; P=1 when the total number of 1s in D3–D0 is odd, making the combined word (D3,D2,D1,D0,P) even-parity\\n- XOR tree depth — log₂(N) gate levels for N input bits; this 4-bit tree has depth 2 (two pipeline stages)\\n- Even parity — P=0 when D3+D2+D1+D0 is already even; P=1 when the sum is odd\\n\\n## How to read\\n\\nThe circuit fans in from left (inputs D3–D0) to right (output P) across two gate levels. The first level pairs adjacent bit positions into two partial-parity signals x1 and x2. The second level XORs x1 and x2 to produce the final parity bit P. The XOR function is both associative and commutative, so the pairing order does not affect correctness. To extend to an 8-bit parity generator, add a third gate level that XORs the parity of the upper and lower nibbles. The receiver re-computes parity over the received data including P; a non-zero result indicates a single-bit (or any odd number of) transmission error.\"\n },\n {\n \"slug\": \"logic-sr-latch\",\n \"diagram\": \"logic\",\n \"title\": \"SR latch with NOR gates\",\n \"description\": \"NOR-based SR latch — the fundamental memory element; Set and Reset inputs, Q and Q̄ outputs — the sequential circuit every digital-logic student derives from first principles.\",\n \"standard\": \"IEEE 91\",\n \"tags\": [\n \"logic\",\n \"sr-latch\",\n \"nor\",\n \"sequential\",\n \"memory\",\n \"latch\",\n \"flip-flop\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"logic \\\"SR Latch (NOR)\\\"\\ninput S, R\\noutput Q, Q_bar\\n\\nQ = NOR(R, Q_bar)\\nQ_bar = NOR(S, Q)\",\n \"notes\": \"## Scenario\\n\\nThe SR (Set-Reset) latch built from two cross-coupled NOR gates is the simplest sequential logic element and the ancestor of every flip-flop, register, and SRAM cell. Digital logic students derive it in the first week of a sequential circuits lecture; VLSI designers recognize it as the core cell in standard-cell libraries. Schematex renders the cross-coupled back-edges automatically, producing the canonical feedback loop without manual wire routing.\\n\\n## Annotation key\\n\\n- `Q = NOR(R, Q_bar)` — upper NOR gate: Q is 1 only when R=0 and Q_bar=0; the Q_bar input is the feedback from the lower gate\\n- `Q_bar = NOR(S, Q)` — lower NOR gate: Q_bar is 1 only when S=0 and Q=0; the Q input is the feedback from the upper gate\\n- Cross-coupled feedback — each gate's output is one of the other gate's inputs; this creates two stable states and one unstable (forbidden) state\\n- Set (S=1, R=0): forces Q=1, Q_bar=0; latch remembers this state when S returns to 0\\n- Reset (R=1, S=0): forces Q=0, Q_bar=1; latch remembers this state when R returns to 0\\n- Hold (S=0, R=0): both NOR gates maintain their current outputs — the circuit stores one bit\\n- Forbidden (S=1, R=1): both Q and Q_bar driven to 0; undefined behavior when both inputs return to 0\\n\\n## How to read\\n\\nThe two NOR gates form a feedback loop: the output of each gate feeds back as one input of the other. In steady state, exactly one output is high and the other is low. Asserting S (Set) high drives Q_bar to 0, which allows Q to rise to 1, reinforcing Q_bar=0 even after S de-asserts — this is the stored \\\"1\\\" state. Asserting R (Reset) high drives Q to 0, which allows Q_bar to rise to 1, storing \\\"0\\\". The forbidden condition S=R=1 breaks the mutual exclusion and produces metastable behavior; real designs ensure S and R are never simultaneously asserted. The back-edges in the diagram represent physical wire connections creating the regenerative loop that gives the latch its memory property.\"\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-ansoff-growth\",\n \"diagram\": \"matrix\",\n \"title\": \"Ansoff growth matrix\",\n \"description\": \"Ansoff Product/Market matrix for a SaaS company's 3-year growth strategy — four quadrants with labeled strategic initiatives.\",\n \"standard\": \"Ansoff (1957)\",\n \"tags\": [\n \"matrix\",\n \"ansoff\",\n \"growth\",\n \"strategy\",\n \"product\",\n \"market\",\n \"consulting\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"matrix ansoff \\\"CloudHR — 3-Year Growth Strategy\\\"\\nstyle: quadrant\\nx-axis: \\\"Markets →\\\"\\ny-axis: \\\"Products →\\\"\\nQ2: \\\"Market Penetration\\\"\\nQ2: \\\"Grow enterprise sales team\\\"\\nQ2: \\\"Launch customer loyalty program\\\"\\nQ2: \\\"Increase self-serve conversion rate\\\"\\nQ1: \\\"Market Development\\\"\\nQ1: \\\"Expand to EMEA region\\\"\\nQ1: \\\"Enter SMB segment via PLG motion\\\"\\nQ1: \\\"Launch APAC channel partner program\\\"\\nQ3: \\\"Product Development\\\"\\nQ3: \\\"Launch mobile app\\\"\\nQ3: \\\"Add AI-powered insights module\\\"\\nQ3: \\\"Build compensation benchmarking add-on\\\"\\nQ4: \\\"Diversification\\\"\\nQ4: \\\"Acquire EdTech onboarding startup\\\"\\nQ4: \\\"Launch learning management module\\\"\",\n \"notes\": \"## Scenario\\n\\nA strategy consultant is facilitating a three-year planning session with the CEO and board of CloudHR, a mid-market SaaS HR platform. The Ansoff matrix structures the conversation by risk level: Market Penetration (existing product, existing market) is the lowest-risk quadrant and where most of this year's budget goes; Diversification (new product, new market) is the highest-risk quadrant and requires acquisition or a separate P&L. The chart provides a shared vocabulary for the board before the financial model is presented.\\n\\n## Annotation key\\n\\n- `matrix ansoff` — preset quadrant layout with the four Ansoff strategy names; axes flip Products (y) and Markets (x)\\n- `style: quadrant` — renders a 2×2 grid with quadrant title headers and bulleted initiative lists\\n- `Q2` (top-left) = **Market Penetration**: existing products sold into existing markets — lowest risk, often the highest near-term return\\n- `Q1` (top-right) = **Market Development**: existing products pushed into new markets — medium risk; requires go-to-market investment\\n- `Q3` (bottom-left) = **Product Development**: new products for existing customers — medium risk; leverages current relationships but requires R&D\\n- `Q4` (bottom-right) = **Diversification**: new products for new markets — highest risk; reserved for M&A or strategic bets with a long payback period\\n- Multiple `Q2:` / `Q3:` lines stack as a bullet list within the quadrant cell\\n\\n## How to read\\n\\nThe Ansoff matrix is a risk-ordering tool, not a prioritisation framework. Read it left-to-right, top-to-bottom as increasing risk. For CloudHR, the near-term revenue plan lives in Market Penetration: growing the existing enterprise sales motion, optimising self-serve conversion, and running a loyalty programme for renewals. Market Development (EMEA expansion, SMB product-led growth, APAC channel) is the 18-month horizon — same product, new buyer segments and geographies. Product Development (mobile app, AI module, compensation benchmarking) requires engineering investment but sells to the known customer base, keeping market-risk low. Diversification — acquiring an EdTech company and launching an LMS — is a 3-year strategic bet that only makes sense if the core business is healthy; the board should treat this quadrant as a separate capital allocation decision, not a line item in the operating budget.\"\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-rice-bubble\",\n \"diagram\": \"matrix\",\n \"title\": \"RICE feature prioritization (bubble chart)\",\n \"description\": \"RICE-scored feature backlog as a bubble chart — Reach × Impact axes, bubble size = Confidence, color = team — for the product sprint review.\",\n \"standard\": \"Sean McBride RICE framework (Intercom)\",\n \"tags\": [\n \"matrix\",\n \"rice\",\n \"prioritization\",\n \"bubble\",\n \"product\",\n \"backlog\",\n \"sprint\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"matrix \\\"RICE Prioritization — Q3 Feature Backlog\\\"\\nstyle: bubble\\nx-axis: \\\"Reach (users / quarter) →\\\"\\ny-axis: \\\"Impact (1–5 scale) →\\\"\\nitem \\\"SSO integration\\\" [x: 0.85, y: 0.90, size: 140, color: \\\"#1E88E5\\\"]\\nitem \\\"API v2\\\" [x: 0.65, y: 0.85, size: 110, color: \\\"#1E88E5\\\"]\\nitem \\\"Bulk export\\\" [x: 0.70, y: 0.55, size: 90, color: \\\"#43A047\\\"]\\nitem \\\"AI suggestions\\\" [x: 0.50, y: 0.80, size: 75, color: \\\"#FB8C00\\\"]\\nitem \\\"Dark mode\\\" [x: 0.90, y: 0.40, size: 120, color: \\\"#43A047\\\"]\\nitem \\\"Mobile app\\\" [x: 0.35, y: 0.75, size: 60, color: \\\"#FB8C00\\\"]\\nitem \\\"Audit log\\\" [x: 0.55, y: 0.60, size: 85, color: \\\"#E53935\\\"]\\nitem \\\"Custom webhooks\\\" [x: 0.40, y: 0.50, size: 50, color: \\\"#E53935\\\"]\",\n \"notes\": \"## Scenario\\n\\nA product manager is running the quarterly sprint-planning review and needs to communicate relative feature priority to three engineering teams — growth (blue), platform (green), and integrations (orange). RICE scoring normalises across very different feature sizes: a viral consumer feature with high reach but uncertain impact sits alongside a high-value enterprise feature with narrow reach and high confidence. The bubble chart makes the three-dimensional trade-off visible without a spreadsheet.\\n\\n## Annotation key\\n\\n- `style: bubble` — scatter plot; each item becomes a circle placed at (x, y) with area proportional to `size`\\n- `x-axis` — Reach: the estimated number of users who will encounter this feature per quarter, normalised 0–1\\n- `y-axis` — Impact: the 1–5 scale from the RICE formula (0.25 = minimal, 3 = massive)\\n- `size` — stands in for the Confidence score; a bubble sized 140 carries ~95 % confidence, 50 carries ~30 %\\n- `color` — team ownership: blue = growth squad, green = platform squad, orange = integrations squad, red = security/compliance team\\n- In RICE the full score is `(Reach × Impact × Confidence) / Effort`; this chart compresses the formula to the three bubble dimensions, leaving Effort as a narrative discussion point\\n\\n## How to read\\n\\nFeatures in the top-right quadrant (high reach, high impact) are the clear \\\"do next\\\" picks — SSO Integration and API v2 land there. Features with large bubbles (high confidence) that sit in the top-right are the easiest approval conversations. A small bubble in the top-right (AI Suggestions) warns that the impact estimate is speculative — the team needs more evidence before committing a full sprint. Dark mode has high reach but low-to-medium impact: a morale feature, not a growth lever. Mobile App and Custom Webhooks sit in the lower-left: either descope them this quarter or assign them to a later planning window. Features owned by the compliance team (red) typically have non-negotiable deadlines that override RICE priority — flag them separately before the sprint-planning final cut.\"\n },\n {\n \"slug\": \"matrix-risk-5x5\",\n \"diagram\": \"matrix\",\n \"title\": \"Risk register — 5×5 heat map (ISO 31000)\",\n \"description\": \"ISO 31000 5×5 likelihood × severity risk heat map with 8 project risks plotted — the standard risk-management deliverable for any project charter.\",\n \"standard\": \"ISO 31000:2018\",\n \"tags\": [\n \"matrix\",\n \"risk\",\n \"iso31000\",\n \"heat-map\",\n \"likelihood\",\n \"severity\",\n \"project\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"matrix \\\"Project Risk Register — ERP Migration\\\"\\nstyle: heat\\nrows: [\\\"Rare\\\", \\\"Unlikely\\\", \\\"Possible\\\", \\\"Likely\\\", \\\"Almost Certain\\\"]\\ncols: [\\\"Negligible\\\", \\\"Minor\\\", \\\"Moderate\\\", \\\"Major\\\", \\\"Catastrophic\\\"]\\ncell (0,0): low\\ncell (1,0): low\\ncell (2,0): low\\ncell (3,0): low\\ncell (4,0): medium\\ncell (0,1): low\\ncell (1,1): low\\ncell (2,1): medium\\ncell (3,1): medium\\ncell (4,1): high\\ncell (0,2): low\\ncell (1,2): medium\\ncell (2,2): medium\\ncell (3,2): high\\ncell (4,2): extreme\\ncell (0,3): medium\\ncell (1,3): medium\\ncell (2,3): high\\ncell (3,3): extreme\\ncell (4,3): extreme\\ncell (0,4): medium\\ncell (1,4): high\\ncell (2,4): extreme\\ncell (3,4): extreme\\ncell (4,4): extreme\\ndot \\\"Vendor delay\\\" at (2,2)\\ndot \\\"Data breach\\\" at (1,4)\\ndot \\\"Scope creep\\\" at (3,3)\\ndot \\\"Key staff turnover\\\" at (2,3)\\ndot \\\"Integration failure\\\" at (1,3)\\ndot \\\"Budget overrun\\\" at (3,2)\\ndot \\\"Regulatory change\\\" at (0,3)\\ndot \\\"User adoption failure\\\" at (2,4)\",\n \"notes\": \"## Scenario\\n\\nA project risk manager is populating the risk section of an ERP migration project charter. ISO 31000:2018 requires that risks be assessed on two independent axes — likelihood of occurrence and severity of consequence — then plotted on a heat map to determine which risks require immediate treatment plans and which can be monitored. This chart will be reviewed at the project steering committee and drives the risk-response budget allocation.\\n\\n## Annotation key\\n\\n- `style: heat` — renders a colour-filled grid; cell colour is determined by the risk rating keyword\\n- `rows` — likelihood scale, bottom to top: Rare (< 5 % probability), Unlikely (5–20 %), Possible (20–50 %), Likely (50–80 %), Almost Certain (> 80 %)\\n- `cols` — consequence / severity scale, left to right: Negligible → Minor → Moderate → Major → Catastrophic\\n- Cell ratings: `low` (green) = accept and monitor; `medium` (yellow) = treat or accept with controls; `high` (orange) = treat with priority; `extreme` (red) = immediate treatment required, may require escalation to executive sponsor\\n- `dot \\\"Label\\\" at (col, row)` — plots a named risk on the heat map at the rated coordinate; coordinates follow the (severity, likelihood) convention\\n\\n## How to read\\n\\nThe colour gradient runs from green in the bottom-left (low severity, low likelihood) to red in the top-right (catastrophic, almost certain). Any dot landing in an `extreme` cell (red) must have a documented treatment plan approved before the project can proceed to execution. This chart has three extreme risks: User Adoption Failure (almost certain, catastrophic), Scope Creep (likely, major), and Budget Overrun (possible, major) — the project manager needs mitigations for each before the charter is signed. Data Breach lands in a high cell: a cybersecurity review and data-handling controls should be scoped into the migration plan. Regulatory Change is rated low likelihood but still warrants a monitor because the consequence would be moderate. Vendor Delay and Integration Failure sit in medium territory — contingency buffer in the schedule is the standard treatment.\"\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-product-taxonomy\",\n \"diagram\": \"mindmap\",\n \"title\": \"E-commerce product category taxonomy\",\n \"description\": \"Mindmap of a fashion e-commerce catalog hierarchy — Women, Men, Kids, Accessories — for a platform team designing the navigation taxonomy.\",\n \"standard\": \"Google Product Taxonomy\",\n \"tags\": [\n \"mindmap\",\n \"ecommerce\",\n \"taxonomy\",\n \"product-catalog\",\n \"navigation\",\n \"fashion\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"mindmap\\n\\n# Fashion Catalog\\n\\n## Women\\n### Tops\\n- T-shirts\\n- Blouses\\n- Sweaters\\n### Bottoms\\n- Jeans\\n- Skirts\\n- Shorts\\n### Dresses\\n- Casual\\n- Formal\\n### Outerwear\\n- Coats\\n- Jackets\\n### Shoes\\n- Heels\\n- Sneakers\\n- Boots\\n\\n## Men\\n### Tops\\n- Shirts\\n- T-shirts\\n- Hoodies\\n### Bottoms\\n- Chinos\\n- Jeans\\n### Outerwear\\n- Coats\\n- Jackets\\n### Shoes\\n- Dress shoes\\n- Sneakers\\n\\n## Kids\\n### Boys\\n- Tops\\n- Bottoms\\n### Girls\\n- Tops\\n- Dresses\\n### Baby\\n- Bodysuits\\n- Sleepwear\\n\\n## Accessories\\n### Bags\\n- Handbags\\n- Backpacks\\n### Jewelry\\n- Necklaces\\n- Earrings\\n### Belts\\n### Hats\\n### Sunglasses\",\n \"notes\": \"## Scenario\\n\\nA platform product manager is redesigning the site navigation and needs to agree the canonical category taxonomy with merchandising, engineering, and SEO before implementation begins. This mindmap serves as the alignment artifact — every team can confirm their domain is correctly represented before a single URL slug is committed to the database schema. Branches can be reorganised in minutes; refactoring a live taxonomy costs weeks.\\n\\n## Annotation key\\n\\n- `#` — root: the catalog name\\n- `##` — top-level department (typically the primary nav bar item)\\n- `###` — sub-category (facet filter or secondary nav)\\n- `-` bullets — leaf-level category types (the URL-slug level)\\n\\n## How to read\\n\\nEach `##` branch is a primary department; its `###` children are the sub-category pages a shopper browses to. Leaf bullets are the final filter-level categories that appear in the faceted search panel. Consistent depth across departments signals a balanced taxonomy — a `###` node with only one leaf child is a candidate for flattening to reduce navigation depth and improve page discoverability.\"\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\": \"mindmap-research-paper-outline\",\n \"diagram\": \"mindmap\",\n \"title\": \"Literature review topic tree\",\n \"description\": \"Mindmap outlining a ML fairness literature review — research questions, subtopics, key papers — for a PhD student's systematic survey.\",\n \"standard\": \"Buzan (1970s)\",\n \"tags\": [\n \"mindmap\",\n \"literature-review\",\n \"research\",\n \"phd\",\n \"ml-fairness\",\n \"survey\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"mindmap\\n\\n# ML Fairness — Literature Review\\n\\n## Fairness Definitions\\n### Statistical\\n- Individual fairness\\n- Group fairness\\n### Causal\\n- Counterfactual fairness\\n- Path-specific effects\\n\\n## Bias Sources\\n### Data collection\\n- Sampling bias\\n- Historical bias\\n### Label noise\\n- Annotator disagreement\\n- Proxy labelling\\n### Proxy features\\n- Correlated attributes\\n- Redundant encodings\\n\\n## Mitigation Techniques\\n### Pre-processing\\n- Reweighing\\n- Resampling\\n### In-processing\\n- Adversarial debiasing\\n- Fairness constraints\\n### Post-processing\\n- Threshold adjustment\\n- Score calibration\\n\\n## Benchmark Datasets\\n- COMPAS recidivism\\n- Adult Income (UCI)\\n- CelebA facial attributes\\n- Drug consumption\\n\\n## Open Problems\\n- Intersectionality\\n- Dynamic fairness over time\\n- Fairness in generative models\",\n \"notes\": \"## Scenario\\n\\nA PhD student beginning a systematic survey of machine learning fairness needs to map the intellectual territory before writing a single word of the literature review. This mindmap externalises the topic structure so the advisor can give fast feedback on scope, missing subtopics, and emphasis — far cheaper to reorganise a mindmap than a draft chapter. The five branches correspond to the five sections the final paper will have.\\n\\n## Annotation key\\n\\n- `#` — root: the survey title and domain\\n- `##` — top-level section of the review\\n- `###` — subsection grouping related concepts\\n- `-` bullets — atomic concepts, methods, or datasets to cover\\n\\n## How to read\\n\\nStart at the centre and follow each branch outward. The two `##` branches on definitions frame the conceptual foundation; bias sources and mitigation techniques form the methodological core; benchmark datasets anchor the empirical evaluation section; open problems motivate the conclusion. Leaves are the unit of work — each bullet corresponds to at least one paper to read and synthesise before the branch is considered covered.\"\n },\n {\n \"slug\": \"orgchart-board-committees\",\n \"diagram\": \"orgchart\",\n \"title\": \"Corporate board and committee structure\",\n \"description\": \"Public-company board governance — full board with audit, compensation, nominating/governance, and risk subcommittees per SEC requirements.\",\n \"standard\": \"SEC / NYSE governance\",\n \"tags\": [\n \"orgchart\",\n \"board\",\n \"governance\",\n \"audit\",\n \"compensation\",\n \"sec\",\n \"committee\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"Acme Corp — Board & Committee Structure\\\"\\nchair: \\\"Victoria Harmon\\\" | Board Chair [role: advisor]\\n audit_chair: \\\"Ellen Frost, CPA\\\" | Audit Committee Chair [role: finance]\\n audit_m1: \\\"James Liu\\\" | Audit Committee Member [role: finance]\\n audit_m2: \\\"Priya Mehta\\\" | Audit Committee Member [role: finance]\\n comp_chair: \\\"Thomas Osei\\\" | Compensation Committee Chair [role: hr]\\n comp_m1: \\\"Sarah Nakamura\\\" | Compensation Committee Member [role: hr]\\n comp_m2: \\\"Rafael Dominguez\\\" | Compensation Committee Member [role: hr]\\n nom_chair: \\\"Linda Abramowitz\\\" | Nom. & Governance Chair [role: legal]\\n nom_m1: \\\"Derek Abubakar\\\" | Nom. & Governance Member [role: legal]\\n nom_m2: \\\"Yuki Fernandez\\\" | Nom. & Governance Member [role: legal]\\n risk_chair: \\\"Raj Mehta\\\" | Risk Committee Chair [role: ops]\\n risk_m1: \\\"Cynthia Okonkwo\\\" | Risk Committee Member [role: ops]\\n risk_m2: \\\"Simon Park\\\" | Risk Committee Member [role: ops]\\nboard_ceo: \\\"David Park\\\" | CEO (Management) [role: ceo]\\n mgmt_cfo: \\\"Angela Torres\\\" | CFO [role: finance]\\n mgmt_clo: \\\"Marcus Reyes\\\" | Chief Legal Officer [role: legal]\\nboard_ceo -.-> audit_chair\\nboard_ceo -.-> comp_chair\\nboard_ceo -.-> nom_chair\\nboard_ceo -.-> risk_chair\",\n \"notes\": \"## Scenario\\n\\nThe corporate secretary is preparing the annual proxy statement and needs to document the board's committee structure as required by SEC Regulation S-K Item 407 and NYSE Listed Company Rules. The four standing committees — Audit, Compensation, Nominating & Governance, and Risk — each consist entirely of independent directors. The CEO and CFO participate in committee meetings by invitation and report to the relevant committees, but are not members. The dotted lines from the CEO to each committee chair represent this management reporting relationship for operational matters.\\n\\n## Annotation key\\n\\n- `chair: \\\"Victoria Harmon\\\" | Board Chair [role: advisor]` — independent chair; non-executive\\n- Committee chairs and members use `[role: finance]`, `[role: hr]`, `[role: legal]`, `[role: ops]` to visually distinguish oversight focus\\n- `board_ceo: \\\"David Park\\\" | CEO (Management)` — management side; inside-the-box CEO distinct from the independent board\\n- `board_ceo -.-> audit_chair` — dotted lines represent management's accountability to each committee, not reporting hierarchy\\n- All committee members must be independent directors under SEC Rule 10A-3 (Audit) and NYSE Section 303A\\n\\n## How to read\\n\\nThe board chart has two distinct clusters. The upper cluster — Board Chair and the four committees — is the governance structure: independent directors exercising fiduciary oversight. The lower cluster — CEO and management — represents the executive team that is accountable to the board. Dotted lines from the CEO to each committee chair indicate that management attends and reports to committees without being members or having voting rights. The Audit Committee chair (Ellen Frost, CPA) satisfies the SEC's financial expert disclosure requirement. NYSE rules require that Compensation and Nom/Gov committees be composed solely of independent directors; the Risk Committee follows the same practice here but is not legally mandated to be fully independent.\"\n },\n {\n \"slug\": \"orgchart-engineering-dept\",\n \"diagram\": \"orgchart\",\n \"title\": \"Engineering department — platform, product, infra squads\",\n \"description\": \"Engineering org with three squad leads under a VP Eng — platform, product, and infrastructure, with open headcount flagged.\",\n \"standard\": \"HR convention\",\n \"tags\": [\n \"orgchart\",\n \"engineering\",\n \"squad\",\n \"platform\",\n \"infra\",\n \"product\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"Engineering Department — Q3 Headcount Plan\\\"\\nstaff_pe: \\\"Diana Okonkwo\\\" | Staff Principal Engineer [role: engineer]\\nvp_eng: \\\"Sarah Chen\\\" | VP Engineering [role: cto]\\n platform_lead: \\\"Marco Rossi\\\" | Platform Lead [role: engineer]\\n pe1: \\\"Kenji Watanabe\\\" | Senior Engineer | Platform [role: engineer]\\n pe2: \\\"Aaliya Hassan\\\" | Engineer | Platform [role: engineer]\\n pe3: \\\"Lucas Ferreira\\\" | Engineer | Platform [role: engineer]\\n open_sr: open \\\"TBH\\\" | Senior Engineer | Platform [role: engineer]\\n product_lead: \\\"Aisha Okafor\\\" | Product Eng Lead [role: engineer]\\n pe4: \\\"Rohan Mehta\\\" | Senior Engineer | Product [role: engineer]\\n pe5: \\\"Chloe Martin\\\" | Engineer | Product [role: engineer]\\n pe6: \\\"Jae-won Oh\\\" | Engineer | Product [role: engineer]\\n pe7: \\\"Fatima Al-Rashid\\\" | Engineer | Product [role: engineer]\\n draft_staff: draft \\\"TBH\\\" | Staff Engineer | Product [role: engineer]\\n infra_lead: \\\"Dev Patel\\\" | Infra Lead [role: engineer]\\n ie1: \\\"Nadia Kowalski\\\" | Senior SRE [role: engineer]\\n ie2: \\\"Emre Yilmaz\\\" | SRE [role: engineer]\\n open_sre: open \\\"TBH\\\" | Site Reliability Engineer [role: engineer]\\nstaff_pe -.-> platform_lead\\nstaff_pe -.-> product_lead\\nstaff_pe -.-> infra_lead\",\n \"notes\": \"## Scenario\\n\\nThe engineering director is presenting the Q3 headcount plan to the CFO. The chart shows three squads — platform, product engineering, and infrastructure — each under a dedicated lead reporting to the VP of Engineering. A Staff Principal Engineer provides technical oversight across all three squads via dotted-line relationships. Two open reqs are actively being recruited (Platform Senior Engineer, SRE), and one Staff Engineer seat in the product squad is planned for Q4 but not yet approved.\\n\\n## Annotation key\\n\\n- `vp_eng: \\\"Sarah Chen\\\" | VP Engineering [role: cto]` — VP-level node coloured with the cto role style\\n- Indentation (2 spaces) — solid-line reporting hierarchy\\n- `open \\\"TBH\\\"` — approved open requisition, currently recruiting\\n- `draft \\\"TBH\\\"` — planned headcount, not yet approved or posted\\n- `staff_pe -.-> platform_lead` — dotted line; technical authority without HR reporting chain\\n\\n## How to read\\n\\nThe tree root is the VP of Engineering. The three squad leads sit at the second level — equal peers in the org, differentiated only by domain. Headcount marked `open` (Platform Senior Eng, SRE) represents approved budget the director is actively spending; `draft` (Product Staff) is the ask for the next planning cycle. The staff principal at the top of the chart is neither the VP's direct report nor a squad lead: the dotted lines to all three leads signal that she sets technical standards and does architecture review across squads without owning any head count.\"\n },\n {\n \"slug\": \"orgchart-hospital-dept\",\n \"diagram\": \"orgchart\",\n \"title\": \"Hospital clinical department hierarchy\",\n \"description\": \"Hospital clinical org — Chief Medical Officer, department heads, attendings, residents, and nursing leads for a teaching hospital.\",\n \"standard\": \"JCAHO / hospital convention\",\n \"tags\": [\n \"orgchart\",\n \"hospital\",\n \"clinical\",\n \"physician\",\n \"nursing\",\n \"hierarchy\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"General Hospital — Clinical Leadership\\\"\\ncmo: \\\"Dr. Patricia Williams\\\" | Chief Medical Officer [role: medical]\\n chief_med: \\\"Dr. James Park\\\" | Chief of Medicine [role: medical]\\n cardio_head: \\\"Dr. Amara Nwosu\\\" | Division Chief | Cardiology [role: medical]\\n att_card1: \\\"Dr. Elena Sousa\\\" | Attending Physician [role: medical]\\n att_card2: \\\"Dr. Ravi Gupta\\\" | Attending Physician [role: medical]\\n res_card1: \\\"Dr. Yuki Tanaka\\\" | PGY-3 Resident [role: medical]\\n res_card2: \\\"Dr. Malik Johnson\\\" | PGY-2 Resident [role: medical]\\n neuro_head: \\\"Dr. Ingrid Larsen\\\" | Division Chief | Neurology [role: medical]\\n att_neuro1: \\\"Dr. Omar Sharif\\\" | Attending Physician [role: medical]\\n att_neuro2: \\\"Dr. Priya Krishnan\\\" | Attending Physician [role: medical]\\n res_neuro1: \\\"Dr. Tomás Rivera\\\" | PGY-3 Resident [role: medical]\\n res_neuro2: \\\"Dr. Aisha Conteh\\\" | PGY-2 Resident [role: medical]\\n chief_surg: \\\"Dr. Amara Diallo\\\" | Chief of Surgery [role: medical]\\n gen_surg_head: \\\"Dr. Wei Zhang\\\" | Division Chief | General Surgery [role: medical]\\n att_gs1: \\\"Dr. Sofia Reyes\\\" | Attending Surgeon [role: medical]\\n att_gs2: \\\"Dr. Kwame Mensah\\\" | Attending Surgeon [role: medical]\\n ortho_head: \\\"Dr. Henrik Svensson\\\" | Division Chief | Orthopedics [role: medical]\\n att_orth1: \\\"Dr. Nalini Patel\\\" | Attending Surgeon [role: medical]\\n att_orth2: \\\"Dr. Seun Adeyemi\\\" | Attending Surgeon [role: medical]\\n cno: \\\"Maria Gonzalez, RN, MSN\\\" | Chief Nursing Officer [role: medical]\\n med_surg_mgr: \\\"Lisa Park, RN\\\" | Nurse Manager | Med-Surg [role: medical]\\n icu_mgr: \\\"Robert Osei, RN\\\" | ICU Nurse Manager [role: medical]\",\n \"notes\": \"## Scenario\\n\\nA hospital administrator is preparing a JCAHO accreditation submission and needs to document the clinical governance structure. The chart shows the three-pillar model common to teaching hospitals: Medicine and Surgery under the CMO handle physician credentialing and clinical protocols, while Nursing reports separately to ensure independent oversight of nursing practice standards. Attendings supervise residents directly; residents rotate between divisions but report to their division chief.\\n\\n## Annotation key\\n\\n- `[role: medical]` — all clinical staff rendered with the medical colour coding\\n- Indentation — solid-line administrative and clinical reporting chain\\n- `PGY-2 / PGY-3` — Post-Graduate Year, the standard US resident designation (PGY-1 = intern)\\n- `RN, MSN` — inline credentials appended to the name field, common in nursing leadership notation\\n- Division Chiefs sit between the department Chief and individual attendings — the standard academic medical centre layer\\n\\n## How to read\\n\\nThe CMO owns clinical quality across all departments. Medicine and Surgery are equal pillars — each Chief has autonomous credentialing authority within their specialty. Within Medicine, Cardiology and Neurology each run their own attending–resident teaching structure: attendings carry clinical responsibility; residents operate under supervision with authority expanding by PGY year. Nursing reports up through the CNO rather than through either clinical chief — a deliberate governance separation required by Magnet hospital standards. The two nurse managers (Med-Surg floor, ICU) translate CNO policy to unit-level staffing and care protocols.\"\n },\n {\n \"slug\": \"orgchart-law-firm-partnership\",\n \"diagram\": \"orgchart\",\n \"title\": \"Law firm partnership structure\",\n \"description\": \"AmLaw 100-style law firm org — equity and non-equity partners, counsel, associates, and professional staff by practice group.\",\n \"standard\": \"NALP convention\",\n \"tags\": [\n \"orgchart\",\n \"law-firm\",\n \"partnership\",\n \"counsel\",\n \"associate\",\n \"legal\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"Chen & Associates LLP — Partnership Structure\\\"\\nmanaging_partner: \\\"Robert Chen\\\" | Managing Partner [role: ceo]\\n corp_chair: \\\"Jennifer Wu\\\" | Corporate Practice Chair [role: coo]\\n corp_ep1: \\\"David Okafor\\\" | Equity Partner | M&A [role: legal]\\n corp_ep1_sa1: \\\"Mei-Ling Torres\\\" | Senior Associate [role: legal]\\n corp_ep1_a1: \\\"Brendan Nwosu\\\" | Associate [role: legal]\\n corp_ep1_a2: \\\"Priya Sharma\\\" | Associate [role: legal]\\n corp_ep2: \\\"Simone Beaumont\\\" | Equity Partner | Securities [role: legal]\\n corp_ep2_sa1: \\\"Aleksei Volkov\\\" | Senior Associate [role: legal]\\n corp_ep2_a1: \\\"Fatou Diallo\\\" | Associate [role: legal]\\n corp_nep: \\\"Marcus Tran\\\" | Non-Equity Partner | Corporate [role: legal]\\n corp_nep_a1: \\\"Yuna Kim\\\" | Associate [role: legal]\\n corp_para1: \\\"Sandra Lopez\\\" | Paralegal [role: ops]\\n lit_chair: \\\"Marcus Johnson\\\" | Litigation Practice Chair [role: coo]\\n lit_ep1: \\\"Amara Osei\\\" | Equity Partner | Commercial Lit [role: legal]\\n lit_ep1_sa1: \\\"Tobias Gruber\\\" | Senior Associate [role: legal]\\n lit_ep1_a1: \\\"Chimamanda Eze\\\" | Associate [role: legal]\\n lit_ep2: \\\"Hiroshi Nakamura\\\" | Equity Partner | White Collar [role: legal]\\n lit_ep2_sa1: \\\"Valentina Cruz\\\" | Senior Associate [role: legal]\\n lit_ep2_a1: \\\"Daniel Abioye\\\" | Associate [role: legal]\\n lit_counsel: \\\"Rachel Goldstein\\\" | Counsel | Litigation [role: legal]\\n cfo: \\\"Dana Kim\\\" | COO / CFO [role: finance]\\n mkt: \\\"Alex Torres\\\" | Chief Marketing Officer [role: ops]\",\n \"notes\": \"## Scenario\\n\\nThe managing partner is preparing materials for the annual partnership meeting, including the governance deck and lateral-hire pitch collateral. The chart shows the two-track attorney structure common to AmLaw 100 firms: equity partners share in firm profits and have capital accounts; non-equity partners are on fixed compensation; counsel are senior attorneys on a permanent non-partnership track. Associates are levelled as first-through-fifth-year and senior (sixth-plus). Professional staff — COO/CFO and CMO — sit as firm-level directs to the managing partner.\\n\\n## Annotation key\\n\\n- `[role: legal]` — attorney nodes; `[role: finance]` and `[role: ops]` — professional staff\\n- Equity Partner — profit-sharing, voting interest in firm governance\\n- Non-Equity Partner — title parity without capital account; typically earns a fixed bonus-eligible salary\\n- Counsel — senior non-partner track: often former partners, domain specialists, or attorneys who opted out of the equity track\\n- Senior Associate — sixth year or above; on the partnership evaluation clock\\n- `corp_chair` / `lit_chair` — practice group chairs own lateral hiring, billing rate setting, and matter assignment within their group\\n\\n## How to read\\n\\nRobert Chen, as managing partner, chairs the firm's executive committee and carries final governance authority. The two practice chairs report to him and run their groups as semi-autonomous profit centres. Within each group, equity partners own client relationships and sign off on fee arrangements; associates bill under partner supervision. The non-equity partner in Corporate adds capacity without diluting the equity pool — a common structure when a client relationship is stable but not large enough to justify a new equity slot. Counsel in Litigation handles specialized motions work that would otherwise require lateral-hiring a lateral partner. The COO/CFO and CMO report directly to the managing partner rather than through a practice chair — they serve the whole firm, not a single group.\"\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-military-squadron\",\n \"diagram\": \"orgchart\",\n \"title\": \"Military squadron command hierarchy\",\n \"description\": \"Air Force fighter squadron org — Squadron Commander, DO, flight leads, and enlisted crew chiefs — with NATO rank notation.\",\n \"standard\": \"NATO rank convention\",\n \"tags\": [\n \"orgchart\",\n \"military\",\n \"squadron\",\n \"command\",\n \"nato\",\n \"rank\",\n \"air-force\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"orgchart \\\"87th Fighter Squadron — Command Structure\\\"\\ncc: \\\"Lt Col James Torres\\\" | Squadron Commander / O-5 [role: ceo]\\n safety_o: \\\"Capt Priya Singh\\\" | Safety Officer / O-3 [role: ops]\\n weapons_o: \\\"Capt Kwame Asante\\\" | Weapons Officer / O-3 [role: ops]\\n do: \\\"Maj Elena Voss\\\" | Director of Operations / O-4 [role: coo]\\n alpha_lead: \\\"Capt Robert Kim\\\" | Alpha Flight Lead / O-3 [role: engineer]\\n alpha_p1: \\\"1Lt Diego Morales\\\" | Pilot / O-2 [role: engineer]\\n alpha_p2: \\\"1Lt Anika Osei\\\" | Pilot / O-2 [role: engineer]\\n alpha_p3: \\\"2Lt Tomás Ibáñez\\\" | Pilot / O-1 [role: engineer]\\n alpha_p4: \\\"2Lt Mei Chen\\\" | Pilot / O-1 [role: engineer]\\n bravo_lead: \\\"Capt Fatima Al-Rashidi\\\" | Bravo Flight Lead / O-3 [role: engineer]\\n bravo_p1: \\\"1Lt Marcus Webb\\\" | Pilot / O-2 [role: engineer]\\n bravo_p2: \\\"1Lt Yuki Tanaka\\\" | Pilot / O-2 [role: engineer]\\n bravo_p3: \\\"2Lt Samuel Adeyemi\\\" | Pilot / O-1 [role: engineer]\\n bravo_p4: \\\"2Lt Natasha Voronova\\\" | Pilot / O-1 [role: engineer]\\n sq_supt: \\\"CMSgt Robert Lee\\\" | Squadron Superintendent / E-9 [role: ops]\\n mx_section: \\\"SMSgt Dana Park\\\" | Maintenance Section Chief / E-8 [role: ops]\\n cc1: \\\"TSgt Hiroshi Nakamura\\\" | Crew Chief / E-6 [role: ops]\\n cc2: \\\"TSgt Amara Diallo\\\" | Crew Chief / E-6 [role: ops]\\n cc3: \\\"SSgt Luisa Ferreira\\\" | Crew Chief / E-5 [role: ops]\\n cc4: \\\"SSgt Kofi Mensah\\\" | Crew Chief / E-5 [role: ops]\\n cc5: \\\"SSgt Ingrid Larsen\\\" | Crew Chief / E-5 [role: ops]\\n cc6: \\\"SSgt Brendan Nwosu\\\" | Crew Chief / E-5 [role: ops]\\n cc7: \\\"SSgt Valentina Cruz\\\" | Crew Chief / E-5 [role: ops]\\n cc8: \\\"SSgt Omar Bashir\\\" | Crew Chief / E-5 [role: ops]\\nadvisor adv1: \\\"Col Andrea Watanabe\\\" | Wing Commander / O-6 [role: advisor]\",\n \"notes\": \"## Scenario\\n\\nThe defense training officer is building a pre-deployment briefing package for NATO coalition partners. The chart uses the standard NATO officer grade notation (O-1 through O-6) and enlisted grade notation (E-5 through E-9) alongside rank titles, making it legible to allied forces regardless of their national naming conventions. The two staff officers (Safety and Weapons) are specialty billets that report directly to the commander — they advise on safety of flight and weapons employment doctrine without commanding pilots. The Wing Commander appears as an external advisor node, reflecting that she exercises authority over the squadron but is not in its internal chain.\\n\\n## Annotation key\\n\\n- `/ O-5` appended to title — NATO OF grade (OF-4 equivalent); O-5 = Lieutenant Colonel in USAF convention\\n- `/ E-9` — NATO OR grade; E-9 = Chief Master Sergeant, the highest enlisted grade in the USAF\\n- `Flight Lead` — the O-3 captain who leads a four-ship element; does not hold a separate command billet\\n- `Squadron Superintendent` — senior enlisted advisor to the commander; parallel authority track to the DO for enlisted matters\\n- `advisor adv1` — Wing Commander: exercises command over the squadron but is not in the internal org tree\\n- Safety Officer and Weapons Officer are staff (special duty) billets shown as direct reports to CC, not in the operations chain\\n\\n## How to read\\n\\nThe Squadron Commander (O-5) holds full command authority. Two parallel tracks report to him: the operations track runs through the Director of Operations (O-4) down to two flight leads each commanding four pilots; the enlisted track runs through the Squadron Superintendent (E-9) and Maintenance Section Chief (E-8) to eight crew chiefs responsible for aircraft airworthiness. Safety and Weapons officers are staff advisors — they brief the commander but do not command anyone. The Wing Commander sits outside the squadron tree as its higher headquarters: she can direct the CC but does not appear inside the squadron's internal structure.\"\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\",\n \"diagram\": \"pedigree\",\n \"title\": \"ART pedigree — IVF, gamete donor, gestational surrogate\",\n \"description\": \"Assisted reproduction technology pedigree with egg donor, sperm from intended father, and gestational surrogate — Bennett 2022 / NSGC ART symbols.\",\n \"standard\": \"Bennett 2022 / NSGC ART notation\",\n \"tags\": [\n \"pedigree\",\n \"art\",\n \"ivf\",\n \"egg-donor\",\n \"surrogate\",\n \"assisted-reproduction\",\n \"nsgc\",\n \"bennett-2022\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"ART Family — IVF with Egg Donor and Gestational Surrogate\\\"\\n intended_father [male, 1985, unaffected, label: \\\"Intended Father\\\"]\\n intended_mother [female, 1987, unaffected, label: \\\"Intended Mother\\\"]\\n egg_donor [female, 1995, donor, label: \\\"Egg Donor (anon.)\\\"]\\n surrogate [female, 1990, surrogate, label: \\\"Gestational Carrier\\\"]\\n intended_father -- intended_mother\\n egg_donor -- intended_father [donor: egg]\\n embryo_carrier [surrogate: surrogate]\\n child1 [female, 2022, proband, genotype: \\\"Genetic parents: IF + Donor\\\", label: \\\"Daughter\\\"]\",\n \"notes\": \"## Scenario\\n\\nA reproductive endocrinologist documents the conception and birth of a daughter (child1, proband) conceived through in-vitro fertilization using the intended father's sperm and an anonymous egg donor's oocyte. The resulting embryo was transferred to and carried by a gestational surrogate (who has no genetic relationship to the child). The intended parents are the legal and social parents. This pedigree structure — required for neonatal records, pediatric genetics intake, and any future reproductive risk counseling — must distinguish four distinct roles: intended mother (social/legal parent, no genetic contribution), intended father (genetic and legal parent), egg donor (genetic contributor, no parental role), and gestational surrogate (gestational carrier, no genetic or legal-parent role). Bennett 2022 ART symbols and NSGC 2008 guidelines both specify distinct visual encoding for each role.\\n\\n## Annotation key\\n\\n- `donor` — diamond symbol per Bennett 2022 / NSGC ART notation; used here for the anonymous egg donor; indicates a gamete contributor with no parental legal or social role\\n- `surrogate` — designated carrier symbol per Bennett 2022; used for the gestational surrogate; carries the embryo to term but contributes no genetic material and holds no parental legal role\\n- `[donor: egg]` — relationship qualifier on the egg donor's coupling line to the intended father's gamete; indicates the nature of the gametic contribution (oocyte)\\n- `intended_father -- intended_mother` — standard mating line between the intended (legal/social) parents; no shared genetic offspring line needed for the intended mother since she contributed no gametes\\n- `[surrogate: surrogate]` — identifies the gestational carrier for the embryo; child's birth line descends from the surrogate's womb, not from the intended mother\\n- `proband` — arrow on child1; the child is the index case for pediatric genetic records\\n- `genotype: \\\"Genetic parents: IF + Donor\\\"` — clinical annotation recording the genetic parentage for medical history and future counseling; intended mother's genetic non-contribution is documented explicitly\\n\\n## How to read\\n\\nThe intended parents (left) are a legally married couple. The intended mother contributed no genetic material; she is represented by an unaffected open circle connected to the intended father by a standard mating line but without a descent line to the child — her parental role is social and legal only. The egg donor (diamond symbol, upper right) contributed the oocyte; she is coupled to the intended father's sperm via a `[donor: egg]` relationship line. The resulting embryo was carried by the gestational surrogate (designated carrier symbol). The child's birth descent line flows from the surrogate, encoding the gestational path. The child inherits genetic material from the intended father and the egg donor only — the genotype annotation makes this explicit for future clinical use. If the child ever presents for her own reproductive genetic counseling, the pedigree immediately distinguishes her genetic risk profile (inherited from intended father + anonymous donor) from the family medical history of her social parents, preventing misattribution of heritable conditions.\"\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-consanguinity\",\n \"diagram\": \"pedigree\",\n \"title\": \"First-cousin marriage — autosomal recessive condition\",\n \"description\": \"Consanguineous pedigree with first-cousin union and autosomal recessive disorder — consanguinity bar notation, carrier status, and COI per NSGC clinical convention.\",\n \"standard\": \"NSGC\",\n \"tags\": [\n \"pedigree\",\n \"consanguinity\",\n \"autosomal-recessive\",\n \"first-cousin\",\n \"carrier\",\n \"coi\",\n \"nsgc\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"First-Cousin Consanguinity — Autosomal Recessive\\\"\\n I-1 [male, unaffected]\\n I-2 [female, carrier-ar]\\n I-1 -- I-2\\n II-1 [male, carrier-ar]\\n II-2 [female, carrier-ar]\\n II-3 [male, unaffected]\\n II-4 [female, carrier-ar]\\n II-1 -- II-4 [consanguineous]\\n III-1 [female, affected, proband, label: \\\"age 3\\\"]\\n III-2 [male, carrier-ar, label: \\\"age 5\\\"]\\n III-3 [male, unaffected, label: \\\"age 7\\\"]\",\n \"notes\": \"## Scenario\\n\\nA clinical geneticist evaluates a 3-year-old girl (III-1, proband) with a suspected autosomal recessive metabolic disorder confirmed on newborn screening and follow-up enzymatic assay. The parents (II-1 and II-4) are first cousins — their mothers are sisters, both daughters of the same founding couple (I-1 and I-2). The grandmother (I-2) is a known carrier. The pedigree demonstrates that a single copy of the mutant allele, carried silently by I-2, reached both parents through two independent descent paths, sharply elevating the probability that both parents are carriers and that offspring receive two copies of the disease allele. The coefficient of inbreeding (COI) for a first-cousin union is 1/16 (6.25%), and for any autosomal recessive condition with carrier rate q, the risk to offspring is substantially increased relative to a random-mating couple.\\n\\n## Annotation key\\n\\n- `carrier-ar` — half-filled symbol (bottom half shaded) per NSGC notation for autosomal recessive heterozygous carrier; one normal allele, one mutant allele (Aa)\\n- `unaffected` — open symbol; clinically unaffected; may be homozygous normal (AA) or carrier (Aa) — cannot be distinguished without molecular testing\\n- `affected` — fully filled symbol; homozygous for the disease allele (aa); proband with confirmed diagnosis\\n- `proband` — triangle arrow on III-1, the index case\\n- `[consanguineous]` — double horizontal bar between II-1 and II-4; NSGC standard notation for a consanguineous (blood-relative) mating; visually distinct from a normal mating line\\n- `label: \\\"age 3\\\"` / `\\\"age 5\\\"` / `\\\"age 7\\\"` — clinical age annotations on Generation III children; useful for surveillance scheduling and sibling testing recommendations\\n- I-2 `carrier-ar` — the common ancestor who introduced the mutant allele; both II-1 and II-4 are her biological children, making them first cousins\\n\\n## How to read\\n\\nThe founding couple (I-1 × I-2) produced four children: II-1, II-2, II-3, and II-4. I-2 is the obligate carrier (one mutant allele). Under autosomal recessive Mendelian transmission, each child of I-1 × I-2 had a 50% chance of inheriting the mutant allele. II-1 and II-4 are both confirmed carriers. Their first-cousin union is marked by the double consanguinity bar. With both parents heterozygous, their offspring face a 25% risk of being homozygous affected (aa), 50% carrier (Aa), and 25% homozygous normal (AA) — identical to any carrier × carrier cross, but the consanguinity structure explains *why* two carriers met: they share a common carrier ancestor. III-1 (proband, age 3) is affected (aa). III-2 (age 5) tested as a carrier. III-3 (age 7) is clinically unaffected; molecular testing to distinguish AA from Aa is recommended before reproductive planning. COI = 1/16 for this first-cousin union.\"\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\": \"pedigree-huntington\",\n \"diagram\": \"pedigree\",\n \"title\": \"Huntington disease — autosomal dominant 3-gen\",\n \"description\": \"Three-generation Huntington disease pedigree — autosomal dominant, late-onset, full penetrance — with predictive genetic testing notation per NSGC.\",\n \"standard\": \"NSGC\",\n \"tags\": [\n \"pedigree\",\n \"huntington\",\n \"autosomal-dominant\",\n \"late-onset\",\n \"genetic-testing\",\n \"nsgc\",\n \"neurology\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"pedigree \\\"Huntington Disease — Autosomal Dominant\\\"\\n I-1 [male, unaffected, deceased]\\n I-2 [female, affected, deceased, genotype: \\\"HTT CAG 42\\\"]\\n I-1 -- I-2\\n II-1 [male, affected, genotype: \\\"HTT CAG 42\\\", label: \\\"onset age 48\\\"]\\n II-2 [female, unaffected, genotype: \\\"HTT CAG 19\\\"]\\n II-3 [male, affected, genotype: \\\"HTT CAG 40\\\"]\\n II-4 [female, unaffected]\\n II-1 -- II-4\\n III-1 [male, proband, genotype: \\\"HTT CAG 42 — predictive positive\\\", label: \\\"age 28\\\"]\\n III-2 [female, unaffected, label: \\\"age 25, untested\\\"]\\n II-5 [female, unaffected]\\n II-3 -- II-5\\n III-3 [female, unaffected, genotype: \\\"HTT CAG 19\\\", label: \\\"age 22\\\"]\\n III-4 [male, unaffected, label: \\\"age 18, untested\\\"]\",\n \"notes\": \"## Scenario\\n\\nA neurogenetics counselor constructs this pedigree for a 28-year-old man (III-1, proband) who sought predictive genetic testing after his father (II-1) was diagnosed with Huntington disease at age 48. The patient's paternal grandmother (I-2) was also affected. Testing confirmed III-1 carries a fully penetrant expanded allele (CAG 42), placing him at near-certain risk for motor onset, typically in the fourth to fifth decade. His maternal aunt (II-2) tested negative (CAG 19 — within normal range). His paternal uncle (II-3) is also affected (CAG 40 — reduced penetrance boundary). The pedigree is required for multidisciplinary HD clinic records and insurance pre-authorization for neuropsychological surveillance.\\n\\n## Annotation key\\n\\n- `affected` — fully filled symbol; individual has received a clinical HD diagnosis with confirmed motor signs\\n- `unaffected` — open symbol; no clinical HD diagnosis; may or may not have been tested\\n- `deceased` — diagonal slash; I-1 and I-2 are deceased (I-2 died of HD complications)\\n- `proband` — triangle arrow; III-1, the index case who prompted genetic testing in this generation\\n- `genotype: \\\"HTT CAG 42\\\"` — molecular confirmation of an expanded CAG repeat in the HTT gene (≥36 is abnormal; ≥40 is fully penetrant)\\n- `genotype: \\\"HTT CAG 19\\\"` — normal allele; fewer than 36 CAG repeats; individual is not at risk\\n- `genotype: \\\"HTT CAG 40\\\"` — fully penetrant expanded allele; II-3 is affected with onset expected\\n- `genotype: \\\"HTT CAG 42 — predictive positive\\\"` — pre-symptomatic positive test in III-1; no motor signs yet\\n- `label: \\\"onset age 48\\\"` — clinical annotation on II-1 recording age of HD motor-sign onset\\n- `label: \\\"age 25, untested\\\"` / `label: \\\"age 18, untested\\\"` — at-risk relatives who have not undergone predictive testing; NSGC convention requires noting untested status\\n\\n## How to read\\n\\nThe inheritance pattern is autosomal dominant: every child of an affected parent has a 50% risk of inheriting the expanded allele, regardless of sex. I-2 (affected, CAG 42) passed the mutation to two of three children — II-1 (affected, CAG 42) and II-3 (affected, CAG 40); II-2 inherited the normal allele (CAG 19) and is not at risk. III-1 (proband) inherited the expanded allele from II-1 and is currently pre-symptomatic at age 28; motor onset is anticipated in his late 30s to mid-40s. His sister III-2 (age 25) has chosen not to undergo predictive testing — a clinically and ethically valid choice that the counselor must respect and document. III-3 (age 22) tested negative (CAG 19) and has been discharged from surveillance. III-4 (age 18) remains untested. The pedigree supports cascade testing recommendations for all at-risk Generation III members.\"\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-gene-family-unrooted\",\n \"diagram\": \"phylo\",\n \"title\": \"Gene family — unrooted network\",\n \"description\": \"Unrooted phylogenetic network of a multi-domain gene family across six organisms — shows reticulate evolution without assuming an outgroup.\",\n \"standard\": \"Newick (unrooted)\",\n \"tags\": [\n \"phylo\",\n \"unrooted\",\n \"gene-family\",\n \"reticulate\",\n \"genomics\",\n \"bioinformatics\",\n \"network\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"phylo \\\"MAPK Gene Family — Unrooted Network\\\"\\n layout: unrooted\\n root: midpoint\\n newick: \\\"(Human_MAPK1:0.12,Mouse_MAPK1:0.14,(Drosophila_RK:0.35,(CElegans_MPK1:0.42,(Yeast_FUS3:0.55,Yeast_KSS1:0.52):0.18[&&NHX:B=88]):0.25[&&NHX:B=75]):0.28[&&NHX:B=82],(Arabidopsis_MPK6:0.40,Rice_OsMPK6:0.38):0.22[&&NHX:B=95]);\\\"\\n clade Plant_MPK = (Arabidopsis_MPK6, Rice_OsMPK6) [color: \\\"#43A047\\\", label: \\\"Plant MAPK\\\"]\\n clade Yeast_MAPK = (Yeast_FUS3, Yeast_KSS1) [color: \\\"#FB8C00\\\", label: \\\"Yeast mating MAPK\\\"]\\n scale \\\"substitutions/site\\\"\",\n \"notes\": \"## Scenario\\n\\nWhen studying a conserved gene family such as MAP kinases across eukaryotes — from yeast to plants to mammals — a bioinformatician often cannot assume a single outgroup for rooting, or may suspect horizontal gene transfer or gene duplication events that make an unrooted representation more honest. The unrooted layout presents branch-length relationships without imposing a root hypothesis, letting the data speak.\\n\\n## Annotation key\\n\\n- `layout: unrooted` — radial unrooted network; no root implied; branch lengths are proportional to substitution rate\\n- `root: midpoint` — midpoint rooting used internally to anchor the layout, but no root node is drawn\\n- `[&&NHX:B=88]` — bootstrap support on internal nodes; lower values (75, 82) signal uncertain branching order\\n- `clade Plant_MPK = (Arabidopsis_MPK6, Rice_OsMPK6)` — green arc highlights the plant MAPK ortholog pair with strong support (95)\\n- `clade Yeast_MAPK = (Yeast_FUS3, Yeast_KSS1)` — orange arc highlights the two yeast mating-pathway MAPKs\\n\\n## How to read\\n\\nIn an unrooted network, evolutionary relatedness is inferred from branch length and topology, not from left-to-right order. Human and Mouse MAPK1 are closely related (short branches), forming a vertebrate cluster. The plant MAPKs (Arabidopsis and Rice, green arc) cluster with strong bootstrap support. The yeast mating MAPKs (FUS3 and KSS1, orange arc) form a well-supported clade with moderate support for their position among animals, consistent with deep conservation of the core kinase domain. Long branches to *Drosophila* and *C. elegans* indicate accelerated evolutionary rates in these lineages.\"\n },\n {\n \"slug\": \"phylo-primate-cladogram\",\n \"diagram\": \"phylo\",\n \"title\": \"Primate cladogram\",\n \"description\": \"Primate cladogram with 10 taxa — equal branch lengths emphasizing topology rather than evolutionary rate — for a physical anthropology or evolution course.\",\n \"standard\": \"Linnaean / cladistic\",\n \"tags\": [\n \"phylo\",\n \"primate\",\n \"cladogram\",\n \"anthropology\",\n \"hominid\",\n \"education\",\n \"topology\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"phylo \\\"Primate Cladogram\\\"\\n layout: cladogram\\n root: midpoint\\n newick: \\\"(((((Human:1,Chimp:1):1,Gorilla:1):1,Orangutan:1):1,(Gibbon:1,Siamang:1):1):1,((Baboon:1,Macaque:1):1,(Spider_monkey:1,Howler_monkey:1):1):1);\\\"\\n clade Hominidae = (Human, Chimp, Gorilla, Orangutan) [color: \\\"#1E88E5\\\", label: \\\"Hominidae (Great Apes)\\\"]\\n clade Lesser_apes = (Gibbon, Siamang) [color: \\\"#E53935\\\", label: \\\"Hylobatidae (Lesser Apes)\\\"]\\n clade Old_World = (Baboon, Macaque) [color: \\\"#43A047\\\", label: \\\"Cercopithecidae (Old World Monkeys)\\\"]\\n clade New_World = (Spider_monkey, Howler_monkey) [color: \\\"#FB8C00\\\", label: \\\"Atelidae (New World Monkeys)\\\"]\",\n \"notes\": \"## Scenario\\n\\nA physical anthropology or human evolution course uses cladograms — topology-only trees with equal branch lengths — to focus students on branching order and shared derived characters (synapomorphies) rather than evolutionary rate. This 10-taxon primate cladogram illustrates the nested hierarchy of ape, monkey, and human lineages in a format suitable for classroom projection, exam handouts, or textbook figures.\\n\\n## Annotation key\\n\\n- `layout: cladogram` — equal branch lengths; topology only; no molecular clock implied\\n- `clade Hominidae` — blue arc groups the four great ape genera: Homo, Pan, Gorilla, Pongo\\n- `clade Lesser_apes` — red arc groups Gibbon and Siamang (Hylobatidae), the sister group to great apes\\n- `clade Old_World` — green arc groups Baboon and Macaque (Cercopithecidae); Old World monkeys diverged before apes\\n- `clade New_World` — orange arc groups Spider monkey and Howler monkey (Atelidae); New World monkeys are the outgroup to Old World anthropoids\\n\\n## How to read\\n\\nReading from the tips inward, the most recently diverged taxa share the most recent common ancestor. Human and Chimpanzee are sister taxa (most recent common ancestor ~6 Ma); Gorilla is the next outgroup (~9 Ma), then Orangutan (~14 Ma). Lesser Apes (Gibbon, Siamang) are the sister group to all great apes. Together, apes (Hominoidea) are nested within the Old World monkey clade (Cercopithecidae) relative to New World monkeys, which form the most distant outgroup among primates shown here. Because this is a cladogram, branch lengths carry no quantitative meaning — only the branching pattern matters.\"\n },\n {\n \"slug\": \"phylo-sars-cov-2-variants\",\n \"diagram\": \"phylo\",\n \"title\": \"SARS-CoV-2 variant evolution tree\",\n \"description\": \"SARS-CoV-2 variant phylogeny — Alpha through XBB — showing lineage divergence from the Wuhan ancestral sequence, for epidemiology teaching.\",\n \"standard\": \"Newick/NHX (Nextstrain convention)\",\n \"tags\": [\n \"phylo\",\n \"sars-cov2\",\n \"covid\",\n \"variants\",\n \"epidemiology\",\n \"nextstrain\",\n \"rectangular\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"phylo \\\"SARS-CoV-2 Variant Evolution\\\"\\n layout: rectangular\\n newick: \\\"((((BA1_Omicron:0.05,BA2_Omicron:0.04):0.02[&&NHX:B=99],XBB_Omicron:0.07):0.03[&&NHX:B=95],(Delta_B1617:0.12,Kappa_B1617:0.10):0.08[&&NHX:B=90]):0.15[&&NHX:B=85],(Alpha_B117:0.18,Beta_B1351:0.20):0.10[&&NHX:B=88],Wuhan_WH1:0.01);\\\"\\n clade Omicron = (BA1_Omicron, BA2_Omicron, XBB_Omicron) [color: \\\"#C62828\\\", label: \\\"Omicron (B.1.1.529)\\\"]\\n clade Delta_clade = (Delta_B1617, Kappa_B1617) [color: \\\"#1565C0\\\", label: \\\"Delta lineage (B.1.617)\\\"]\\n clade Early_VOC = (Alpha_B117, Beta_B1351) [color: \\\"#2E7D32\\\", label: \\\"Early VOCs (Alpha / Beta)\\\"]\\n scale \\\"nucleotide substitutions/site\\\"\",\n \"notes\": \"## Scenario\\n\\nAn epidemiologist or public health educator needs to illustrate how SARS-CoV-2 variants of concern diverged from the ancestral Wuhan sequence to explain immune escape, vaccine effectiveness shifts, and the emergence of Omicron sublineages. This tree follows Nextstrain naming conventions and can be updated by swapping in a new Newick string from any phylogenetic inference tool.\\n\\n## Annotation key\\n\\n- `Wuhan_WH1:0.01` — ancestral Wuhan sequence placed as outgroup; very short branch reflects minimal divergence from the reference genome\\n- `[&&NHX:B=99]` — bootstrap support on internal nodes; values ≥ 95 indicate statistically robust branching\\n- `clade Omicron` — red arc groups BA.1, BA.2, and XBB subvariants; high bootstrap (99, 95) confirms monophyletic origin\\n- `clade Delta_clade` — blue arc groups the Delta and Kappa sub-lineages of B.1.617\\n- `scale \\\"nucleotide substitutions/site\\\"` — horizontal scale bar calibrated in nucleotide substitutions per site\\n\\n## How to read\\n\\nReading from the root (left) outward, the Wuhan ancestral sequence diverges first. The next split separates Early VOCs (Alpha and Beta, green arc) from the Delta and Omicron lineages. Within the right subtree, Delta (B.1.617) forms its own clade before the Omicron radiation. The Omicron clade (red arc) shows the tightest clustering and highest bootstrap support, consistent with rapid clonal expansion from a single introduction event. Branch lengths encode molecular divergence — the markedly longer Omicron branches reflect the elevated mutation burden relative to Delta and early VOCs.\"\n },\n {\n \"slug\": \"phylo-vertebrate-evolution\",\n \"diagram\": \"phylo\",\n \"title\": \"Vertebrate evolution — rectangular phylogram\",\n \"description\": \"Rectangular phylogram of 10 vertebrate orders with bootstrap support values, three clade arcs (Actinopterygii, Reptilia, Mammalia), and a branch-length scale bar.\",\n \"standard\": \"Newick/NHX\",\n \"tags\": [\n \"phylo\",\n \"vertebrate\",\n \"rectangular\",\n \"bootstrap\",\n \"clade\",\n \"evolution\",\n \"education\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"phylo \\\"Vertebrate Evolution\\\"\\n layout: rectangular\\n newick: \\\"((((Human:0.05,Chimp:0.06):0.04[&&NHX:B=99],(Mouse:0.15,Rat:0.14):0.08[&&NHX:B=97]):0.2[&&NHX:B=95],(Chicken:0.25,Crocodile:0.28):0.15[&&NHX:B=88]):0.3[&&NHX:B=72],(Zebrafish:0.45,(Salmon:0.5,Coelacanth:0.6):0.1[&&NHX:B=65]):0.4[&&NHX:B=80]);\\\"\\n clade Mammalia = (Human, Chimp, Mouse, Rat) [color: \\\"#1E88E5\\\", label: \\\"Mammalia\\\"]\\n clade Reptilia = (Chicken, Crocodile) [color: \\\"#E53935\\\", label: \\\"Reptilia (incl. Aves)\\\"]\\n clade Actinopterygii = (Zebrafish, Salmon) [color: \\\"#43A047\\\", label: \\\"Actinopterygii\\\"]\\n scale \\\"My (million years)\\\"\",\n \"notes\": \"## Scenario\\n\\nA high school or undergraduate biology teacher needs a clean, accurate vertebrate phylogeny for a lecture slide or lab handout — one that shows real evolutionary distances, bootstrap support for major clades, and standard clade annotations without requiring access to MEGA or FigTree. Schematex renders the Newick string directly to SVG with colored clade arcs and a calibrated scale bar.\\n\\n## Annotation key\\n\\n- `layout: rectangular` — rectangular phylogram; branch lengths are proportional to evolutionary distance (substitutions per site, scaled to million years)\\n- `[&&NHX:B=99]` — bootstrap support value on each internal node; values ≥ 95 indicate strong support\\n- `clade Mammalia = (Human, Chimp, Mouse, Rat)` — groups the four mammal taxa with a blue arc and label\\n- `clade Reptilia = (Chicken, Crocodile)` — highlights the reptile + bird clade (Sauropsida) in red\\n- `scale \\\"My (million years)\\\"` — draws a calibrated scale bar beneath the tree\\n\\n## How to read\\n\\nThe tree is rooted at the base of the vertebrate radiation. The deepest split separates ray-finned fishes (Actinopterygii: Zebrafish, Salmon) from the tetrapod lineage. Within tetrapods, Reptilia (Chicken, Crocodile) diverges first, then Mammalia splits into primates (Human, Chimp) and rodents (Mouse, Rat). Bootstrap values above 95 on the primate and rodent clades confirm strong statistical support. The Coelacanth, a lobe-finned fish, is an outgroup to the ray-finned fishes within the Actinopterygii clade, consistent with its status as a living fossil. Branch lengths are proportional to molecular evolutionary distance.\"\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-data-center-2n\",\n \"diagram\": \"sld\",\n \"title\": \"Data center — 2N redundant UPS and STS\",\n \"description\": \"Tier IV-style 2N data center power with dual utility feeds, dual UPS strings, static transfer switch, and A/B rack PDU distribution.\",\n \"standard\": \"Uptime Institute Tier IV\",\n \"tags\": [\n \"sld\",\n \"data-center\",\n \"2n\",\n \"ups\",\n \"sts\",\n \"tier4\",\n \"redundancy\",\n \"pdu\"\n ],\n \"complexity\": 5,\n \"featured\": false,\n \"dsl\": \"sld \\\"2N Data Center Power — Tier IV\\\"\\nutil_a = utility [label: \\\"Utility Feed A — 480V 3φ\\\"]\\nutil_b = utility [label: \\\"Utility Feed B — 480V 3φ\\\"]\\ngenset_a = generator [kw: 1500, voltage: 480]\\ngenset_b = generator [kw: 1500, voltage: 480]\\nats_a = ats [amps: 3000]\\nats_b = ats [amps: 3000]\\nbus_a = bus [voltage: 480]\\nbus_b = bus [voltage: 480]\\nups_a = ups [kva: 500]\\nups_b = ups [kva: 500]\\nsts = load [label: \\\"STS — Static Transfer Switch 400A\\\"]\\npdu_a1 = panel [label: \\\"PDU A1\\\"]\\npdu_a2 = panel [label: \\\"PDU A2\\\"]\\npdu_b1 = panel [label: \\\"PDU B1\\\"]\\npdu_b2 = panel [label: \\\"PDU B2\\\"]\\nrack = load [label: \\\"Server Racks — Dual Corded (A + B)\\\"]\\nutil_a -> ats_a\\ngenset_a -> ats_a\\nats_a -> bus_a\\nbus_a -> ups_a\\nups_a -> pdu_a1\\nups_a -> pdu_a2\\nutil_b -> ats_b\\ngenset_b -> ats_b\\nats_b -> bus_b\\nbus_b -> ups_b\\nups_b -> pdu_b1\\nups_b -> pdu_b2\\nups_a -> sts\\nups_b -> sts\\nsts -> rack\\npdu_a1 -> rack\\npdu_b1 -> rack\",\n \"notes\": \"## Scenario\\n\\nA critical facility engineer documents the power architecture of a Tier IV colocation data hall for client due diligence and for the commissioning authority. Uptime Institute Tier IV requires 2N redundancy — every active component has a full-capacity parallel path, so any single failure leaves loads on a remaining path without switching. The SLD is the primary deliverable for the owner's project requirements (OPR) document, the basis of design (BOD), and the commissioning test plan.\\n\\n## Annotation key\\n\\n- `utility [label:...]` — independent utility service entrance feeds (physically separate cable routes and substations for Tier IV)\\n- `generator [kw:..., voltage:...]` — on-site diesel generator with N+1 fuel supply; each supports its entire A or B string at 100% load\\n- `ats [amps:...]` — automatic transfer switch between utility and generator; positioned upstream of each UPS string\\n- `bus [voltage:...]` — 480 V distribution bus internal to each power string (A-side or B-side)\\n- `ups [kva:...]` — double-conversion UPS with bypass; battery provides ride-through during generator start-up\\n- `load [label: \\\"STS...\\\"]` — static transfer switch; selects between A-side and B-side UPS output in &lt;4 ms for single-corded loads\\n- `panel [label: \\\"PDU...\\\"]` — rack-level power distribution unit; feeds dual-corded servers at 208 V single-phase\\n- `load [label: \\\"Server Racks...\\\"]` — server racks with dual power supplies connected to both A and B PDUs simultaneously\\n- `->` — directed power flow; dual arrows into `rack` represent the two independent supply paths\\n\\n## How to read\\n\\nTwo completely independent power strings (A and B) run in parallel from utility source to rack. On the A-side: Utility Feed A and Generator A feed ATS-A, which supplies the 480 V A-bus, then UPS-A (500 kVA), then PDU A1 and A2. On the B-side the mirror image runs from Utility Feed B and Generator B. Server racks are dual-corded — one power supply connects to an A-side PDU, the other to a B-side PDU. Either path can carry 100% of rack load independently, satisfying Tier IV's concurrently maintainable and fault-tolerant requirements. The static transfer switch (STS) provides a UPS-backed path for any single-corded appliances; it monitors both UPS outputs and transfers to the healthy path within one quarter-cycle on the preferred source failing.\"\n },\n {\n \"slug\": \"sld-ev-fast-charger\",\n \"diagram\": \"sld\",\n \"title\": \"EV fast-charging site — 350 kW DCFC\",\n \"description\": \"Utility to 350 kW DC fast-charging site with service entrance, switchgear, three DCFC dispensers, and make-ready conduit per NEC 625.\",\n \"standard\": \"NEC 625\",\n \"tags\": [\n \"sld\",\n \"ev\",\n \"dcfc\",\n \"nec625\",\n \"charger\",\n \"switchgear\",\n \"480v\",\n \"fast-charging\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sld \\\"EV Fast-Charging Site — 350 kW DCFC\\\"\\nutility = utility [label: \\\"Utility 480V 3φ\\\"]\\nservice_entrance = breaker [amps: 1200]\\nmeter = meter [label: \\\"Revenue-Grade kWh Meter\\\"]\\nmain_sw = breaker [amps: 1000]\\nbrk1 = breaker [amps: 350]\\nbrk2 = breaker [amps: 350]\\nbrk3 = breaker [amps: 125]\\nbrk4 = breaker [amps: 350]\\ndcfc1 = load [label: \\\"DCFC Dispenser 1 — 150 kW\\\"]\\ndcfc2 = load [label: \\\"DCFC Dispenser 2 — 150 kW\\\"]\\ndcfc3 = load [label: \\\"DCFC Dispenser 3 — 50 kW\\\"]\\nfuture1 = load [label: \\\"Make-Ready — 150 kW (future)\\\"]\\nmgmt_panel = panel [label: \\\"Site Management / Network Hub\\\"]\\nutility -> service_entrance\\nservice_entrance -> meter\\nmeter -> main_sw\\nmain_sw -> brk1\\nmain_sw -> brk2\\nmain_sw -> brk3\\nmain_sw -> brk4\\nbrk1 -> dcfc1\\nbrk2 -> dcfc2\\nbrk3 -> dcfc3\\nbrk4 -> future1\\nmain_sw -> mgmt_panel\",\n \"notes\": \"## Scenario\\n\\nAn EV infrastructure engineer prepares the electrical permit drawings for a new public DC fast-charging station. The local building department and serving utility require a single-line diagram compliant with NEC Article 625 before issuing the electrical permit and utility service application. The SLD shows the complete power path from the utility point of delivery through the revenue-grade meter, switchgear, branch circuit breakers, and each DCFC dispenser. Conduit stubs for future capacity expansion must appear on the permit drawings so the AHJ approves the raceway sizing upfront, avoiding a costly panel changeout later.\\n\\n## Annotation key\\n\\n- `utility` — 480 V three-phase utility point of delivery; transformer and service lateral by the serving utility\\n- `breaker [amps: 1200]` — service entrance main breaker; NEC 230.79 requires a service disconnecting means at the building entry\\n- `meter [label:...]` — revenue-grade interval kWh meter for utility billing; also feeds demand data to the EVSE network\\n- `breaker [amps: 1000]` — main switchgear breaker protecting the DCFC distribution panel; sized at 125% of continuous EVSE load per NEC 625.42\\n- `breaker [amps: 350 / 125]` — branch circuit overcurrent protection for each DCFC or Level 2 circuit; NEC 625.42 requires 125% of EVSE nameplate continuous current\\n- `load [label: \\\"DCFC Dispenser...\\\"]` — DC fast-charge dispenser producing up to 150 kW at 400–920 V DC (CCS / CHAdeMO / NACS)\\n- `load [label: \\\"Make-Ready...\\\"]` — conduit, wire, and breaker space pre-installed for future dispenser; no energized equipment yet\\n- `panel [label:...]` — 120 V site management panel powering EVSE network communication modules, canopy lighting, and cameras\\n- `->` — directed power flow from utility source to EVSE loads\\n\\n## How to read\\n\\nThe serving utility delivers 480 V three-phase power to the 1200 A service entrance breaker, the utility demarcation point. Power passes through the revenue-grade kWh meter (metering before the load for accurate billing) then to the 1000 A main switchgear breaker that feeds the DCFC distribution section. Four branch circuit breakers fan out: two 350 A breakers supply the 150 kW dispensers (Dispensers 1 and 2), one 125 A breaker supplies the 50 kW dispenser (Dispenser 3), and one 350 A breaker feeds a make-ready stub — raceway, conductors, and a breaker space held for a future 150 kW unit. The site management panel receives a small 208 V tap from the switchgear for EVSE networking hardware, camera systems, and canopy lighting. Total installed load is 350 kW; service is sized to 560 kW to accommodate the make-ready future load without utility upgrade.\"\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-hospital-critical\",\n \"diagram\": \"sld\",\n \"title\": \"Hospital critical branch — NFPA 99 three-branch\",\n \"description\": \"Hospital essential electrical system with NFPA 99 life-safety, critical, and equipment branches fed via ATS from utility and generator.\",\n \"standard\": \"NFPA 99 / NFPA 110\",\n \"tags\": [\n \"sld\",\n \"hospital\",\n \"nfpa99\",\n \"life-safety\",\n \"critical-branch\",\n \"ats\",\n \"generator\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"sld \\\"Hospital Essential Electrical System — NFPA 99\\\"\\nutility = utility [label: \\\"Normal Power 480V 3φ\\\"]\\ngenset = generator [kw: 500, voltage: 480]\\nnormal_bus = bus [voltage: 480]\\nats1 = ats [amps: 400]\\nats2 = ats [amps: 600]\\nats3 = ats [amps: 400]\\nbrk_ls = breaker [amps: 400]\\nbrk_crit = breaker [amps: 600]\\nbrk_equip = breaker [amps: 400]\\nls_branch = load [label: \\\"Life-Safety Branch — Exit Lighting / Egress / Fire Alarm\\\"]\\ncrit_branch = load [label: \\\"Critical Branch — OR / ICU / Nurse Call\\\"]\\nequip_branch = load [label: \\\"Equipment Branch — HVAC / Sterilizers / Med Equip\\\"]\\nutility -> normal_bus\\nnormal_bus -> ats1\\ngenset -> ats1\\nats1 -> brk_ls\\nbrk_ls -> ls_branch\\nnormal_bus -> ats2\\ngenset -> ats2\\nats2 -> brk_crit\\nbrk_crit -> crit_branch\\nnormal_bus -> ats3\\ngenset -> ats3\\nats3 -> brk_equip\\nbrk_equip -> equip_branch\",\n \"notes\": \"## Scenario\\n\\nA hospital electrical engineer prepares the essential electrical system (EES) single-line diagram required for a new patient-care facility's construction permit and Joint Commission inspection. NFPA 99-2021 §6.4 mandates that hospitals classify all loads into three branches of the EES — life-safety, critical, and equipment — each with an automatic transfer switch that independently connects to both the normal utility supply and the on-site emergency generator. The SLD demonstrates code-compliant separation of branches and ensures the AHJ (authority having jurisdiction) can verify that no branch carries loads from a different classification.\\n\\n## Annotation key\\n\\n- `utility` — utility normal power source at 480 V three-phase\\n- `generator [kw:..., voltage:...]` — on-site diesel or natural-gas emergency generator per NFPA 110 Level 1 (10-second start)\\n- `bus [voltage:...]` — 480 V normal-power distribution bus; does not carry EES loads directly\\n- `ats [amps:...]` — automatic transfer switch; senses loss of utility and transfers load to generator within 10 s (NFPA 110)\\n- `breaker [amps:...]` — branch feeder overcurrent protective device isolating each NFPA 99 branch\\n- `load [label:...]` — EES branch terminal representing all panels and sub-feeders in that classification\\n- `->` — directed power flow; each ATS receives two upstream feeds (utility and generator) independently\\n\\n## How to read\\n\\nUtility normal power feeds the 480 V main bus. All three ATSs draw their normal-source feed from this bus. In parallel, the 500 kW on-site generator feeds the alternate-source input of each ATS independently — this is the NFPA 99 requirement that each branch have its own transfer means. Under normal conditions each ATS passes utility power through its branch breaker to its classified loads. On utility failure, each ATS independently transfers to the generator within 10 seconds. The life-safety branch (400 A) powers egress lighting, exit signs, and fire alarm — the highest-priority loads that must energize first. The critical branch (600 A) serves operating rooms, ICU receptacles, and nurse-call systems. The equipment branch (400 A) supports HVAC serving patient areas, sterilizers, and durable medical equipment. Physical and electrical separation between branches is a NFPA 99 §6.4.2 hard requirement.\"\n },\n {\n \"slug\": \"sld-industrial-480v-mcc\",\n \"diagram\": \"sld\",\n \"title\": \"Plant 480 V motor control center\",\n \"description\": \"Industrial 480V MCC with a 2000A main breaker, six motor starters and buckets, and a VFD for variable-speed pump — standard factory floor distribution.\",\n \"standard\": \"NEMA ICS-18\",\n \"tags\": [\n \"sld\",\n \"mcc\",\n \"industrial\",\n \"motor\",\n \"vfd\",\n \"480v\",\n \"nema\",\n \"starter\",\n \"bucket\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sld \\\"Plant 480V Motor Control Center — MCC-1\\\"\\nutility_480 = utility [label: \\\"Utility 480V 3φ\\\"]\\nmain_bkr = breaker [amps: 2000]\\nmcc_bus = bus [voltage: 480]\\nbrk_p101 = breaker [amps: 150]\\nbrk_m201 = breaker [amps: 100]\\nbrk_c301 = breaker [amps: 200]\\nbrk_vfd = breaker [amps: 125]\\nbrk_b401 = breaker [amps: 60]\\nbrk_a501 = breaker [amps: 60]\\nbrk_plc = breaker [amps: 30]\\nmotor_p101 = motor [hp: 75, label: \\\"Pump Motor P-101\\\"]\\nmotor_m201 = motor [hp: 50, label: \\\"Conveyor Motor M-201\\\"]\\nmotor_c301 = motor [hp: 100, label: \\\"Compressor C-301\\\"]\\nvfd1 = load [label: \\\"VFD — Cooling Tower Fan 60HP\\\"]\\nmotor_b401 = motor [hp: 30, label: \\\"Blower B-401\\\"]\\nmotor_a501 = motor [hp: 25, label: \\\"Agitator A-501\\\"]\\nplc_panel = panel [label: \\\"PLC Control Panel\\\"]\\nutility_480 -> main_bkr\\nmain_bkr -> mcc_bus\\nmcc_bus -> brk_p101\\nbrk_p101 -> motor_p101\\nmcc_bus -> brk_m201\\nbrk_m201 -> motor_m201\\nmcc_bus -> brk_c301\\nbrk_c301 -> motor_c301\\nmcc_bus -> brk_vfd\\nbrk_vfd -> vfd1\\nmcc_bus -> brk_b401\\nbrk_b401 -> motor_b401\\nmcc_bus -> brk_a501\\nbrk_a501 -> motor_a501\\nmcc_bus -> brk_plc\\nbrk_plc -> plc_panel\",\n \"notes\": \"## Scenario\\n\\nA plant electrical engineer documents Motor Control Center MCC-1 for a process facility expansion. The MCC single-line diagram is required for the electrical permit package, factory acceptance testing (FAT) at the MCC manufacturer's shop, and OSHA 70E arc-flash hazard analysis. NEMA ICS-18 defines the construction and testing standard for low-voltage MCC assemblies; each motor starter or VFD occupies a separate removable unit (bucket) with its own branch circuit breaker. The SLD confirms that motor ratings, breaker sizes, and conductor ampacities are consistent before the MCC is ordered and built.\\n\\n## Annotation key\\n\\n- `utility [label:...]` — 480 V three-phase plant distribution feeder supplying the MCC incoming section\\n- `breaker [amps: 2000]` — main incoming circuit breaker; isolates the entire MCC from the plant distribution bus\\n- `bus [voltage: 480]` — horizontal copper bus bar running the full length of the MCC; feeds all starter and VFD buckets\\n- `breaker [amps: N]` — individual motor branch circuit breaker (one per bucket); sized per NEC 430.52 at motor FLA × 250%\\n- `motor [hp:..., label:...]` — three-phase induction motor with full-voltage non-reversing (FVNR) starter; hp determines FLA and wire size\\n- `load [label: \\\"VFD...\\\"]` — variable-frequency drive controlling motor speed for the cooling tower fan; input breaker sized to VFD nameplate input amps\\n- `panel [label:...]` — 120/208 V control power panel for PLC I/O, pilot lights, push-button stations, and 24 V DC power supply\\n- `->` — directed power flow from MCC bus through breaker to motor or load\\n\\n## How to read\\n\\nThe 480 V three-phase utility feeder enters the MCC at the 2000 A main breaker, which serves as the MCC's service disconnecting means and fault interrupter. The main breaker feeds the horizontal MCC bus, from which seven branch circuit breakers distribute power to individual buckets. Five FVNR motor starters drive fixed-speed loads: the 75 HP process pump (P-101), 50 HP conveyor (M-201), 100 HP air compressor (C-301), 30 HP combustion air blower (B-401), and 25 HP tank agitator (A-501). The VFD bucket runs the 60 HP cooling tower fan at variable speed to maintain condenser water setpoint, saving fan energy at part load. The 30 A control power breaker feeds the PLC control panel that sequences all six driven loads and monitors process instruments through the MCC's control wiring.\"\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-solar-pv-commercial\",\n \"diagram\": \"sld\",\n \"title\": \"Commercial rooftop PV — grid-tied with net metering\",\n \"description\": \"200 kW commercial PV array through DC combiners, string inverters, AC disconnect, and bi-directional net-metering connection per NEC 690.\",\n \"standard\": \"NEC 690\",\n \"tags\": [\n \"sld\",\n \"solar\",\n \"pv\",\n \"nec690\",\n \"inverter\",\n \"net-metering\",\n \"commercial\",\n \"rooftop\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"sld \\\"200 kW Commercial Rooftop PV — Grid-Tied\\\"\\npv1 = pv_array [kw: 50]\\npv2 = pv_array [kw: 50]\\npv3 = pv_array [kw: 50]\\npv4 = pv_array [kw: 50]\\ncomb1 = combiner [inputs: 2]\\ncomb2 = combiner [inputs: 2]\\ninv1 = inverter [kw: 100]\\ninv2 = inverter [kw: 100]\\nac_disco = disconnect [amps: 240]\\nmain_bkr = breaker [amps: 250]\\nmeter_net = meter [label: \\\"Bi-directional Net Meter\\\"]\\nutility = utility [label: \\\"Utility 480V 3φ\\\"]\\nload_service = load [label: \\\"Facility Loads\\\"]\\npv1 -> comb1\\npv2 -> comb1\\npv3 -> comb2\\npv4 -> comb2\\ncomb1 -> inv1\\ncomb2 -> inv2\\ninv1 -> ac_disco\\ninv2 -> ac_disco\\nac_disco -> main_bkr\\nmain_bkr -> meter_net\\nmeter_net -> utility\\nmeter_net -> load_service\",\n \"notes\": \"## Scenario\\n\\nA PV system designer prepares the electrical permit package for a 200 kW grid-tied commercial rooftop installation. Local AHJ and the serving utility both require a signed, stamped single-line diagram per NEC Article 690 before issuing the interconnection agreement and net-metering tariff enrollment. The SLD must show the complete DC-to-grid power path, all overcurrent protection devices, the AC disconnect required by NEC 690.15, and the bi-directional production meter required by the utility's net-metering tariff.\\n\\n## Annotation key\\n\\n- `pv_array [kw:...]` — rooftop PV sub-array (strings of series-wired modules); four 50 kW sub-arrays total 200 kW DC\\n- `combiner [inputs:...]` — DC combiner box aggregating two sub-arrays per inverter input; includes string-level fusing per NEC 690.9\\n- `inverter [kw:...]` — grid-tied string inverter converting DC to 480 V AC three-phase; anti-islanding relay per NEC 690.61\\n- `disconnect [amps:...]` — utility-accessible AC disconnect switch required by NEC 690.15; 240 A rated for combined inverter output\\n- `breaker [amps:...]` — main production meter breaker; 250 A provides overcurrent protection at the point of common coupling\\n- `meter [label:...]` — bi-directional revenue-grade kWh meter recording both production (export) and consumption (import)\\n- `utility` — 480 V three-phase utility grid; receives surplus generation during export, supplies deficit during import\\n- `load [label:...]` — facility electrical loads consuming PV generation before any surplus reaches the grid\\n- `->` — directed DC or AC power flow; flow at net meter is bi-directional (arrow represents the prevailing export direction)\\n\\n## How to read\\n\\nFour 50 kW PV sub-arrays pair into two DC combiner boxes, each feeding one 100 kW string inverter. Both inverters merge at the 240 A AC disconnect — the utility-accessible isolation point required by NEC 690.15. The combined 200 kW AC output passes through the 250 A production breaker to the bi-directional net meter. From the net meter, power flows in either direction: when PV generation exceeds facility load, surplus energy exports to the utility grid and the meter records export kWh; when facility load exceeds generation (nights, cloudy days), the utility imports through the same meter. The serving utility reads the net difference for billing under the net-metering tariff, crediting the owner at the retail rate for each kWh exported.\"\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\": \"sld-wind-farm-collector\",\n \"diagram\": \"sld\",\n \"title\": \"Wind farm 34.5 kV collector system\",\n \"description\": \"Offshore-style wind farm with 8 turbines on two feeder strings, 34.5 kV collector bus, offshore substation, and 115 kV grid POI per IEEE 1547.\",\n \"standard\": \"IEEE 1547\",\n \"tags\": [\n \"sld\",\n \"wind\",\n \"collector\",\n \"34.5kv\",\n \"turbine\",\n \"offshore-substation\",\n \"ieee1547\",\n \"poi\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"sld \\\"Wind Farm 34.5 kV Collector System — 24 MW\\\"\\nwt1 = generator [kw: 3000, voltage: 0.69]\\nwt2 = generator [kw: 3000, voltage: 0.69]\\nwt3 = generator [kw: 3000, voltage: 0.69]\\nwt4 = generator [kw: 3000, voltage: 0.69]\\nwt5 = generator [kw: 3000, voltage: 0.69]\\nwt6 = generator [kw: 3000, voltage: 0.69]\\nwt7 = generator [kw: 3000, voltage: 0.69]\\nwt8 = generator [kw: 3000, voltage: 0.69]\\nxfmr_wt1 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt2 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt3 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt4 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt5 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt6 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt7 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nxfmr_wt8 = transformer [kva: 3500, primary: 0.69, secondary: 34.5]\\nfeeder_a = bus [voltage: 34.5]\\nfeeder_b = bus [voltage: 34.5]\\ncoll_bus = bus [voltage: 34.5]\\noffshore_xfmr = transformer [kva: 80000, primary: 34.5, secondary: 115]\\nhv_bus = bus [voltage: 115]\\npoi_sw = disconnect [amps: 1200]\\ngrid = utility [label: \\\"Grid 115 kV\\\"]\\nwt1 -> xfmr_wt1\\nwt2 -> xfmr_wt2\\nwt3 -> xfmr_wt3\\nwt4 -> xfmr_wt4\\nwt5 -> xfmr_wt5\\nwt6 -> xfmr_wt6\\nwt7 -> xfmr_wt7\\nwt8 -> xfmr_wt8\\nxfmr_wt1 -> feeder_a\\nxfmr_wt2 -> feeder_a\\nxfmr_wt3 -> feeder_a\\nxfmr_wt4 -> feeder_a\\nxfmr_wt5 -> feeder_b\\nxfmr_wt6 -> feeder_b\\nxfmr_wt7 -> feeder_b\\nxfmr_wt8 -> feeder_b\\nfeeder_a -> coll_bus\\nfeeder_b -> coll_bus\\ncoll_bus -> offshore_xfmr\\noffshore_xfmr -> hv_bus\\nhv_bus -> poi_sw\\npoi_sw -> grid\",\n \"notes\": \"## Scenario\\n\\nA wind project electrical engineer prepares the collector system single-line diagram for the utility interconnection application and the engineering report submitted to the transmission system operator (TSO). IEEE 1547-2018 governs the technical requirements for distributed energy resource (DER) interconnection at the point of interconnection (POI), including voltage and frequency ride-through, reactive power capability, and anti-islanding protection. The SLD must show the complete power path from each wind turbine generator (WTG) through the 34.5 kV collector cable system, offshore substation, and HV export cable to the grid POI, enabling the utility's protection engineer to model fault currents and relay coordination.\\n\\n## Annotation key\\n\\n- `generator [kw:..., voltage: 0.69]` — wind turbine generator producing 3 MW at low voltage (690 V); type-III DFIG or type-IV full-converter\\n- `transformer [kva: 3500, primary: 0.69, secondary: 34.5]` — pad-mount turbine step-up transformer (TST) at the base of each tower; steps 690 V to 34.5 kV for collection\\n- `bus [voltage: 34.5]` — 34.5 kV collector feeder string (submarine cable daisy-chaining 4 turbines per string); labeled feeder_a (WTs 1–4) and feeder_b (WTs 5–8)\\n- `bus [voltage: 34.5]` — 34.5 kV collector bus on the offshore substation platform aggregating both feeder strings\\n- `transformer [kva: 80000, primary: 34.5, secondary: 115]` — 80 MVA offshore substation main power transformer stepping 34.5 kV to 115 kV for the HV export cable\\n- `bus [voltage: 115]` — 115 kV HV bus on the offshore substation; connection point for the export cable and protection switchgear\\n- `disconnect [amps: 1200]` — POI disconnect switch at the onshore grid connection point; the IEEE 1547 interconnection boundary\\n- `utility [label:...]` — 115 kV transmission grid; TSO controls all operations beyond the POI\\n- `->` — directed power flow from turbine to grid; all flows are generation (export) during normal operation\\n\\n## How to read\\n\\nEach of the eight 3 MW wind turbine generators produces power at 690 V. A dedicated 3.5 MVA step-up transformer at the base of each tower raises the voltage to 34.5 kV for the underwater collection cable. Turbines 1–4 connect in a daisy-chain along Feeder A string; turbines 5–8 connect along Feeder B string. Both 12 MW strings converge at the 34.5 kV collector bus on the offshore substation platform. The 80 MVA offshore main transformer steps the collector voltage to 115 kV for the HV export cable to shore. At the onshore grid connection, the 1200 A POI disconnect switch marks the IEEE 1547 interconnection boundary — the point at which the wind farm's protection system must provide anti-islanding, frequency ride-through, and reactive power response per the interconnection agreement. Total nameplate capacity is 24 MW (8 × 3 MW); the 80 MVA transformer and 115 kV export system are sized with margin for a future second phase.\"\n },\n {\n \"slug\": \"sociogram-criminal-network\",\n \"diagram\": \"sociogram\",\n \"title\": \"Criminal network OSINT sociogram\",\n \"description\": \"Law-enforcement-style network sociogram mapping known associates, informants, and communication links in a hypothetical drug distribution network.\",\n \"standard\": \"Social network analysis (SNA)\",\n \"tags\": [\n \"sociogram\",\n \"criminal-network\",\n \"osint\",\n \"sna\",\n \"intelligence\",\n \"organized-crime\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"sociogram \\\"Hypothetical Drug Distribution Network — SNA Training Example\\\"\\n config: directed = true\\n config: layout = force-directed\\n\\n group leadership [label: \\\"Leadership\\\", color: \\\"#B71C1C\\\"]\\n subjectA; supplierH\\n group associates [label: \\\"Associates\\\", color: \\\"#E57373\\\"]\\n associateB; associateC; associateD\\n group couriers [label: \\\"Couriers\\\", color: \\\"#FF8A65\\\"]\\n courierE; courierF; courierG\\n group informants [label: \\\"Informants\\\", color: \\\"#78909C\\\"]\\n informantI\\n\\n subjectA -> associateB [label: \\\"financial direction\\\"]\\n subjectA -> associateC\\n subjectA -> associateD\\n associateB -> courierE [label: \\\"operational tasking\\\"]\\n associateC -> courierF\\n associateD -> courierG\\n supplierH -> subjectA [label: \\\"supply chain upstream\\\"]\\n informantI -> associateB [label: \\\"link unknown to Subject A\\\"]\\n associateB <-> associateC [label: \\\"peer coordination\\\"]\\n courierE -x> subjectA [label: \\\"conflict — link severed\\\"]\",\n \"notes\": \"## Scenario\\n\\nA law enforcement intelligence analyst builds this network diagram during a link-analysis phase of a drug distribution investigation. Social network analysis (SNA) identifies key nodes — the Subject A hub (a network star with high betweenness centrality), the upstream supplier, and the informant whose connection to Associate B is not yet known to Subject A. The force-directed layout naturally exposes hierarchical structure: leadership cluster at the center, operational associates at mid-distance, couriers at the periphery. All names are fictional; this diagram is a training example for SNA methodology.\\n\\n**All persons depicted are fictional. This diagram is for analytical methodology illustration only.**\\n\\n## Annotation key\\n\\n- `config: directed = true` — edges have direction, representing who directs or tasks whom; asymmetric in criminal hierarchies\\n- `config: layout = force-directed` — high-centrality nodes (Subject A, Associate B) naturally gravitate to the center; peripheral nodes (couriers) push to the edge\\n- `->` — directed operational link: command, financial, or supply chain relationship\\n- `<->` — mutual peer coordination link (both parties confirmed the connection)\\n- `-x>` — severed or conflicted link; the connection was documented but terminated\\n- `role: star` — node with the highest in-degree or betweenness centrality; primary analytical target\\n- `group` color coding — organizational tier in the network hierarchy\\n- `[label: \\\"...\\\"]` — edge label captures link type from OSINT or documented evidence\\n\\n## How to read\\n\\nSubject A is the network star — all three associates (B, C, D) receive direction from Subject A, and the upstream supplier feeds into Subject A exclusively. Each associate tasks a single courier, creating a cell structure that limits lateral exposure. Informant I has a confirmed link to Associate B that is not visible to Subject A — an intelligence asset whose operational security must be protected. The severed link from Courier E to Subject A (conflict edge) represents a documented falling-out and suggests Courier E may be a potential cooperating witness. The force-directed layout clusters the leadership nodes at center and pushes couriers to the periphery, matching the operational distance in the real network hierarchy. In a live investigation, node size would be scaled to betweenness centrality and edge labels would reference the evidentiary source (wire intercept, surveillance log, financial record).\"\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\": \"timeline-biography-einstein\",\n \"diagram\": \"timeline\",\n \"title\": \"Albert Einstein — biographical timeline\",\n \"description\": \"Einstein's life from birth through the photoelectric effect, special relativity, Nobel Prize, and Manhattan Project refusal — for science history class.\",\n \"standard\": \"Historical biography convention\",\n \"tags\": [\n \"timeline\",\n \"biography\",\n \"einstein\",\n \"science\",\n \"physics\",\n \"relativity\",\n \"history\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timeline \\\"Albert Einstein — Life and Work (1879–1955)\\\"\\nconfig: style = lollipop\\n\\n1879: \\\"Born in Ulm, Kingdom of Württemberg, Germany\\\" [side: below]\\n1896: \\\"Renounces German citizenship — moves to Switzerland\\\" [side: below]\\n1900: \\\"Graduates ETH Zürich — struggles to find academic post\\\" [side: below]\\n1905: milestone \\\"Annus Mirabilis — photoelectric effect, special relativity, E=mc²\\\" [side: above, color: #1565C0]\\n1909: \\\"First academic appointment — University of Zürich\\\" [side: below]\\n1914: \\\"Moves to Berlin — appointed to Prussian Academy of Sciences\\\" [side: below]\\n1916: milestone \\\"General Theory of Relativity published\\\" [side: above, color: #1565C0]\\n1919: milestone \\\"Eddington eclipse confirms gravitational lensing\\\" [side: above, color: #2E7D32]\\n1921: milestone \\\"Nobel Prize in Physics — photoelectric effect\\\" [side: above, color: #2E7D32]\\n1933: \\\"Flees Nazi Germany — joins Institute for Advanced Study, Princeton\\\" [side: below]\\n1939: \\\"Signs letter to FDR warning of German atomic bomb program\\\" [side: below, color: #B71C1C]\\n1952: \\\"Declines offer of Israeli presidency\\\" [side: below]\\n1955: \\\"Dies in Princeton, New Jersey, age 76\\\" [side: below]\",\n \"notes\": \"## Scenario\\n\\nA science history teacher uses this timeline as the opening slide for a unit on 20th-century physics. The biographical arc — obscure patent clerk to world's most famous scientist in a single decade — is as compelling as the physics itself. Blue diamonds mark the theoretical breakthroughs; green diamonds mark experimental confirmation and institutional recognition; the 1939 red event signals Einstein's ambivalent relationship with the political consequences of his work.\\n\\n## Annotation key\\n\\n- `milestone` — career-defining event (diamond marker)\\n- Blue diamonds — original theoretical contributions\\n- Green diamonds — external recognition and experimental validation\\n- Red label — politically significant letter to President Roosevelt warning of nuclear weapons\\n\\n## How to read\\n\\nTime flows left to right from 1879 to 1955. The 26 years between birth and the Annus Mirabilis (1905) are the long preparation; the single year 1905 produced four papers that would each individually have earned a place in physics history. The gap between the General Relativity paper (1916) and its experimental confirmation (1919) illustrates the typical lag between theory and observation. Note that the Nobel Prize (1921) was awarded not for relativity but for the photoelectric effect — the prize committee considered relativity too speculative at the time.\"\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-geologic-eras\",\n \"diagram\": \"timeline\",\n \"title\": \"Geologic time scale — Phanerozoic eon\",\n \"description\": \"Geologic time scale from the Cambrian explosion (541 Ma) to present — era bands with key extinction events per International Commission on Stratigraphy.\",\n \"standard\": \"ICS Geologic Time Scale 2023\",\n \"tags\": [\n \"timeline\",\n \"geology\",\n \"geologic-time\",\n \"paleozoic\",\n \"mesozoic\",\n \"cenozoic\",\n \"ics\",\n \"extinction\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"timeline \\\"Phanerozoic Eon — 541 Ma to Present\\\"\\nconfig: style = lollipop\\n\\n-541: milestone \\\"Cambrian explosion — first complex animals\\\" [side: above, color: #558B2F]\\n-488: \\\"Ordovician begins — marine invertebrates diversify\\\" [side: below]\\n-444: milestone \\\"End-Ordovician extinction — 85% species lost\\\" [side: above, color: #B71C1C]\\n-419: \\\"Silurian begins — first vascular land plants\\\" [side: below]\\n-359: milestone \\\"Late Devonian extinction — 75% species lost\\\" [side: above, color: #B71C1C]\\n-299: \\\"Permian begins — first reptiles dominant\\\" [side: below]\\n-252: milestone \\\"End-Permian extinction — Great Dying, 96% marine species lost\\\" [side: above, color: #B71C1C]\\n-201: milestone \\\"End-Triassic extinction — dinosaurs rise\\\" [side: above, color: #B71C1C]\\n-145: \\\"Cretaceous begins — flowering plants emerge\\\" [side: below]\\n-66: milestone \\\"K-Pg extinction — non-avian dinosaurs lost\\\" [side: above, color: #B71C1C]\\n-2.6: \\\"Pleistocene begins — repeated glacial cycles\\\" [side: below]\\n0: milestone \\\"Present day\\\" [side: above, color: #1565C0]\",\n \"notes\": \"## Scenario\\n\\nAn earth science teacher projects this timeline while introducing the Phanerozoic eon. The negative-year notation (Ma before present) lets students see geological time on a familiar number line. Red extinction diamonds are immediately recognisable as crises that reset evolutionary trajectories; the green Cambrian diamond marks the starting point of complex animal life. Students can see at a glance that mass extinctions are rare but catastrophic, and that the current geological moment is a vanishingly thin sliver at the right edge.\\n\\n## Annotation key\\n\\n- Negative numbers — millions of years before present (Ma); e.g. -252 = 252 Ma ago\\n- `milestone` — major geological boundary or mass extinction event\\n- Red diamonds — mass extinction events per ICS classification\\n- Green diamond — Cambrian explosion (origin of animal body plans)\\n- Blue diamond — present day reference anchor\\n\\n## How to read\\n\\nTime flows left to right from -541 Ma (Cambrian explosion) to 0 (today). The five red diamonds mark the Big Five mass extinctions recognised by the ICS; each wiped out a substantial fraction of species and reset evolutionary trajectories. The longest gap between crises (Ordovician to Devonian: ~75 Ma) shows that life can stabilise for tens of millions of years between upheavals. The entire Cenozoic Era — the age of mammals — occupies only the rightmost 12% of this timeline.\"\n },\n {\n \"slug\": \"timeline-history-of-ai\",\n \"diagram\": \"timeline\",\n \"title\": \"History of AI — 1950 to 2025\",\n \"description\": \"Lollipop timeline of AI milestones from Turing's 1950 paper through deep learning, LLMs, and AGI debate — for an AI course introduction.\",\n \"standard\": \"Historical convention\",\n \"tags\": [\n \"timeline\",\n \"ai\",\n \"history\",\n \"milestones\",\n \"deep-learning\",\n \"llm\",\n \"turing\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timeline \\\"History of Artificial Intelligence — 1950 to 2025\\\"\\nconfig: style = lollipop\\n\\n1950: milestone \\\"Turing: Computing Machinery and Intelligence — Turing Test proposed\\\" [side: above, color: #1565C0]\\n1956: \\\"Dartmouth Conference — field of AI named\\\" [side: below]\\n1966: milestone \\\"ELIZA chatbot — first natural-language interface\\\" [side: above, color: #6A1B9A]\\n1986: \\\"Rumelhart & Hinton: backpropagation popularized\\\" [side: below]\\n1997: milestone \\\"Deep Blue defeats Kasparov at chess\\\" [side: above, color: #1565C0]\\n2006: \\\"Hinton: deep belief networks — deep learning renaissance\\\" [side: below]\\n2012: milestone \\\"AlexNet wins ImageNet — top-5 error 15.3%\\\" [side: above, color: #2E7D32]\\n2017: \\\"Vaswani et al.: Attention Is All You Need\\\" [side: below]\\n2022: milestone \\\"ChatGPT — 1 million users in 5 days\\\" [side: above, color: #C62828]\\n2024: \\\"o1 reasoning model — chain-of-thought at inference\\\" [side: below]\\n2025: \\\"Multimodal frontier: GPT-4o, Claude 3, Gemini Ultra\\\" [side: below]\",\n \"notes\": \"## Scenario\\n\\nAn AI course instructor uses this timeline on the first day to give students a 75-year arc before diving into technical content. The lollipop layout alternates above and below the axis so events in the same decade do not collide. Colour separates conceptual foundations (blue), system breakthroughs (green), and societal impact moments (red) — students can immediately see that the field alternated between long winters and sudden step-changes.\\n\\n## Annotation key\\n\\n- `milestone` — diamond marker for field-defining events\\n- `[side: above|below]` — alternates labels to prevent overlap\\n- Blue — foundational theory; Green — benchmark performance leap; Purple — human-machine interaction; Red — public inflection point\\n\\n## How to read\\n\\nTime flows left to right from 1950 to 2025. Diamond markers are the headline breakthroughs; round markers are important supporting developments. Notice the 26-year gap between Turing's paper and ELIZA — AI winters were real. The acceleration from 2012 onward is structural: AlexNet, Transformers, and large language models each arrived faster than the last, compressing the time between conceptual proposal and world-scale deployment.\"\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\": \"timeline-product-roadmap-q-planning\",\n \"diagram\": \"timeline\",\n \"title\": \"Q3–Q4 product roadmap\",\n \"description\": \"Two-quarter product roadmap in Gantt-style swimlanes — Engineering, Product, Design, and Marketing tracks for a SaaS company's H2 plan.\",\n \"standard\": \"Product roadmap convention\",\n \"tags\": [\n \"timeline\",\n \"roadmap\",\n \"gantt\",\n \"swimlane\",\n \"product\",\n \"q3\",\n \"q4\",\n \"planning\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"timeline \\\"H2 Product Roadmap — Q3 & Q4 2025\\\"\\nconfig: style = gantt\\n\\nlane \\\"Engineering\\\"\\n 2025-07-01 - 2025-07-21: \\\"Auth refactor\\\" [category: engineering]\\n 2025-08-01 - 2025-09-12: \\\"API v3\\\" [category: engineering]\\n 2025-10-01 - 2025-10-28: \\\"Mobile performance\\\" [category: engineering]\\n 2025-11-03 - 2025-12-05: \\\"Search indexing upgrade\\\" [category: engineering]\\n\\nlane \\\"Product\\\"\\n 2025-07-01 - 2025-07-18: \\\"Feature discovery sprints\\\" [category: product]\\n 2025-08-01: milestone \\\"Q3 spec freeze\\\" [color: #E53935]\\n 2025-09-08 - 2025-09-26: \\\"Q4 planning & prioritization\\\" [category: product]\\n 2025-10-06: milestone \\\"Q4 spec freeze\\\" [color: #E53935]\\n\\nlane \\\"Design\\\"\\n 2025-07-01 - 2025-08-22: \\\"Design system v2\\\" [category: design]\\n 2025-10-01 - 2025-10-28: \\\"Mobile redesign\\\" [category: design]\\n 2025-11-03 - 2025-11-28: \\\"Onboarding flow refresh\\\" [category: design]\\n\\nlane \\\"Marketing\\\"\\n 2025-07-01 - 2025-08-15: \\\"Q3 demand-gen campaign\\\" [category: marketing]\\n 2025-09-15: milestone \\\"Product Hunt launch\\\" [color: #2E7D32]\\n 2025-10-01 - 2025-11-28: \\\"Q4 ABM outreach\\\" [category: marketing]\\n 2025-11-17: milestone \\\"Holiday campaign go-live\\\" [color: #2E7D32]\",\n \"notes\": \"## Scenario\\n\\nThe head of product presents this Gantt roadmap at the H2 planning offsite. Four swimlanes give each function a dedicated row so it is immediately clear which teams are working in parallel and where dependencies exist. The two spec-freeze diamonds act as forcing functions — everything Engineering needs from Product must land before each red diamond, or the downstream engineering bars shift right.\\n\\n## Annotation key\\n\\n- `lane \\\"Name\\\"` — swimlane grouping one team's work\\n- `DATE - DATE: \\\"Label\\\"` — continuous work block (horizontal bar)\\n- `DATE: milestone \\\"Label\\\"` — instantaneous checkpoint (diamond)\\n- `[category: …]` — colour assignment in the legend\\n- `[color: #hex]` — explicit milestone colour (red = freeze, green = launch)\\n\\n## How to read\\n\\nScan horizontally along a lane to understand one team's H2 workload. Scan vertically at any date to see what all four teams are doing simultaneously. Red diamonds mark spec freezes — if a bar extends past one, it needs an exception. Green diamonds mark external launches — every bar that feeds them must complete before the diamond or the launch slips. Gaps between bars are intentional buffer; bars with no gap indicate a team is at full capacity.\"\n },\n {\n \"slug\": \"timing-ddr-read\",\n \"diagram\": \"timing\",\n \"title\": \"DDR4 read burst timing\",\n \"description\": \"DDR4 read burst timing — CAS latency, data strobe (DQS), 8-beat DQ burst, and on-die termination (ODT) assertion — for memory subsystem engineers.\",\n \"standard\": \"JEDEC DDR4 (JESD79-4)\",\n \"tags\": [\n \"timing\",\n \"ddr4\",\n \"read-burst\",\n \"dqs\",\n \"cas-latency\",\n \"odt\",\n \"memory\",\n \"jedec\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"timing \\\"DDR4 Read Burst — CL=16, BL=8\\\"\\nCLK: pppppppppppppppppppp\\nCS_N: 10==================\\nRAS_N: 10==================\\nCAS_N: ================1===\\nWE_N: 1===================\\nODT: 00000000000000011111\\nDQS: 000000000000000ppppp\\nDQ: zzzzzzzzzzzzzzzx==== data: [\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\"]\",\n \"notes\": \"## Scenario\\n\\nA memory subsystem engineer, FPGA designer, or PCB layout engineer needs to verify DDR4 command and data timing against the JEDEC JESD79-4 specification during simulation or hardware bring-up. This diagram shows the critical timing relationships between the ACTIVATE command (RAS), the READ command (CAS), CAS latency (CL=16), DQS preamble, the 8-beat DQ burst, and ODT assertion for read termination.\\n\\n## Annotation key\\n\\n- `CLK` — differential clock; `p` = one double-data-rate clock cycle; data is transferred on both rising and falling edges\\n- `CS_N` / `RAS_N` — ACTIVATE command asserted (both low) at cycle 1 to open the target row\\n- `CAS_N` — READ command issued at cycle 16 (CAS_N goes high after assertion); CAS latency (CL=16) is the delay in clock cycles from READ command to first valid data\\n- `ODT` — on-die termination enables at the DRAM approximately tAONPD after the READ command to reduce signal reflections during the burst\\n- `DQS` — data strobe; preamble (first `p` of DQS) precedes the first data beat; controller samples DQ on each DQS edge\\n- `DQ` — data bus; `z` = high-impedance before burst, `x` = undefined transition, `=` = stable data; `data:[...]` labels each beat\\n\\n## How to read\\n\\nThe memory controller asserts ACTIVATE (CS_N + RAS_N low at cycle 1) to open the DRAM row, waits tRCD cycles, then issues a READ command (CS_N + CAS_N low at cycle 16). After CL=16 clock cycles, the DRAM begins driving DQS with a preamble half-clock before the first data beat. The controller captures DQ data on each DQS edge, collecting D0–D7 over 8 beats (BL=8). ODT is asserted before the burst begins to terminate the DQ and DQS lines during the read, suppressing reflections on the stub-heavy DDR4 bus. After D7, DQS and DQ return to high-impedance and ODT de-asserts.\"\n },\n {\n \"slug\": \"timing-i2c-read\",\n \"diagram\": \"timing\",\n \"title\": \"I²C master read transaction\",\n \"description\": \"I²C master-read timing with start condition, 7-bit address + R/W bit, ACK/NAK, and 2-byte data read — for embedded firmware documentation.\",\n \"standard\": \"NXP I²C specification\",\n \"tags\": [\n \"timing\",\n \"i2c\",\n \"master-read\",\n \"ack\",\n \"nak\",\n \"embedded\",\n \"firmware\",\n \"protocol\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"timing \\\"I²C Master Read — 2 Bytes\\\"\\nSCL: 1ppppppppppppppppppppppppppp11\\nSDA: 10========10========10======01 data: [\\\"START\\\",\\\"0x48 R\\\",\\\"ACK\\\",\\\"0xAB\\\",\\\"ACK\\\",\\\"0xCD\\\",\\\"NAK\\\",\\\"STOP\\\"]\",\n \"notes\": \"## Scenario\\n\\nAn embedded firmware engineer documents a two-byte I²C master-read transaction — for example, reading two bytes of temperature data from a TMP112 or similar sensor at address 0x48 — for inclusion in a device driver review, BSP documentation, or a hardware bring-up checklist. The timing diagram shows the key protocol phases: START, address frame with R/W bit, ACK handshake, data bytes, and STOP.\\n\\n## Annotation key\\n\\n- `SCL` — serial clock line; `p` is one clock pulse (high then low); `1` = sustained high, `0` = sustained low\\n- `SDA` — serial data line; `1` = high, `0` = low, `=` = stable (bus driven), value labeled by `data:[...]`\\n- `10=...=` pattern on SDA — START condition: SDA falls while SCL is high, followed by address bits held stable during each SCL high phase\\n- `ACK` (SDA=0 during 9th SCL pulse) — receiver acknowledges by pulling SDA low\\n- `NAK` (SDA=1 during 9th SCL pulse after last byte) — master signals end of read by releasing SDA high\\n- `STOP` — SDA rises while SCL is high, signaling bus release\\n\\n## How to read\\n\\nThe transaction opens with a START condition (SDA falls while SCL is high). The master clocks out a 7-bit device address (0x48) plus a Read bit (R/W=1) over 8 SCL pulses; the addressed slave pulls SDA low during the 9th clock as ACK. The slave then drives the first data byte (0xAB) over 8 clocks; the master ACKs to request more data. The slave drives the second byte (0xCD); the master issues NAK to signal no further bytes are needed. Finally, the master generates a STOP condition (SDA rises while SCL is high), releasing the bus. Both lines return to idle-high.\"\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\": \"timing-uart-frame\",\n \"diagram\": \"timing\",\n \"title\": \"UART 8N1 frame timing\",\n \"description\": \"UART 8-bit, no parity, 1 stop bit (8N1) frame timing at 115200 baud — showing idle, start bit, 8 data bits, and stop bit for a firmware datasheet.\",\n \"standard\": \"TIA-232 (RS-232)\",\n \"tags\": [\n \"timing\",\n \"uart\",\n \"8n1\",\n \"serial\",\n \"baud\",\n \"start-bit\",\n \"stop-bit\",\n \"firmware\",\n \"rs232\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"timing \\\"UART 8N1 Frame — 115200 baud — 'A' (0x41)\\\"\\nTX: 1 0 1 0 0 0 0 0 1 0 1 1 data: [\\\"IDLE\\\",\\\"START\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\",\\\"D4\\\",\\\"D5\\\",\\\"D6\\\",\\\"D7\\\",\\\"STOP\\\",\\\"IDLE\\\"]\\nRX: 1 0 1 0 0 0 0 0 1 0 1 1 data: [\\\"IDLE\\\",\\\"START\\\",\\\"D0\\\",\\\"D1\\\",\\\"D2\\\",\\\"D3\\\",\\\"D4\\\",\\\"D5\\\",\\\"D6\\\",\\\"D7\\\",\\\"STOP\\\",\\\"IDLE\\\"]\",\n \"notes\": \"## Scenario\\n\\nA firmware engineer or serial protocol analyst documents an 8N1 UART frame for a device datasheet, a hardware bring-up guide, or a lecture on serial communication. The example transmits the ASCII character 'A' (0x41 = 0100 0001 binary), sent LSB-first as required by the UART standard, at 115200 baud over RS-232 or a 3.3 V CMOS logic-level UART interface.\\n\\n## Annotation key\\n\\n- `TX` — transmit line; idle state is logic high (mark); each character = 1 start bit + 8 data bits + 1 stop bit\\n- `RX` — receive line; mirrors TX with the same bit encoding, shown here as a loopback for clarity\\n- `0` (START) — start bit: always logic low, signals the beginning of a frame; receiver synchronizes its sampling clock here\\n- `D0`–`D7` — data bits transmitted LSB-first; 'A' = 0x41 = 0b01000001: D0=1, D1=0, D2=0, D3=0, D4=0, D5=0, D6=1, D7=0\\n- `1` (STOP) — stop bit: logic high for at least one bit period, returns the line to idle (mark) state\\n- Each character cell = 1 bit period = 1/115200 s ≈ 8.68 µs\\n\\n## How to read\\n\\nThe line is idle-high before the frame. The transmitter pulls TX low for exactly one bit period as the start bit, allowing the receiver's UART to detect the falling edge and begin sampling. The eight data bits follow LSB-first: for 'A' (0x41), D0 is 1 (LSB), D1–D5 are 0, D6 is 1, D7 is 0 (MSB). The stop bit returns the line to logic high for one bit period, after which the line remains idle until the next frame. The RX line mirrors TX; in a real system the receiver samples each bit at the center of its bit period, approximately 4.34 µs after the falling edge of the start bit.\"\n },\n {\n \"slug\": \"timing-usb-packet\",\n \"diagram\": \"timing\",\n \"title\": \"USB 2.0 full-speed packet\",\n \"description\": \"USB 2.0 full-speed SYNC+PID+address+endpoint+CRC5 token packet timing on D+ and D− differential pair — for USB protocol analysis.\",\n \"standard\": \"USB 2.0 Specification\",\n \"tags\": [\n \"timing\",\n \"usb\",\n \"full-speed\",\n \"token-packet\",\n \"differential\",\n \"sync\",\n \"pid\",\n \"crc\",\n \"protocol\"\n ],\n \"complexity\": 3,\n \"featured\": false,\n \"dsl\": \"timing \\\"USB 2.0 Full-Speed SOF Token Packet\\\"\\nD_plus: 1010101011========x=====10\\nD_minus: 0101010100========x=====01\\nSE0: 0000000000========x=====11 data: [\\\"SYNC (KJKJKJKK)\\\",\\\"PID (SOF 0xA5)\\\",\\\"Frame Number (11b)\\\",\\\"CRC5 (5b)\\\",\\\"EOP\\\",\\\"IDLE\\\"]\",\n \"notes\": \"## Scenario\\n\\nA USB protocol engineer, USB IP core designer, or embedded systems developer analyzing a USB 2.0 full-speed bus capture needs to understand the bit-level encoding of a Start-of-Frame (SOF) token packet. This diagram shows the NRZI-encoded differential signals on D+ and D− for the mandatory SYNC field, PID byte, 11-bit frame number, 5-bit CRC, and End-of-Packet (EOP) single-ended zero condition.\\n\\n## Annotation key\\n\\n- `D_plus` / `D_minus` — USB differential pair; full-speed idle state (J) is D+=1, D−=0; K state is D+=0, D−=1\\n- SYNC field — 8-bit alternating KJ sequence ending in KK: `10101010 11` on D+; USB uses NRZI encoding so alternating bits signal the clock\\n- `PID` (0xA5) — SOF Packet ID byte `10100101`; transmitted in NRZI, stable during this phase\\n- `Frame Number` — 11-bit frame counter (0–2047), incremented each millisecond; stable bus state during each bit\\n- `CRC5` — 5-bit CRC over the frame number field, per USB 2.0 §8.3.5\\n- `SE0` — single-ended zero: both D+ and D− driven low for 2 bit periods as the End-of-Packet (EOP); followed by J (idle)\\n- `x` — transition / undefined bit state during SE0-to-idle edge\\n\\n## How to read\\n\\nThe packet begins with the host driving an 8-bit SYNC field (KJKJKJKK) that allows the receiver's PLL to lock to the 12 Mbit/s full-speed clock. The PID byte 0xA5 (SOF) follows, identifying the packet type. The 11-bit frame number and 5-bit CRC5 are transmitted LSB-first over 16 bit times. The EOP is signaled by driving both D+ and D− low (SE0) for exactly 2 bit periods, which cannot be confused with data since valid data always has differential drive. After EOP, the host releases both lines to idle (J state: D+=1, D−=0), completing the token packet in approximately 3 µs at full speed.\"\n },\n {\n \"slug\": \"venn-4-ellipse-gene-sets\",\n \"diagram\": \"venn\",\n \"title\": \"4-way gene-set overlap (Edwards layout)\",\n \"description\": \"Four-way gene-expression overlap across four RNA-seq conditions — stress, heat, drought, salinity — using an Edwards ellipse layout for bioinformatics.\",\n \"standard\": \"Edwards (2004) 4-ellipse layout\",\n \"tags\": [\n \"venn\",\n \"gene-sets\",\n \"rna-seq\",\n \"edwards\",\n \"bioinformatics\",\n \"4-way\",\n \"expression\"\n ],\n \"complexity\": 4,\n \"featured\": false,\n \"dsl\": \"venn \\\"DEG Overlap — Abiotic Stress Conditions\\\"\\nmode: edwards-4\\nset stress \\\"Oxidative stress\\\" [color: \\\"#E53935\\\"]\\nset heat \\\"Heat shock\\\" [color: \\\"#FB8C00\\\"]\\nset drought \\\"Drought\\\" [color: \\\"#43A047\\\"]\\nset salinity \\\"Salinity\\\" [color: \\\"#1E88E5\\\"]\\nstress only : 312\\nheat only : 287\\ndrought only : 445\\nsalinity only : 198\\nstress & heat : 89\\nstress & drought : 124\\nstress & salinity : 67\\nheat & drought : 78\\nheat & salinity : 45\\ndrought & salinity : 102\\nstress & heat & drought : 34\\nstress & heat & salinity : 22\\nstress & drought & salinity : 41\\nheat & drought & salinity : 28\\nstress & heat & drought & salinity : 15\",\n \"notes\": \"## Scenario\\n\\nA bioinformatician has run RNA-seq on Arabidopsis seedlings under four abiotic stress treatments and identified differentially expressed genes (DEGs) in each condition. The 4-way Edwards Venn reveals the core stress-response transcriptome — the 15 genes in the quadruple intersection are candidates for broad-spectrum stress-tolerance engineering — while the large drought-exclusive region (445) flags condition-specific regulators worth investigating in a targeted follow-up experiment.\\n\\n## Annotation key\\n\\n- `mode: edwards-4` — renders four ellipses at orientations that expose all 15 possible intersections\\n- `A & B : n` — gene count in the pairwise intersection of two conditions\\n- `A & B & C : n` — gene count shared across three conditions\\n- `stress & heat & drought & salinity : n` — core pan-stress regulome\\n\\n## How to read\\n\\nEach ellipse represents the DEG set from one treatment; overlapping regions are genes significantly regulated under multiple conditions. Start with the quadruple intersection (15 genes) — these are the most broadly responsive and highest-priority for functional validation. Pairwise intersections reveal mechanistic overlap: oxidative stress and drought share 124 genes, suggesting a shared ROS-signalling component. Large exclusive regions (drought: 445) indicate highly condition-specific transcriptional programs.\"\n },\n {\n \"slug\": \"venn-audience-overlap-marketing\",\n \"diagram\": \"venn\",\n \"title\": \"Paid audience overlap — Meta × Google × TikTok\",\n \"description\": \"Three ad-platform audience overlap for performance marketing — Meta, Google, and TikTok intersection counts to guide budget allocation.\",\n \"standard\": \"Venn (1880)\",\n \"tags\": [\n \"venn\",\n \"audience\",\n \"meta\",\n \"google\",\n \"tiktok\",\n \"marketing\",\n \"overlap\",\n \"paid\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"venn \\\"Q4 Holiday Campaign — Paid Audience Overlap\\\"\\nset meta \\\"Meta (FB + IG)\\\" [color: \\\"#1877F2\\\"]\\nset google \\\"Google Ads\\\" [color: \\\"#EA4335\\\"]\\nset tiktok \\\"TikTok\\\" [color: \\\"#010101\\\"]\\nmeta & google : 18400\\nmeta & tiktok : 24700\\ngoogle & tiktok : 9200\\nmeta & google & tiktok : 5100\\nmeta only : 61000\\ngoogle only : 38500\\ntiktok only : 42300\",\n \"notes\": \"## Scenario\\n\\nA performance marketing manager is finalising the Q4 holiday campaign budget across three platforms. The Venn reveals that a meaningful audience of 5,100 users is targetable on all three channels simultaneously — this cohort will see the brand multiple times, so frequency capping is critical. The 61k Meta-exclusive pool is the largest single-platform opportunity, while TikTok's 42k exclusive reach justifies keeping it in the mix even at a higher CPM.\\n\\n## Annotation key\\n\\n- `set ID \\\"Label\\\"` — one ad platform per circle\\n- `A & B : n` — users reachable on both platforms (multi-touch risk)\\n- `A only : n` — users reachable exclusively on one platform\\n\\n## How to read\\n\\nEach circle represents the targetable audience on one platform. Intersection counts show users reachable across multiple channels — useful for setting frequency caps and coordinating creative sequencing. The triple intersection (5,100) is the most saturated segment and should receive unified messaging. Exclusive regions show where each platform provides unique incremental reach that the others cannot access.\"\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-euler-taxonomy\",\n \"diagram\": \"venn\",\n \"title\": \"Euler diagram — animal kingdom containment\",\n \"description\": \"Euler containment diagram showing Animals ⊃ Vertebrates ⊃ Mammals ⊃ Primates — a nested subset visualization for biology class.\",\n \"standard\": \"Euler (1768)\",\n \"tags\": [\n \"euler\",\n \"venn\",\n \"taxonomy\",\n \"mammals\",\n \"vertebrates\",\n \"biology\",\n \"containment\"\n ],\n \"complexity\": 1,\n \"featured\": false,\n \"dsl\": \"venn \\\"Animal Kingdom — Nested Containment\\\"\\nmode: euler\\nset animals \\\"Animals\\\" [color: \\\"#43A047\\\"]\\nset vertebrates \\\"Vertebrates\\\" [subset-of: animals, color: \\\"#1E88E5\\\"]\\nset mammals \\\"Mammals\\\" [subset-of: vertebrates, color: \\\"#FB8C00\\\"]\\nset primates \\\"Primates\\\" [subset-of: mammals, color: \\\"#E53935\\\"]\",\n \"notes\": \"## Scenario\\n\\nA biology teacher uses this Euler diagram to introduce taxonomic hierarchy on the first day of a classification unit. Unlike a Venn diagram — which implies partial overlap between circles — an Euler diagram shows true containment: every primate is a mammal, every mammal is a vertebrate, and every vertebrate is an animal. Students can immediately see that the sets are nested, not intersecting.\\n\\n## Annotation key\\n\\n- `mode: euler` — enables containment (subset) layout instead of partial overlap\\n- `subset-of: ID` — declares that this set is fully enclosed within another\\n- Nested rings from outermost to innermost: Animals → Vertebrates → Mammals → Primates\\n\\n## How to read\\n\\nRead from the outside in. The outermost ring (Animals) contains all others. Each inner ring is a strict subset of the ring enclosing it — no element can be in Primates without also being in Mammals, Vertebrates, and Animals. The space between Vertebrates and Mammals represents vertebrates that are not mammals (fish, amphibians, reptiles, birds). The space between Mammals and Primates represents mammals that are not primates (dogs, cats, whales, bats).\"\n },\n {\n \"slug\": \"venn-feature-comparison-tools\",\n \"diagram\": \"venn\",\n \"title\": \"Feature comparison — Notion vs. Obsidian vs. Roam\",\n \"description\": \"Three-way Venn of knowledge-management features across Notion, Obsidian, and Roam Research — for product teams benchmarking a new tool.\",\n \"standard\": \"Venn (1880)\",\n \"tags\": [\n \"venn\",\n \"feature-comparison\",\n \"notion\",\n \"obsidian\",\n \"roam\",\n \"product\",\n \"competitive\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"venn \\\"Knowledge Management Tools — Feature Overlap\\\"\\nset notion \\\"Notion\\\" [color: \\\"#000000\\\"]\\nset obsidian \\\"Obsidian\\\" [color: \\\"#7C3AED\\\"]\\nset roam \\\"Roam Research\\\" [color: \\\"#3B82F6\\\"]\\nnotion & obsidian : 3\\nnotion & roam : 2\\nobsidian & roam : 2\\nnotion & obsidian & roam : 3\\nnotion only : 8\\nobsidian only : 6\\nroam only : 4\",\n \"notes\": \"## Scenario\\n\\nA product manager is building a competitive teardown before a roadmap review. Rather than a spreadsheet of checkboxes, the Venn communicates at a glance which features are table stakes (the triple intersection), which are differentiators (exclusive regions), and which signal partnership opportunities or feature gaps. The counts here represent clusters of related capabilities, not raw feature counts.\\n\\n## Annotation key\\n\\n- `set ID \\\"Label\\\"` — one tool per circle\\n- `A & B : n` — number of feature clusters shared by both tools\\n- `A only : n` — feature clusters unique to one tool\\n\\n## How to read\\n\\nEach circle represents one tool's total feature set grouped into capability clusters. The triple intersection (3 clusters: block-based editing, bidirectional links, tagging) represents the baseline every modern knowledge tool must ship. Notion's exclusive region (8 clusters) reflects its broader collaboration and database surface area. Obsidian's exclusive region (6) reflects its plugin ecosystem and local-first architecture. Roam's exclusive region (4) reflects its outliner-first and daily-notes conventions.\"\n },\n {\n \"slug\": \"venn-prisma-screening\",\n \"diagram\": \"venn\",\n \"title\": \"PRISMA systematic review — database screening\",\n \"description\": \"Three-database PRISMA deduplication Venn showing PubMed, Embase, and Cochrane overlap counts for a systematic literature review.\",\n \"standard\": \"PRISMA 2020\",\n \"tags\": [\n \"venn\",\n \"prisma\",\n \"systematic-review\",\n \"literature\",\n \"pubmed\",\n \"embase\"\n ],\n \"complexity\": 2,\n \"featured\": false,\n \"dsl\": \"venn \\\"Database Screening — PRISMA Deduplication\\\"\\nset pubmed \\\"PubMed\\\" [color: \\\"#1E88E5\\\"]\\nset embase \\\"Embase\\\" [color: \\\"#E53935\\\"]\\nset cochrane \\\"Cochrane\\\" [color: \\\"#43A047\\\"]\\npubmed & embase : 1240\\npubmed & cochrane : 340\\nembase & cochrane : 280\\npubmed & embase & cochrane : 180\\npubmed only : 4200\\nembase only : 2800\\ncochrane only : 620\",\n \"notes\": \"## Scenario\\n\\nA systematic reviewer searches PubMed, Embase, and Cochrane before title/abstract screening. Before any reading begins, duplicates must be removed — the same paper indexed in multiple databases would inflate the apparent evidence base. This Venn shows where the three databases overlap so the reviewer can report the PRISMA 2020 deduplication step with exact counts and transparently justify why 2,040 records were removed before screening began.\\n\\n## Annotation key\\n\\n- `set ID \\\"Label\\\"` — one database per circle\\n- `A & B : n` — records indexed in both databases (potential duplicates)\\n- `A only : n` — records unique to a single database\\n\\n## How to read\\n\\nEach circle represents one database's raw retrieval. Overlapping regions are records that appear in more than one source and are the primary deduplication targets. The triple intersection (180) means those papers were found in all three databases simultaneously. After removing all intersections as duplicates, the unique record count is 4 200 + 2 800 + 620 = 7 620 — the number that proceeds to title/abstract screening and is recorded in the PRISMA flow diagram.\"\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 `#`. 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:** `#` 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 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 `#`. 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- **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 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\\\" ( WS quoted-string )? NEWLINE\\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 `#`. 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- **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\\\" ( WS quoted-string )? NEWLINE\\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\\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---\\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` | `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 | 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\\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\\\"\\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.\\n\\n```\\ntiming\\nCLK: pppppppp\\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: wavestring` — name, colon, then a string of wave characters (no spaces inside the wave).\\n3. Add `data: [\\\"val1\\\", \\\"val2\\\"]` after the wave string to label bus segments.\\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\\n\\nThe smallest useful positional circuit: a voltage source, a resistor, and a ground.\\n\\n```\\ncircuit \\\"Voltage divider\\\"\\nV1: voltage_source down value=\\\"5V\\\"\\nwire right\\nR1: resistor right value=\\\"10k\\\"\\nwire right\\nground\\n```\\n\\nFour rules cover 80% of positional-mode usage:\\n\\n1. Start with the keyword `circuit`, optionally followed by a quoted title.\\n2. Each component is `id: type direction` — or just `type direction` for anonymous components.\\n3. Each component's output end becomes the starting point for the next component (the \\\"cursor\\\").\\n4. `at: id.end` (or `at: id.start`) jumps the cursor to any named anchor — use this to branch.\\n\\n> Comments must start with `#` on their own line.\\n\\n---\\n\\n## 2. Components\\n\\n### 2.1 Positional mode syntax\\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.2 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.3 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.4 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.5 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.6 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.7 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.8 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.9 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.\\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 must start with `#` 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\\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 colon: `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:** `#` at the start of a line (after leading whitespace). Inline `# …` after an element line is also stripped.\\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) | `LadderParseError: element outside of rung` | Rung header must end with `:` — `rung 1:` |\\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\\\"\\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 must start with `#` 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\\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| `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\\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 must start with `#` 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---\\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:** `#` at the start of a line (after optional leading whitespace). The `#` character inside a double-quoted string is not treated as a comment.\\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**The `#` character** starts 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\\n---\\n\\n## 8. Grammar (EBNF)\\n\\n```text\\ndocument = header (blank | comment | effect | category | config | cause | sub-cause)*\\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\\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```\\ndecisiontree \\\"Laptop troubleshoot\\\"\\n\\nquestion \\\"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: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```\\ndecisiontree \\\"Triage — chest pain onset\\\"\\n\\nq \\\"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```\\ndecisiontree \\\"Pain level triage\\\"\\n\\nquestion \\\"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```\\ndecisiontree:decision \\\"Cloud vendor selection\\\"\\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```\\n\\n---\\n\\n## 5. 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```\\ndecisiontree:ml \\\"Iris classification (CART)\\\"\\ndirection: top-down\\nimpurity: gini\\n\\nsplit \\\"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## 6. 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## 7. 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## 8. 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## 9. 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## 10. 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`.\\n\\n```\\nclassDef danger fill:#f9c,stroke:#c00\\nclassDef safe fill:#cfc,stroke:#090\\nclass errorNode danger\\nclass successNode safe\\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\\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. 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## 9. 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## 10. 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## 11. Reserved words & escaping\\n\\n**Reserved at line start:** `matrix` (header), `x-axis:`, `y-axis:`, `quadrant`, `config:`, `title:`, `rows:`, `cols:`, `grid:`, `axis:`, `margins:`, `cell`.\\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## 12. 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## 13. 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?\\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 | comment | blank\\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\\n```\\n%% style: map\\n%% style: logic-right\\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---\\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` | `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` or `logic-right` |\\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 \"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 \"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 \"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 \"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 * 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","/**\n * Syntax lookup — LLM-facing per-diagram grammar reference.\n *\n * v1: returns the stripped-MDX content from `website/content/docs/*.mdx`\n * (JSX components replaced with fenced DSL code blocks).\n *\n * Later: may be replaced with curated compact summaries per diagram if\n * the stripped docs prove too long for good LLM performance.\n */\nimport { SYNTAX, type GeneratedSyntax } from \"./_generated\";\n\nexport type SyntaxDoc = GeneratedSyntax & { key: string };\n\nexport function getSyntaxForType(syntaxKey: string): SyntaxDoc | undefined {\n const s = SYNTAX[syntaxKey];\n if (!s) return undefined;\n return { key: syntaxKey, ...s };\n}\n\nexport function listSyntaxKeys(): string[] {\n return Object.keys(SYNTAX);\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 { parse, render, type SchematexConfig } from \"../core/api\";\nimport {\n DIAGRAM_REGISTRY,\n getDiagramMeta,\n type DiagramMeta,\n} from \"./registry\";\nimport { extractError, type SchematexValidationError } from \"./errors\";\nimport { getExamplesForType, type Example, type GetExamplesOptions } from \"./examples\";\nimport { getSyntaxForType, type SyntaxDoc } 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 function getSyntax(type: string): 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);\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 | { ok: true; type: string | null }\n | { ok: false; type: string | null; errors: SchematexValidationError[] };\n\nexport function validateDsl(type: string | undefined, dsl: string): ValidateDslResult {\n const config: SchematexConfig | undefined = type\n ? { type: type as SchematexConfig[\"type\"] }\n : undefined;\n try {\n parse(dsl, config);\n return { ok: true, type: type ?? resolveTypeFromText(dsl) };\n } catch (err) {\n return {\n ok: false,\n type: type ?? resolveTypeFromText(dsl),\n errors: [extractError(err)],\n };\n }\n}\n\n// ─── renderDsl ──────────────────────────────────────────────────\n\nexport type RenderDslResult =\n | { ok: true; type: string | null; svg: string }\n | { ok: false; type: string | null; errors: SchematexValidationError[] };\n\nexport function renderDsl(\n type: string | undefined,\n dsl: string,\n options: Omit<SchematexConfig, \"type\"> = {}\n): RenderDslResult {\n const config: SchematexConfig = {\n ...options,\n ...(type ? { type: type as SchematexConfig[\"type\"] } : {}),\n };\n try {\n const svg = render(dsl, config);\n return { ok: true, type: type ?? resolveTypeFromText(dsl), svg };\n } catch (err) {\n return {\n ok: false,\n type: type ?? resolveTypeFromText(dsl),\n errors: [extractError(err)],\n };\n }\n}\n\n// ─── helpers ────────────────────────────────────────────────────\n\nfunction resolveTypeFromText(text: string): string | null {\n const first = text.trim().split(/\\s+|\\n/)[0]?.toLowerCase() ?? \"\";\n const meta = DIAGRAM_REGISTRY.find((d) => d.type === first);\n return meta?.type ?? null;\n}\n"]}