schematex 0.3.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/dist/ai/ai-sdk.cjs +25 -25
  2. package/dist/ai/ai-sdk.d.cts +1 -1
  3. package/dist/ai/ai-sdk.d.ts +1 -1
  4. package/dist/ai/ai-sdk.js +20 -20
  5. package/dist/ai/index.cjs +28 -28
  6. package/dist/ai/index.d.cts +1 -1
  7. package/dist/ai/index.d.ts +1 -1
  8. package/dist/ai/index.js +20 -20
  9. package/dist/browser.cjs +22 -22
  10. package/dist/browser.js +20 -20
  11. package/dist/{chunk-HDKDQAEQ.cjs → chunk-3WNW5Y7P.cjs} +54 -2
  12. package/dist/chunk-3WNW5Y7P.cjs.map +1 -0
  13. package/dist/{chunk-B6INLQBU.cjs → chunk-55UEHL57.cjs} +46 -46
  14. package/dist/{chunk-B6INLQBU.cjs.map → chunk-55UEHL57.cjs.map} +1 -1
  15. package/dist/{chunk-JDTB7IKL.js → chunk-5U2W3HQA.js} +3 -3
  16. package/dist/{chunk-JDTB7IKL.js.map → chunk-5U2W3HQA.js.map} +1 -1
  17. package/dist/{chunk-ULYRO2KY.cjs → chunk-5UCXMYE7.cjs} +44 -44
  18. package/dist/{chunk-ULYRO2KY.cjs.map → chunk-5UCXMYE7.cjs.map} +1 -1
  19. package/dist/{chunk-UGCUNADI.js → chunk-66XQBGX7.js} +35 -16
  20. package/dist/chunk-66XQBGX7.js.map +1 -0
  21. package/dist/{chunk-45KP67RR.js → chunk-6TIN33CA.js} +5 -5
  22. package/dist/chunk-6TIN33CA.js.map +1 -0
  23. package/dist/{chunk-NNU4RGT3.js → chunk-6YUP3QMA.js} +39 -27
  24. package/dist/chunk-6YUP3QMA.js.map +1 -0
  25. package/dist/{chunk-COLTVQWR.cjs → chunk-7EWFVNYD.cjs} +25 -25
  26. package/dist/{chunk-COLTVQWR.cjs.map → chunk-7EWFVNYD.cjs.map} +1 -1
  27. package/dist/{chunk-RP5UATRA.js → chunk-AC3XH3LB.js} +4 -4
  28. package/dist/{chunk-RP5UATRA.js.map → chunk-AC3XH3LB.js.map} +1 -1
  29. package/dist/{chunk-XTATRNUN.cjs → chunk-APV4AWQ5.cjs} +442 -430
  30. package/dist/chunk-APV4AWQ5.cjs.map +1 -0
  31. package/dist/{chunk-NZH4GWE6.cjs → chunk-AVIKQZSX.cjs} +37 -37
  32. package/dist/{chunk-NZH4GWE6.cjs.map → chunk-AVIKQZSX.cjs.map} +1 -1
  33. package/dist/{chunk-X7RPFTTR.cjs → chunk-CWZKP3CJ.cjs} +26 -26
  34. package/dist/{chunk-X7RPFTTR.cjs.map → chunk-CWZKP3CJ.cjs.map} +1 -1
  35. package/dist/{chunk-TYCHEOQX.js → chunk-FIVUMDLF.js} +49 -24
  36. package/dist/chunk-FIVUMDLF.js.map +1 -0
  37. package/dist/{chunk-DNZFOCV7.js → chunk-FO7BLCEW.js} +3 -3
  38. package/dist/{chunk-DNZFOCV7.js.map → chunk-FO7BLCEW.js.map} +1 -1
  39. package/dist/{chunk-OC22GGQN.js → chunk-GLFBHQSQ.js} +54 -4
  40. package/dist/chunk-GLFBHQSQ.js.map +1 -0
  41. package/dist/{chunk-XZNPAD6E.js → chunk-GVCPFBAV.js} +59 -8
  42. package/dist/chunk-GVCPFBAV.js.map +1 -0
  43. package/dist/{chunk-B37IKTI7.cjs → chunk-HOI6QKC6.cjs} +97 -47
  44. package/dist/chunk-HOI6QKC6.cjs.map +1 -0
  45. package/dist/{chunk-A5D2IMOX.cjs → chunk-IAEABLIV.cjs} +47 -47
  46. package/dist/{chunk-A5D2IMOX.cjs.map → chunk-IAEABLIV.cjs.map} +1 -1
  47. package/dist/{chunk-5YYAYW67.js → chunk-IQRRZPVZ.js} +3 -3
  48. package/dist/{chunk-5YYAYW67.js.map → chunk-IQRRZPVZ.js.map} +1 -1
  49. package/dist/{chunk-VLMK7MQK.js → chunk-MNOO7STY.js} +25 -6
  50. package/dist/chunk-MNOO7STY.js.map +1 -0
  51. package/dist/{chunk-ZNOD4VZT.cjs → chunk-N56YC75X.cjs} +46 -46
  52. package/dist/{chunk-ZNOD4VZT.cjs.map → chunk-N56YC75X.cjs.map} +1 -1
  53. package/dist/{chunk-YQANC7HQ.js → chunk-PAG3BNIV.js} +3 -3
  54. package/dist/{chunk-YQANC7HQ.js.map → chunk-PAG3BNIV.js.map} +1 -1
  55. package/dist/{chunk-QSQX77S2.cjs → chunk-PG6TDGKI.cjs} +21 -21
  56. package/dist/{chunk-QSQX77S2.cjs.map → chunk-PG6TDGKI.cjs.map} +1 -1
  57. package/dist/{chunk-WYFXOXVK.cjs → chunk-Q5OFA4I2.cjs} +35 -35
  58. package/dist/{chunk-WYFXOXVK.cjs.map → chunk-Q5OFA4I2.cjs.map} +1 -1
  59. package/dist/{chunk-MJGDP3CS.cjs → chunk-QOLBWCF5.cjs} +488 -109
  60. package/dist/chunk-QOLBWCF5.cjs.map +1 -0
  61. package/dist/{chunk-MCFQAUQV.cjs → chunk-QXL7AY2H.cjs} +58 -39
  62. package/dist/chunk-QXL7AY2H.cjs.map +1 -0
  63. package/dist/chunk-SYYBKDL7.js +122 -0
  64. package/dist/chunk-SYYBKDL7.js.map +1 -0
  65. package/dist/{chunk-H2OEUBPO.js → chunk-TQU44E46.js} +441 -62
  66. package/dist/chunk-TQU44E46.js.map +1 -0
  67. package/dist/{chunk-FCGHV6ZK.js → chunk-U3KRKXF7.js} +4 -4
  68. package/dist/{chunk-FCGHV6ZK.js.map → chunk-U3KRKXF7.js.map} +1 -1
  69. package/dist/{chunk-3YZ6FPQW.cjs → chunk-UDGU73RL.cjs} +131 -131
  70. package/dist/{chunk-3YZ6FPQW.cjs.map → chunk-UDGU73RL.cjs.map} +1 -1
  71. package/dist/{chunk-U6L3FAML.js → chunk-UDJ2KN2A.js} +3 -3
  72. package/dist/{chunk-U6L3FAML.js.map → chunk-UDJ2KN2A.js.map} +1 -1
  73. package/dist/{chunk-FE6GAUNW.js → chunk-UT4TIDAA.js} +5 -5
  74. package/dist/{chunk-FE6GAUNW.js.map → chunk-UT4TIDAA.js.map} +1 -1
  75. package/dist/{chunk-SQKLKBBK.cjs → chunk-UWRTV6IV.cjs} +27 -8
  76. package/dist/chunk-UWRTV6IV.cjs.map +1 -0
  77. package/dist/{chunk-NB56L5QK.js → chunk-WTF6JXHN.js} +4 -4
  78. package/dist/{chunk-NB56L5QK.js.map → chunk-WTF6JXHN.js.map} +1 -1
  79. package/dist/{chunk-ZNDIGQJD.js → chunk-X5QJO4ZD.js} +3 -3
  80. package/dist/{chunk-ZNDIGQJD.js.map → chunk-X5QJO4ZD.js.map} +1 -1
  81. package/dist/{chunk-M5B2UUNW.js → chunk-XV2DTN6G.js} +4 -4
  82. package/dist/{chunk-M5B2UUNW.js.map → chunk-XV2DTN6G.js.map} +1 -1
  83. package/dist/{chunk-K2SOC3XF.cjs → chunk-YUPG2M3I.cjs} +71 -20
  84. package/dist/chunk-YUPG2M3I.cjs.map +1 -0
  85. package/dist/{chunk-2JDVJRR3.cjs → chunk-ZCW7YH3C.cjs} +28 -28
  86. package/dist/chunk-ZCW7YH3C.cjs.map +1 -0
  87. package/dist/{chunk-3FKS4KQK.cjs → chunk-ZFNZ2FYI.cjs} +88 -63
  88. package/dist/chunk-ZFNZ2FYI.cjs.map +1 -0
  89. package/dist/{chunk-5AEN2PLB.cjs → chunk-ZZJDGGC3.cjs} +33 -33
  90. package/dist/{chunk-5AEN2PLB.cjs.map → chunk-ZZJDGGC3.cjs.map} +1 -1
  91. package/dist/diagrams/blockdiagram/index.cjs +6 -6
  92. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  93. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  94. package/dist/diagrams/blockdiagram/index.js +2 -2
  95. package/dist/diagrams/circuit/index.cjs +8 -8
  96. package/dist/diagrams/circuit/index.d.cts +1 -1
  97. package/dist/diagrams/circuit/index.d.ts +1 -1
  98. package/dist/diagrams/circuit/index.js +2 -2
  99. package/dist/diagrams/ecomap/index.cjs +8 -8
  100. package/dist/diagrams/ecomap/index.d.cts +1 -1
  101. package/dist/diagrams/ecomap/index.d.ts +1 -1
  102. package/dist/diagrams/ecomap/index.js +3 -3
  103. package/dist/diagrams/entity/index.cjs +6 -6
  104. package/dist/diagrams/entity/index.d.cts +1 -1
  105. package/dist/diagrams/entity/index.d.ts +1 -1
  106. package/dist/diagrams/entity/index.js +2 -2
  107. package/dist/diagrams/fishbone/index.cjs +8 -8
  108. package/dist/diagrams/fishbone/index.d.cts +1 -1
  109. package/dist/diagrams/fishbone/index.d.ts +1 -1
  110. package/dist/diagrams/fishbone/index.js +2 -2
  111. package/dist/diagrams/flowchart/index.cjs +8 -8
  112. package/dist/diagrams/flowchart/index.d.cts +2 -2
  113. package/dist/diagrams/flowchart/index.d.ts +2 -2
  114. package/dist/diagrams/flowchart/index.js +2 -2
  115. package/dist/diagrams/genogram/index.cjs +10 -10
  116. package/dist/diagrams/genogram/index.d.cts +1 -1
  117. package/dist/diagrams/genogram/index.d.ts +1 -1
  118. package/dist/diagrams/genogram/index.js +3 -3
  119. package/dist/diagrams/ladder/index.cjs +6 -6
  120. package/dist/diagrams/ladder/index.d.cts +1 -1
  121. package/dist/diagrams/ladder/index.d.ts +1 -1
  122. package/dist/diagrams/ladder/index.js +2 -2
  123. package/dist/diagrams/logic/index.cjs +6 -6
  124. package/dist/diagrams/logic/index.d.cts +1 -1
  125. package/dist/diagrams/logic/index.d.ts +1 -1
  126. package/dist/diagrams/logic/index.js +2 -2
  127. package/dist/diagrams/orgchart/index.cjs +7 -7
  128. package/dist/diagrams/orgchart/index.d.cts +1 -1
  129. package/dist/diagrams/orgchart/index.d.ts +1 -1
  130. package/dist/diagrams/orgchart/index.js +2 -2
  131. package/dist/diagrams/pedigree/index.cjs +8 -8
  132. package/dist/diagrams/pedigree/index.d.cts +1 -1
  133. package/dist/diagrams/pedigree/index.d.ts +1 -1
  134. package/dist/diagrams/pedigree/index.js +3 -3
  135. package/dist/diagrams/phylo/index.cjs +7 -7
  136. package/dist/diagrams/phylo/index.d.cts +1 -1
  137. package/dist/diagrams/phylo/index.d.ts +1 -1
  138. package/dist/diagrams/phylo/index.js +2 -2
  139. package/dist/diagrams/sld/index.cjs +6 -6
  140. package/dist/diagrams/sld/index.d.cts +1 -1
  141. package/dist/diagrams/sld/index.d.ts +1 -1
  142. package/dist/diagrams/sld/index.js +2 -2
  143. package/dist/diagrams/sociogram/index.cjs +7 -7
  144. package/dist/diagrams/sociogram/index.d.cts +1 -1
  145. package/dist/diagrams/sociogram/index.d.ts +1 -1
  146. package/dist/diagrams/sociogram/index.js +3 -3
  147. package/dist/diagrams/timing/index.cjs +5 -5
  148. package/dist/diagrams/timing/index.d.cts +1 -1
  149. package/dist/diagrams/timing/index.d.ts +1 -1
  150. package/dist/diagrams/timing/index.js +2 -2
  151. package/dist/diagrams/venn/index.cjs +9 -9
  152. package/dist/diagrams/venn/index.d.cts +1 -1
  153. package/dist/diagrams/venn/index.d.ts +1 -1
  154. package/dist/diagrams/venn/index.js +2 -2
  155. package/dist/{index-CUwp4GXI.d.ts → index-D3u6vcA4.d.ts} +1 -1
  156. package/dist/{index-ivhNGsyU.d.cts → index-bdfj6FpQ.d.cts} +1 -1
  157. package/dist/index.cjs +41 -41
  158. package/dist/index.d.cts +2 -2
  159. package/dist/index.d.ts +2 -2
  160. package/dist/index.js +19 -19
  161. package/dist/react.cjs +20 -20
  162. package/dist/react.cjs.map +1 -1
  163. package/dist/react.js +19 -19
  164. package/dist/react.js.map +1 -1
  165. package/dist/{types-Bl-Pn7Wj.d.cts → types-DnU2UlWz.d.cts} +26 -3
  166. package/dist/{types-Bl-Pn7Wj.d.ts → types-DnU2UlWz.d.ts} +26 -3
  167. package/package.json +1 -1
  168. package/dist/chunk-2JDVJRR3.cjs.map +0 -1
  169. package/dist/chunk-3FKS4KQK.cjs.map +0 -1
  170. package/dist/chunk-45KP67RR.js.map +0 -1
  171. package/dist/chunk-B37IKTI7.cjs.map +0 -1
  172. package/dist/chunk-H2OEUBPO.js.map +0 -1
  173. package/dist/chunk-HDKDQAEQ.cjs.map +0 -1
  174. package/dist/chunk-K2SOC3XF.cjs.map +0 -1
  175. package/dist/chunk-KLJEK547.js +0 -71
  176. package/dist/chunk-KLJEK547.js.map +0 -1
  177. package/dist/chunk-MCFQAUQV.cjs.map +0 -1
  178. package/dist/chunk-MJGDP3CS.cjs.map +0 -1
  179. package/dist/chunk-NNU4RGT3.js.map +0 -1
  180. package/dist/chunk-OC22GGQN.js.map +0 -1
  181. package/dist/chunk-SQKLKBBK.cjs.map +0 -1
  182. package/dist/chunk-TYCHEOQX.js.map +0 -1
  183. package/dist/chunk-UGCUNADI.js.map +0 -1
  184. package/dist/chunk-VLMK7MQK.js.map +0 -1
  185. package/dist/chunk-XTATRNUN.cjs.map +0 -1
  186. package/dist/chunk-XZNPAD6E.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkXTATRNUN_cjs = require('./chunk-XTATRNUN.cjs');
3
+ var chunkAPV4AWQ5_cjs = require('./chunk-APV4AWQ5.cjs');
4
4
 
5
5
  // src/ai/registry.ts
6
6
  var DIAGRAM_REGISTRY = [
@@ -483,6 +483,25 @@ var EXAMPLES = [
483
483
  "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]',
484
484
  "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)` \u2014 medical conditions filling the symbol; color is optional hex\n- `deceased` with birth and death years \u2014 marks individuals with a slash and date range\n- `index` \u2014 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 \u2014 the inheritance pattern spanning three generations justifies BRCA genetic testing."
485
485
  },
486
+ {
487
+ "slug": "genogram-foster-care",
488
+ "diagram": "genogram",
489
+ "title": "Foster care / child protection",
490
+ "description": "Foster-care genogram for a real LATAM child-protection case \u2014 biological parents (cohabitation ended), abuse, current foster placement (dotted secondary link), unknown-count siblings, and a maternal uncle as known-relative-with-unknown-ancestry.",
491
+ "standard": "McGoldrick 2020 + Bennett 2022 (adopted-out / dual-parent convention)",
492
+ "tags": [
493
+ "foster-care",
494
+ "dual-parent",
495
+ "abuse",
496
+ "sibling-of",
497
+ "unknown-siblings",
498
+ "latam"
499
+ ],
500
+ "complexity": 3,
501
+ "featured": true,
502
+ "dsl": 'genogram "Familia Isa\xEDas"\n victor [male, label: "V\xEDctor Seguel"]\n monica [female, label: "M\xF3nica Barrientos"]\n victor ~/~ monica\n ?\n isaias [male, 2020, age: 6, label: "Isa\xEDas", index]\n pablo_sr [male, label: "Don Pablo"]\n priscila [female, label: "Do\xF1a 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\xEDo materno", sibling-of: monica]\n victor -physical-abuse-> isaias\n monica -physical-abuse-> isaias\n tio_materno -nevermet- isaias',
503
+ "notes": '## Scenario\n\nA foster-care social worker in Chile is preparing the case file for Isa\xEDas, a 6-year-old boy removed from his biological parents (V\xEDctor and M\xF3nica) due to physical abuse from both. He currently lives with foster parents Don Pablo and Do\xF1a Priscila, who have two biological children of their own. The case file mentions Isa\xEDas 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\xEDas is the **biological son** of V\xEDctor and M\xF3nica \u2014 solid parent-child line down from the bio couple.\n2. He **currently lives** with Don Pablo and Do\xF1a Priscila as a foster child \u2014 *secondary dotted link* from the foster couple, drawn without pulling Isa\xEDas away from his bio-parent position.\n3. He was **removed due to physical abuse** from both bio parents \u2014 directional red zigzag arrows.\n4. The **maternal uncle** is M\xF3nica\'s brother (`sibling-of: monica`) with **no current relationship** to Isa\xEDas \u2014 dashed bracket between M\xF3nica and T\xEDo + `nevermet` line.\n5. Isa\xEDas has **unknown-count siblings** still with the bio parents \u2014 single `?` diamond placeholder.\n6. **Isa\xEDas is the index person** \u2014 concentric outer border highlight.\n\n## Annotation key\n\n- `~/~` \u2014 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 \u2192 engine treats the second declaration as a **secondary "current caregiver" link** (dotted), preserving all attributes from the first declaration.\n- `?` on a child line \u2192 a single diamond with `?` glyph meaning "\u22651 siblings, count and identities unknown" (standard pedigree convention).\n- `[sibling-of: monica]` \u2192 places T\xEDo materno on M\xF3nica\'s generation with a dashed bracket between them, **without** synthesizing phantom maternal grandparents.\n- `-physical-abuse->` \u2192 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\xEDas as a third biological child of Don Pablo + Do\xF1a Priscila \u2014 or dropped his sex and label when the `[foster]` redeclaration overwrote the original \u2014 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.'
504
+ },
486
505
  {
487
506
  "slug": "genogram-medical-history",
488
507
  "diagram": "genogram",
@@ -940,7 +959,7 @@ var EXAMPLES = [
940
959
  var SYNTAX = {
941
960
  "genogram": {
942
961
  "title": "Genogram",
943
- "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** \u2014 `--` (marriage) here; see \xA74.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 \u2014 see \xA78.\n\n---\n\n## 2. Individuals\n\nAn individual line is `id [attr1, attr2, \u2026]`. 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:"\u2026"`).\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| `age:N` | e.g. `age:42` | Age shown inside shape |\n| `death:YYYY` | e.g. `death:2020` | Explicit death year |\n| `label:"\u2026"` | e.g. `label:"Dr. Smith"` | Display label override |\n| `conditions:\u2026` | see \xA75 | 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| \u2610 Square | `male` | Male |\n| \u25CB Circle | `female` | Female |\n| \u25C7 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 \u2014 so `-x-` beats `--`.\n\n| Operator | Type | Example | Meaning |\n|---|---|---|---|\n| `-x-` | divorced | `a -x- b` | Divorce |\n| `-/-` | separated | `a -/- b` | Separation |\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 |\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| `twin-identical` | Grouped with other `twin-identical` children of the same couple |\n| `twin-fraternal` | Grouped with other `twin-fraternal` children |\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)]\u2026`\n\n```\nfather [male, 1945, conditions: heart(full, #E53935)]\nmother [female, 1948, conditions: diabetes(half-left) + anxiety(half-right, #26A69A)]\n```\n\n- **`name`** \u2014 any identifier you choose (displayed in legend/tooltip).\n- **`fill`** \u2014 required, controls which region of the shape is colored. See table below.\n- **`color`** \u2014 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"` \u2014 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 \u2014 `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 \u2014 fine\n alice [female, 1980] # \u2190 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 \u2014 avoid using these sequences in IDs:\n`--`, `~`, `==`, `-x-`, `-/-`, `-o-`, and any `-<type>-` / `-<type>->` matching an emotional-relationship type.\n\n**Strings with spaces** must be double-quoted: titles, labels, `label:"\u2026"`. 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 \xA713 Roadmap) |\n| `alice [female, transgender]` | `Unknown property \'transgender\'` | Not yet parseable (\xA713 Roadmap) |\n| `dad -- mom` \u2190 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 (\xA713 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\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\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" | "twin-identical" | "twin-fraternal"\n | "index"\n | digit digit digit digit // year\n | "age" ":" digits\n | "death" ":" digit digit digit digit\n | "label" ":" quoted-string\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 \u2014 please open an issue.\n\n---'
962
+ "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** \u2014 `--` (marriage) here; see \xA74.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 \u2014 see \xA78.\n\n---\n\n## 2. Individuals\n\nAn individual line is `id [attr1, attr2, \u2026]`. 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:"\u2026"`).\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 `?` \u2014 placeholder for \u22651 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:"\u2026"` | 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 \u2014 for known relatives with unknown ancestry. |\n| `conditions:\u2026` | see \xA75 | 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| \u2610 Square | `male` | Male |\n| \u25CB Circle | `female` | Female |\n| \u25C7 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 \u2014 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 \u2014 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` \u2014 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 \u2014 "\u22651 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 \u2014 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 \u2014 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 \u2014 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\xEDo 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)]\u2026`\n\n```\nfather [male, 1945, conditions: heart(full, #E53935)]\nmother [female, 1948, conditions: diabetes(half-left) + anxiety(half-right, #26A69A)]\n```\n\n- **`name`** \u2014 any identifier you choose (displayed in legend/tooltip).\n- **`fill`** \u2014 required, controls which region of the shape is colored. See table below.\n- **`color`** \u2014 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"` \u2014 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 \u2014 `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 \u2014 fine\n alice [female, 1980] # \u2190 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 \u2014 avoid using these sequences in IDs:\n`--`, `~`, `~/~`, `==`, `-x-`, `-/-`, `-//`, `-o-`, and any `-<type>-` / `-<type>->` matching an emotional-relationship type.\n\n**Reserved id `?`** \u2014 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:"\u2026"`. 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 \xA713 Roadmap) |\n| `alice [female, transgender]` | `Unknown property \'transgender\'` | Not yet parseable (\xA713 Roadmap) |\n| `dad -- mom` \u2190 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 (\xA713 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 \u2014 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 \u2014 please open an issue.\n\n---'
944
963
  },
945
964
  "ecomap": {
946
965
  "title": "Ecomap",
@@ -968,7 +987,7 @@ var SYNTAX = {
968
987
  },
969
988
  "circuit": {
970
989
  "title": "Circuit schematic",
971
- "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` \u2014 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 \u2014 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="\u2026"] [label="\u2026"]\n```\n\nAn anonymous component omits the `id:` prefix \u2014 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 \u2192 capacitor \u2192 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 \u2014 3 decreasing lines (also: `gnd`) |\n| `gnd_signal` | Signal ground \u2014 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 \u2014 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 \u2014 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: +/\u2212 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 \u2014 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 \u2014 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\u2026] [value] [key=value\u2026]`\n\n- **ID** \u2014 component identifier. The first letter determines the default type (SPICE prefix convention).\n- **net1, net2, \u2026** \u2014 net names the pins connect to. Use `0`, `gnd`, or `GND` for the ground net.\n- **value** (optional bare token) \u2014 component value or model name.\n- **key=value** (optional) \u2014 `label=`, `value=`, `type=` overrides.\n\n### 4.2 SPICE prefix \u2192 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\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="\u2026"` | all components | Display label (reference designator) |\n| `value="\u2026"` | all components | Value annotation (1k\u03A9, 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"` \u2014 first line only.\n- **Component label:** `label="R1"` attribute \u2014 reference designator shown beside the symbol.\n- **Value annotation:** `value="4.7k"` \u2014 shown beside or below the component.\n- **Net label:** `label "VOUT" right` \u2014 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` \u2014 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\u03A9"`.\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 \u2014 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 \u2014 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` \u2014 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 \xA72 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 \u2014 please open an issue.\n\n---'
990
+ "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` \u2014 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 \u2014 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="\u2026"] [label="\u2026"]\n```\n\nAn anonymous component omits the `id:` prefix \u2014 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 \u2192 capacitor \u2192 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 \u2014 3 decreasing lines (also: `gnd`) |\n| `gnd_signal` | Signal ground \u2014 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 \u2014 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 \u2014 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: +/\u2212 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 \u2014 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 \u2014 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\u2026] [value] [key=value\u2026]`\n\n- **ID** \u2014 component identifier. The first letter determines the default type (SPICE prefix convention).\n- **net1, net2, \u2026** \u2014 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 \u2014 e.g. `gnd_ref`, `AGND_DIG`, `EARTH1`) all canonicalize to the ground net.\n- **value** (optional bare token) \u2014 component value or model name.\n- **key=value** (optional) \u2014 `label=`, `value=`, `type=` overrides.\n\n### 4.2 SPICE prefix \u2192 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 \u2014 directional valve envelopes, cylinder symbols, line styles for pressure/return/drain \u2014 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="\u2026"` | all components | Display label (reference designator) |\n| `value="\u2026"` | all components | Value annotation (1k\u03A9, 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"` \u2014 first line only.\n- **Component label:** `label="R1"` attribute \u2014 reference designator shown beside the symbol.\n- **Value annotation:** `value="4.7k"` \u2014 shown beside or below the component.\n- **Net label:** `label "VOUT" right` \u2014 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` \u2014 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\u03A9"`.\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 \u2014 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 \u2014 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` \u2014 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 \xA72 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 \u2014 please open an issue.\n\n---'
972
991
  },
973
992
  "block": {
974
993
  "title": "Block diagram",
@@ -1000,7 +1019,7 @@ var SYNTAX = {
1000
1019
  },
1001
1020
  "flowchart": {
1002
1021
  "title": "Flowchart",
1003
- "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]` \u2014 the shape brackets determine the node type (see \xA72).\n3. Connect nodes with `-->`. Add a label between pipe characters: `-->|Yes|`.\n4. Nodes are created automatically when first referenced in an edge \u2014 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** \u2014 placed between `|` characters directly after the arrow:\n```\nA -->|Yes| B\nA -.->|optional| B\nA ==>|critical| B\n```\n\n**Inline label** \u2014 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\u2192C and B\u2192C\nA --> B & C %% A\u2192B and A\u2192C\nA & B --> C & D %% four edges: A\u2192C, A\u2192D, B\u2192C, B\u2192D\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---\n\n## 6. Labels & comments\n\n- **Direction:** `flowchart TD` \u2014 first token after `flowchart` or `graph`. `TD` and `TB` are equivalent.\n- **Title:** `flowchart LR "My diagram"` \u2014 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 \u2014 ignored by the parser\nA[Step 1] --> B[Step 2] %% inline %% is NOT supported \u2014 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 \u2014 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 \u2014 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 \u2014 duplicate edges may appear | Use chains OR separate lines, not both for the same pair |\n| `direction LR` outside a subgraph | Silently ignored \u2014 `direction` override only applies inside `subgraph \u2026 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 ... %% parsed but not yet rendered\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 \u2014 please open an issue.\n\n---'
1022
+ "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]` \u2014 the shape brackets determine the node type (see \xA72).\n3. Connect nodes with `-->`. Add a label between pipe characters: `-->|Yes|`.\n4. Nodes are created automatically when first referenced in an edge \u2014 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** \u2014 placed between `|` characters directly after the arrow:\n```\nA -->|Yes| B\nA -.->|optional| B\nA ==>|critical| B\n```\n\n**Inline label** \u2014 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\u2192C and B\u2192C\nA --> B & C %% A\u2192B and A\u2192C\nA & B --> C & D %% four edges: A\u2192C, A\u2192D, B\u2192C, B\u2192D\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>\u2026</b>` | Bold |\n| `<i>\u2026</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` \u2014 first token after `flowchart` or `graph`. `TD` and `TB` are equivalent.\n- **Title:** `flowchart LR "My diagram"` \u2014 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 \u2014 ignored by the parser\nA[Step 1] --> B[Step 2] %% inline %% is NOT supported \u2014 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 \u2014 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 \u2014 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 \u2014 duplicate edges may appear | Use chains OR separate lines, not both for the same pair |\n| `direction LR` outside a subgraph | Silently ignored \u2014 `direction` override only applies inside `subgraph \u2026 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 \u2014 please open an issue.\n\n---'
1004
1023
  },
1005
1024
  "matrix": {
1006
1025
  "title": "Matrix / Quadrant diagram",
@@ -1104,7 +1123,7 @@ function getExamples(type, opts = {}) {
1104
1123
  function validateDsl(type, dsl) {
1105
1124
  const config = type ? { type } : void 0;
1106
1125
  try {
1107
- chunkXTATRNUN_cjs.parse(dsl, config);
1126
+ chunkAPV4AWQ5_cjs.parse(dsl, config);
1108
1127
  return { ok: true, type: type ?? resolveTypeFromText(dsl) };
1109
1128
  } catch (err) {
1110
1129
  return {
@@ -1120,7 +1139,7 @@ function renderDsl(type, dsl, options = {}) {
1120
1139
  ...type ? { type } : {}
1121
1140
  };
1122
1141
  try {
1123
- const svg = chunkXTATRNUN_cjs.render(dsl, config);
1142
+ const svg = chunkAPV4AWQ5_cjs.render(dsl, config);
1124
1143
  return { ok: true, type: type ?? resolveTypeFromText(dsl), svg };
1125
1144
  } catch (err) {
1126
1145
  return {
@@ -1144,5 +1163,5 @@ exports.getSyntax = getSyntax;
1144
1163
  exports.listDiagrams = listDiagrams;
1145
1164
  exports.renderDsl = renderDsl;
1146
1165
  exports.validateDsl = validateDsl;
1147
- //# sourceMappingURL=chunk-SQKLKBBK.cjs.map
1148
- //# sourceMappingURL=chunk-SQKLKBBK.cjs.map
1166
+ //# sourceMappingURL=chunk-UWRTV6IV.cjs.map
1167
+ //# sourceMappingURL=chunk-UWRTV6IV.cjs.map