schematex 0.6.1 → 0.6.2

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 (103) hide show
  1. package/dist/ai/ai-sdk.cjs +11 -11
  2. package/dist/ai/ai-sdk.d.cts +3 -3
  3. package/dist/ai/ai-sdk.d.ts +3 -3
  4. package/dist/ai/ai-sdk.js +6 -6
  5. package/dist/ai/index.cjs +17 -17
  6. package/dist/ai/index.d.cts +3 -3
  7. package/dist/ai/index.d.ts +3 -3
  8. package/dist/ai/index.js +6 -6
  9. package/dist/{api-DFrSR3lw.d.ts → api-XWHHAhQI.d.ts} +1 -1
  10. package/dist/{api-BEJTXyBA.d.cts → api-qVDutqXH.d.cts} +1 -1
  11. package/dist/browser.cjs +12 -12
  12. package/dist/browser.d.cts +3 -3
  13. package/dist/browser.d.ts +3 -3
  14. package/dist/browser.js +6 -6
  15. package/dist/{chunk-ST5YRTTV.cjs → chunk-2F45Y2ON.cjs} +44 -5
  16. package/dist/chunk-2F45Y2ON.cjs.map +1 -0
  17. package/dist/{chunk-V4RO5KYY.cjs → chunk-3JAI3OVG.cjs} +81 -47
  18. package/dist/chunk-3JAI3OVG.cjs.map +1 -0
  19. package/dist/{chunk-R6VX5YTJ.cjs → chunk-ECD5XHBM.cjs} +2 -2
  20. package/dist/{chunk-R6VX5YTJ.cjs.map → chunk-ECD5XHBM.cjs.map} +1 -1
  21. package/dist/{chunk-MFAMNFPA.js → chunk-EPKIJEH7.js} +6 -63
  22. package/dist/chunk-EPKIJEH7.js.map +1 -0
  23. package/dist/{chunk-OTSVMKII.js → chunk-ITUPR7G5.js} +150 -48
  24. package/dist/chunk-ITUPR7G5.js.map +1 -0
  25. package/dist/{chunk-I2GQYOZ5.js → chunk-IZWKJVIC.js} +147 -107
  26. package/dist/chunk-IZWKJVIC.js.map +1 -0
  27. package/dist/{chunk-UWA5MWCI.js → chunk-JVAJ6ZLO.js} +81 -47
  28. package/dist/chunk-JVAJ6ZLO.js.map +1 -0
  29. package/dist/{chunk-4XR7X7XW.cjs → chunk-KSNUMQGS.cjs} +151 -111
  30. package/dist/chunk-KSNUMQGS.cjs.map +1 -0
  31. package/dist/{chunk-522WB2EH.js → chunk-LGABFD3L.js} +2 -2
  32. package/dist/{chunk-522WB2EH.js.map → chunk-LGABFD3L.js.map} +1 -1
  33. package/dist/{chunk-6URNSB6G.js → chunk-P26FCZP3.js} +44 -5
  34. package/dist/chunk-P26FCZP3.js.map +1 -0
  35. package/dist/{chunk-SSLNPHCL.cjs → chunk-SD6VDTQR.cjs} +152 -50
  36. package/dist/chunk-SD6VDTQR.cjs.map +1 -0
  37. package/dist/{chunk-XNCOSVNG.cjs → chunk-SUIDD2C5.cjs} +6 -63
  38. package/dist/chunk-SUIDD2C5.cjs.map +1 -0
  39. package/dist/{diagnostics-B-ffSEhl.d.ts → diagnostics-DRxhodP6.d.cts} +0 -8
  40. package/dist/{diagnostics-B-ffSEhl.d.cts → diagnostics-DRxhodP6.d.ts} +0 -8
  41. package/dist/diagrams/blockdiagram/index.cjs +5 -5
  42. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  43. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  44. package/dist/diagrams/blockdiagram/index.js +1 -1
  45. package/dist/diagrams/circuit/index.cjs +7 -7
  46. package/dist/diagrams/circuit/index.d.cts +1 -1
  47. package/dist/diagrams/circuit/index.d.ts +1 -1
  48. package/dist/diagrams/circuit/index.js +1 -1
  49. package/dist/diagrams/ecomap/index.d.cts +1 -1
  50. package/dist/diagrams/ecomap/index.d.ts +1 -1
  51. package/dist/diagrams/entity/index.d.cts +1 -1
  52. package/dist/diagrams/entity/index.d.ts +1 -1
  53. package/dist/diagrams/fishbone/index.d.cts +1 -1
  54. package/dist/diagrams/fishbone/index.d.ts +1 -1
  55. package/dist/diagrams/flowchart/index.d.cts +2 -2
  56. package/dist/diagrams/flowchart/index.d.ts +2 -2
  57. package/dist/diagrams/genogram/index.d.cts +1 -1
  58. package/dist/diagrams/genogram/index.d.ts +1 -1
  59. package/dist/diagrams/ladder/index.d.cts +1 -1
  60. package/dist/diagrams/ladder/index.d.ts +1 -1
  61. package/dist/diagrams/logic/index.d.cts +1 -1
  62. package/dist/diagrams/logic/index.d.ts +1 -1
  63. package/dist/diagrams/orgchart/index.d.cts +1 -1
  64. package/dist/diagrams/orgchart/index.d.ts +1 -1
  65. package/dist/diagrams/pedigree/index.d.cts +1 -1
  66. package/dist/diagrams/pedigree/index.d.ts +1 -1
  67. package/dist/diagrams/phylo/index.d.cts +1 -1
  68. package/dist/diagrams/phylo/index.d.ts +1 -1
  69. package/dist/diagrams/sld/index.cjs +7 -7
  70. package/dist/diagrams/sld/index.d.cts +1 -1
  71. package/dist/diagrams/sld/index.d.ts +1 -1
  72. package/dist/diagrams/sld/index.js +1 -1
  73. package/dist/diagrams/sociogram/index.d.cts +1 -1
  74. package/dist/diagrams/sociogram/index.d.ts +1 -1
  75. package/dist/diagrams/timing/index.cjs +4 -4
  76. package/dist/diagrams/timing/index.d.cts +1 -1
  77. package/dist/diagrams/timing/index.d.ts +1 -1
  78. package/dist/diagrams/timing/index.js +1 -1
  79. package/dist/diagrams/venn/index.d.cts +1 -1
  80. package/dist/diagrams/venn/index.d.ts +1 -1
  81. package/dist/{index-S0njakQ2.d.cts → index-BRIkOPnd.d.cts} +1 -1
  82. package/dist/{index-DPWdYfNx.d.ts → index-C7SN-FB3.d.ts} +1 -1
  83. package/dist/index.cjs +32 -32
  84. package/dist/index.d.cts +4 -4
  85. package/dist/index.d.ts +4 -4
  86. package/dist/index.js +8 -8
  87. package/dist/react.cjs +6 -6
  88. package/dist/react.d.cts +2 -2
  89. package/dist/react.d.ts +2 -2
  90. package/dist/react.js +5 -5
  91. package/dist/{tools-kK_enDwb.d.ts → tools-BVeUNdsU.d.ts} +2 -2
  92. package/dist/{tools-CeGGMCs7.d.cts → tools-DdhP1kWY.d.cts} +2 -2
  93. package/package.json +1 -1
  94. package/dist/chunk-4XR7X7XW.cjs.map +0 -1
  95. package/dist/chunk-6URNSB6G.js.map +0 -1
  96. package/dist/chunk-I2GQYOZ5.js.map +0 -1
  97. package/dist/chunk-MFAMNFPA.js.map +0 -1
  98. package/dist/chunk-OTSVMKII.js.map +0 -1
  99. package/dist/chunk-SSLNPHCL.cjs.map +0 -1
  100. package/dist/chunk-ST5YRTTV.cjs.map +0 -1
  101. package/dist/chunk-UWA5MWCI.js.map +0 -1
  102. package/dist/chunk-V4RO5KYY.cjs.map +0 -1
  103. package/dist/chunk-XNCOSVNG.cjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { parseResult, renderResult } from './chunk-I2GQYOZ5.js';
1
+ import { parseResult, renderResult } from './chunk-IZWKJVIC.js';
2
2
 
3
3
  // src/ai/registry.ts
4
4
  var DIAGRAM_REGISTRY = [
@@ -614,6 +614,25 @@ If the LED doesn't light up, three things to check, in order: LED polarity (the
614
614
  "dsl": 'circuit "Inverting Op-Amp (netlist)" netlist\nVin vin 0 AC1V\nRin vin inv 10k\nRf out inv 100k\nU1 noninv inv out type=opamp label="U1 TL072"\nRbias noninv 0 10k\nVp vcc 0 +12V\nVn vee 0 -12V',
615
615
  "notes": "## Scenario\n\nAn analog engineer documents a standard inverting gain stage before moving to PCB layout. The two resistors make the gain visible in the schematic: `Rf / Rin = 10`, so the output is an inverted, amplified version of the input.\n\n## Annotation key\n\n- `type=opamp` selects the three-pin op-amp symbol in netlist mode.\n- `Rin` and `Rf` are ordinary SPICE-style resistor lines.\n- `noninv`, `inv`, and `out` are named nets, not pixel coordinates.\n\n## How to read\n\nThe input signal enters through `Rin` into the inverting input. `Rf` feeds the output back to the same node, closing the negative feedback loop. The non-inverting input is tied to ground through `Rbias`, giving the stage a stable reference."
616
616
  },
617
+ {
618
+ "slug": "circuit-pullup-orientation-hint",
619
+ "diagram": "circuit",
620
+ "title": "Pull-up resistor circuit with dir= orientation hint",
621
+ "description": "A netlist-mode circuit that uses the optional dir= orientation hint to draw the pull-up resistor vertically, showing lightweight layout control on top of automatic placement.",
622
+ "standard": "IEEE 315 / IEC 60617",
623
+ "tags": [
624
+ "netlist",
625
+ "pull-up",
626
+ "dir",
627
+ "orientation",
628
+ "push-button",
629
+ "SPICE"
630
+ ],
631
+ "complexity": 1,
632
+ "featured": false,
633
+ "dsl": 'circuit "Pull-up + push button" netlist\nV1 vcc 0 5V\nR1 vcc sig 10k dir=down\nSW1 sig 0 type=switch\nC1 sig 0 100n',
634
+ "notes": "## Scenario\n\nAn embedded engineer documents a classic active-low input: a pull-up resistor\nholds the signal high, a push button pulls it to ground, and a small capacitor\ndebounces it. The connectivity is written as a SPICE-style netlist \u2014 the engine\nplaces everything from the node names \u2014 and one optional hint refines the look.\n\n## Annotation key\n\n- **netlist line** \u2014 `id node-A node-B value`; components that share a node name\n are wired together. `0` is ground.\n- **`dir=down`** \u2014 the optional orientation hint. `R1` connects `vcc` to `sig`;\n by default the engine would lay it horizontally, but a pull-up reads best drawn\n vertically from the supply rail down to the signal node, so `dir=down` rotates\n just that symbol. Connectivity is unchanged \u2014 `dir=` only rotates the glyph.\n- **`type=switch`** \u2014 the `SW1` id prefix is ambiguous, so the component type is\n made explicit.\n\n## How to read\n\n`R1` ties `sig` up to `vcc` (drawn vertically thanks to `dir=down`). `SW1` and the\ndebounce cap `C1` both go from `sig` to ground, so the engine recognises them as\nshunt legs and drops them beneath the node. Pressing the button shorts `sig` to\nground, pulling the input low."
635
+ },
617
636
  {
618
637
  "slug": "decisiontree-investment-analysis",
619
638
  "diagram": "decisiontree",
@@ -2410,6 +2429,25 @@ If the LED doesn't light up, three things to check, in order: LED polarity (the
2410
2429
  "dsl": 'timeline "Platform v2 Launch"\nconfig: style = gantt\n\n2025-07-01 - 2025-08-15: "Engineering build" [category: "engineering"]\n2025-07-15 - 2025-08-31: "Design polish" [category: "design"]\n2025-08-01 - 2025-09-10: "Marketing collateral" [category: "marketing"]\n2025-08-20: milestone "Feature freeze" [color: #E53935]\n2025-08-20 - 2025-09-05: "QA hardening" [category: "engineering"]\n2025-09-01 - 2025-09-12: "Press embargo outreach" [category: "marketing"]\n2025-09-15: milestone "Public launch" [color: #2E7D32]',
2411
2430
  "notes": '## Scenario\n\nThe launch PM shares this in weekly exec status. Overlapping bars show where workstreams parallelize (design polishing while engineering still builds) and the feature-freeze diamond makes the handoff between build and QA unmissable. The second milestone (public launch) anchors the entire timeline and is the reason every other bar exists.\n\n## Annotation key\n\n- `DATE - DATE: "Label"` \u2014 range (bar) event\n- `DATE: milestone "Label"` \u2014 point milestone (diamond)\n- `[category: \u2026]` \u2014 group colour in the gantt legend\n- `[color: #hex]` \u2014 explicit marker colour\n\n## How to read\n\nTime flows left to right. Horizontal bars are continuous work; diamonds are instantaneous events. Overlapping bars mean two teams are working simultaneously \u2014 fine, so long as they coordinate. The red *Feature freeze* marks the transition from net-new work to hardening; any engineering bar extending past it needs an exception. The green *Public launch* is the terminal milestone every other bar is serving.'
2412
2431
  },
2432
+ {
2433
+ "slug": "timing-clock-rle-shorthand",
2434
+ "diagram": "timing",
2435
+ "title": "Timing diagram with clock and run-length shorthands",
2436
+ "description": "A synchronous bus-read timing diagram written with the clock and rle shorthands so signals stay aligned without hand-counting wave characters.",
2437
+ "standard": "WaveDrom / IEEE 1497",
2438
+ "tags": [
2439
+ "clock",
2440
+ "run-length",
2441
+ "rle",
2442
+ "WaveDrom",
2443
+ "synchronous",
2444
+ "bus-read"
2445
+ ],
2446
+ "complexity": 1,
2447
+ "featured": false,
2448
+ "dsl": 'timing "Synchronous Bus Read"\nCLK: clock 8\nRST: rle 1*2 0*6\nEN: rle 0*2 1*4 0*2\nDATA: zz====zz data: ["D0","D1","D2","D3"]',
2449
+ "notes": "## Scenario\n\nA digital designer documents an 8-cycle synchronous read. Rather than typing\n`pppppppp` for the clock and counting `0`/`1` runs by hand for reset and enable \u2014\nthe most common source of misaligned waveforms \u2014 the diagram uses the two\nlength-explicit shorthands.\n\n## Annotation key\n\n- **`clock N`** \u2014 a clock generator with `N` periods. `CLK: clock 8` expands to\n `pppppppp`; add `neg` for a negedge clock. No character-counting.\n- **`rle <state>*<count> \u2026`** \u2014 run-length segments. `RST: rle 1*2 0*6` expands to\n `11000000`; `EN: rle 0*2 1*4 0*2` expands to `00111100`. Every signal's total\n cell count is explicit, so the waves line up.\n- **raw wave string** \u2014 `DATA: zz====zz` keeps per-cell control where it matters;\n `data: [...]` labels the four `=` bus segments.\n\n## How to read\n\nThe clock runs 8 cycles. Reset is asserted for the first 2 cycles, then drops.\nEnable rises for the middle 4 cycles. The data bus is high-impedance until enable,\nthen presents four stable bytes `D0\u2026D3`, returning to high-Z after. Because\n`clock` and `rle` make each signal exactly 8 cells, the edges align without manual\ncounting."
2450
+ },
2413
2451
  {
2414
2452
  "slug": "timing-i2c-read-burst",
2415
2453
  "diagram": "timing",
@@ -2545,7 +2583,7 @@ var SYNTAX = {
2545
2583
  },
2546
2584
  "timing": {
2547
2585
  "title": "Timing diagram",
2548
- "content": '## 1. Your first timing diagram\n\nThe smallest useful timing diagram: a clock and one data signal.\n\n```\ntiming\nCLK: pppppppp\nDATA: 0011==00 data: ["A","B"]\n```\n\nThree rules cover 80% of usage:\n\n1. Start with the keyword `timing`, optionally followed by a quoted title and `[hscale: N]`.\n2. Each signal is one line: `NAME: wavestring` \u2014 name, colon, then a string of wave characters (no spaces inside the wave).\n3. Add `data: ["val1", "val2"]` after the wave string to label bus segments.\n\n> Comments must start with `#` on their own line.\n\n---\n\n## 2. Wave characters\n\nThe wave string is a sequence of characters, one per time period. The parser accepts these:\n\n| Character | State | Meaning |\n|---|---|---|\n| `0` | Logic low | Signal at GND / VSS |\n| `1` | Logic high | Signal at VDD |\n| `x` | Unknown | Don\'t-care, undefined, or uninitialized |\n| `z` | High-Z | Tri-state / high-impedance |\n| `p` | Clock pulse (positive) | Rising-edge-active clock; one `p` = one full period (low\u2192high\u2192low) |\n| `P` | Clock pulse (positive, tall) | Same as `p`, visually taller |\n| `n` | Clock pulse (negative) | Falling-edge-active; one `n` = one full period (high\u2192low\u2192high) |\n| `N` | Clock pulse (negative, tall) | Same as `n`, visually taller |\n| `=` | Bus data | Parallel-bus segment; add labels via `data: [\u2026]` |\n| `2`\u2013`9` | Named bus segment | Same as `=`, indexed into `data: [\u2026]` by position |\n| `.` | Hold / continue | Extend the previous state for one more period |\n| `h` / `H` | Hold high | Force-high for this period |\n| `l` / `L` | Hold low | Force-low for this period |\n| `u` | Rising edge | Diagonal from low to high (transition only) |\n| `d` / `D` | Falling edge | Diagonal from high to low (transition only) |\n\n```\ntiming "Wave character reference"\nclk: pppppppppp\nhigh: 1111111111\nlow: 0000000000\nunkn: xxxxxxxxxx\nhiz: zzzzzzzzzz\nbus: x========x data: ["ADDR","DATA","","","","","",""]\nhold: 0..1..0..1\nrise: 0u1\nfall: 1d0\n```\n\n---\n\n## 3. Data labels\n\nWhen a signal carries a bus value, tag the wave with `data: ["label1", "label2", \u2026]`. Each non-empty quoted string is placed inside the corresponding `=` (or `2`\u2013`9`) segment.\n\n```\nMOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]\n```\n\nEmpty strings `""` leave a segment unlabeled (useful for segments that extend a previous value).\n\n```\nMISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]\n# first four z-periods have no label; four = segments get labels starting at 0xFF\n```\n\n```\ntiming "I2C read burst"\nSCL: ppppppppppp\nSDA: x1=======1x data: ["ADDR+R","ACK","D0","D1","D2","D3","D4","D5","NACK"]\n```\n\n---\n\n## 4. Grouping signals\n\nWrap related signals in a `[GroupName]` block. A `---` line closes the group and also acts as a visual separator between groups.\n\n```\n[Control]\nCLK: pppppppp\nCS_N: 10000001\n---\n[Data]\nMOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]\nMISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]\n```\n\nAlternative `group "name" { \u2026 }` syntax is also accepted (closing `}` closes the group).\n\n```\ntiming "UART frame"\n[Clock & control]\nCLK: pppppppppppp\nTX_EN: 0111111110\n---\n[Data lines]\nTX: 1========== data: ["START","D0","D1","D2","D3","D4","D5","D6","D7","STOP"]\nRX: zz1=======1 data: ["","","D0","D1","D2","D3","D4","D5","D6","D7"]\n```\n\n---\n\n## 5. Title and hscale\n\n**Title:** `timing "SPI Transaction"` \u2014 appears at the top of the diagram.\n\n**hscale:** `timing "title" [hscale: 2]` \u2014 scales the width of each time period. Default is 1. Use 2 for wider periods when data labels need more room.\n\n```\ntiming "Wide bus" [hscale: 2]\nCLK: pppp\nDATA: ==== data: ["long label here","another","third","fourth"]\n```\n\n---\n\n## 6. Labels & comments\n\n- **Signal name:** anything before the first `:` on a signal line. Names with spaces are fine \u2014 the colon is the delimiter.\n- **Data labels:** `data: ["a", "b"]` after the wave string.\n- **Title:** first token after `timing` keyword, quoted.\n- **Comments:** `#` at the start of a line (after leading whitespace).\n\n```\ntiming "Demo"\n# this is a comment\nCLK: pppp # \u2190 inline trailing comment is NOT supported\n```\n\n---\n\n## 7. Common mistakes\n\n| You wrote | Parser says | Fix |\n|---|---|---|\n| `CLK: p p p p` (spaces in wave) | Wave string parsed as `p` only; the rest is treated as data clause | Remove spaces: `CLK: pppp` |\n| `DATA: =====` with no `data:` | Segments render as unlabeled bus cells | Add `data: ["A","B","C","D","E"]` |\n| Wave character `s` or `r` | `TimingParseError: Invalid wave string` | Only the characters listed in \xA72 are valid |\n| `CLK pppp` (no colon) | Line does not match signal pattern; silently skipped | The colon after the signal name is required |\n| `data: [A, B, C]` (unquoted) | Values not recognized \u2014 parser looks for `"\u2026"` | Quote each value: `data: ["A","B","C"]` |\n| `[Group Name with spaces]` | Group label is `Group Name with spaces` \u2014 parsed fine | Supported |\n| `hscale: 2` on its own line | Not recognized (hscale goes on the header line) | `timing "title" [hscale: 2]` |\n\n---\n\n## 8. Grammar (EBNF)\n\n```text\ndocument = header (blank | comment | group-open | group-close | separator | signal)*\n\nheader = "timing" ( WS quoted-string )? ( WS "[" "hscale:" number "]" )? NEWLINE\nquoted-string = \'"\' any-char-but-quote* \'"\'\n\ngroup-open = "[" label "]" NEWLINE\n | "group" WS quoted-string WS "{"? NEWLINE\ngroup-close = "}" NEWLINE\nseparator = "---" NEWLINE\n\nsignal = name ":" WS wave-string ( WS data-clause )? NEWLINE\nname = any text before the first ":"\nwave-string = wave-char+\nwave-char = "0"|"1"|"x"|"z"\n | "p"|"P"|"n"|"N"\n | "h"|"H"|"l"|"L"\n | "u"|"d"|"D"\n | "="|"."|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"\n\ndata-clause = "data:" WS ( "[" quoted-string ("," quoted-string)* "]"\n | quoted-string+ )\n\ncomment = "#" any NEWLINE\n```\n\nAuthoritative source: `src/diagrams/timing/parser.ts`. If this diverges from the parser, the parser wins \u2014 please open an issue.\n\n---'
2586
+ "content": '## 1. Your first timing diagram\n\nThe smallest useful timing diagram: a clock and one data signal. The friendliest way to write it avoids counting characters entirely:\n\n```\ntiming\nCLK: clock 8\nRST: rle 1*2 0*6\nDATA: 0011==00 data: ["A","B"]\n```\n\nThree rules cover 80% of usage:\n\n1. Start with the keyword `timing`, optionally followed by a quoted title and `[hscale: N]`.\n2. Each signal is one line: `NAME: <wave>` \u2014 name, colon, then the waveform. The waveform can be:\n - **`clock N`** \u2014 a clock generator with `N` periods (add `neg` for a negedge clock). No character-counting.\n - **`rle <state>*<count> \u2026`** \u2014 run-length segments, e.g. `rle 1*2 0*6` = `11000000`. Auto-aligns length.\n - **a raw WaveDrom wave string** \u2014 a contiguous run of state characters (no internal spaces) for fine control.\n3. Add `data: ["val1", "val2"]` after a raw wave string to label bus segments.\n\n> **Tip for alignment:** the #1 cause of a broken timing diagram is signals of unequal length. `clock N` and `rle` make every signal\'s cell count explicit, so they line up. Use raw wave strings only when you need per-cell control.\n\n> Comments must start with `#` on their own line.\n\n---\n\n## 2. Wave characters\n\nThe wave string is a sequence of characters, one per time period. The parser accepts these:\n\n| Character | State | Meaning |\n|---|---|---|\n| `0` | Logic low | Signal at GND / VSS |\n| `1` | Logic high | Signal at VDD |\n| `x` | Unknown | Don\'t-care, undefined, or uninitialized |\n| `z` | High-Z | Tri-state / high-impedance |\n| `p` | Clock pulse (positive) | Rising-edge-active clock; one `p` = one full period (low\u2192high\u2192low) |\n| `P` | Clock pulse (positive, tall) | Same as `p`, visually taller |\n| `n` | Clock pulse (negative) | Falling-edge-active; one `n` = one full period (high\u2192low\u2192high) |\n| `N` | Clock pulse (negative, tall) | Same as `n`, visually taller |\n| `=` | Bus data | Parallel-bus segment; add labels via `data: [\u2026]` |\n| `2`\u2013`9` | Named bus segment | Same as `=`, indexed into `data: [\u2026]` by position |\n| `.` | Hold / continue | Extend the previous state for one more period |\n| `h` / `H` | Hold high | Force-high for this period |\n| `l` / `L` | Hold low | Force-low for this period |\n| `u` | Rising edge | Diagonal from low to high (transition only) |\n| `d` / `D` | Falling edge | Diagonal from high to low (transition only) |\n\n```\ntiming "Wave character reference"\nclk: pppppppppp\nhigh: 1111111111\nlow: 0000000000\nunkn: xxxxxxxxxx\nhiz: zzzzzzzzzz\nbus: x========x data: ["ADDR","DATA","","","","","",""]\nhold: 0..1..0..1\nrise: 0u1\nfall: 1d0\n```\n\n---\n\n## 3. Data labels\n\nWhen a signal carries a bus value, tag the wave with `data: ["label1", "label2", \u2026]`. Each non-empty quoted string is placed inside the corresponding `=` (or `2`\u2013`9`) segment.\n\n```\nMOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]\n```\n\nEmpty strings `""` leave a segment unlabeled (useful for segments that extend a previous value).\n\n```\nMISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]\n# first four z-periods have no label; four = segments get labels starting at 0xFF\n```\n\n```\ntiming "I2C read burst"\nSCL: ppppppppppp\nSDA: x1=======1x data: ["ADDR+R","ACK","D0","D1","D2","D3","D4","D5","NACK"]\n```\n\n---\n\n## 4. Grouping signals\n\nWrap related signals in a `[GroupName]` block. A `---` line closes the group and also acts as a visual separator between groups.\n\n```\n[Control]\nCLK: pppppppp\nCS_N: 10000001\n---\n[Data]\nMOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]\nMISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]\n```\n\nAlternative `group "name" { \u2026 }` syntax is also accepted (closing `}` closes the group).\n\n```\ntiming "UART frame"\n[Clock & control]\nCLK: pppppppppppp\nTX_EN: 0111111110\n---\n[Data lines]\nTX: 1========== data: ["START","D0","D1","D2","D3","D4","D5","D6","D7","STOP"]\nRX: zz1=======1 data: ["","","D0","D1","D2","D3","D4","D5","D6","D7"]\n```\n\n---\n\n## 5. Title and hscale\n\n**Title:** `timing "SPI Transaction"` \u2014 appears at the top of the diagram.\n\n**hscale:** `timing "title" [hscale: 2]` \u2014 scales the width of each time period. Default is 1. Use 2 for wider periods when data labels need more room.\n\n```\ntiming "Wide bus" [hscale: 2]\nCLK: pppp\nDATA: ==== data: ["long label here","another","third","fourth"]\n```\n\n---\n\n## 6. Labels & comments\n\n- **Signal name:** anything before the first `:` on a signal line. Names with spaces are fine \u2014 the colon is the delimiter.\n- **Data labels:** `data: ["a", "b"]` after the wave string.\n- **Title:** first token after `timing` keyword, quoted.\n- **Comments:** `#` at the start of a line (after leading whitespace).\n\n```\ntiming "Demo"\n# this is a comment\nCLK: pppp # \u2190 inline trailing comment is NOT supported\n```\n\n---\n\n## 7. Common mistakes\n\n| You wrote | Parser says | Fix |\n|---|---|---|\n| `CLK: p p p p` (spaces in wave) | Wave string parsed as `p` only; the rest is treated as data clause | Remove spaces: `CLK: pppp` |\n| `DATA: =====` with no `data:` | Segments render as unlabeled bus cells | Add `data: ["A","B","C","D","E"]` |\n| Wave character `s` or `r` | `TimingParseError: Invalid wave string` | Only the characters listed in \xA72 are valid |\n| `CLK pppp` (no colon) | Line does not match signal pattern; silently skipped | The colon after the signal name is required |\n| `data: [A, B, C]` (unquoted) | Values not recognized \u2014 parser looks for `"\u2026"` | Quote each value: `data: ["A","B","C"]` |\n| `[Group Name with spaces]` | Group label is `Group Name with spaces` \u2014 parsed fine | Supported |\n| `hscale: 2` on its own line | Not recognized (hscale goes on the header line) | `timing "title" [hscale: 2]` |\n\n---\n\n## 8. Grammar (EBNF)\n\n```text\ndocument = header (blank | comment | group-open | group-close | separator | signal)*\n\nheader = "timing" ( WS quoted-string )? ( WS "[" "hscale:" number "]" )? NEWLINE\nquoted-string = \'"\' any-char-but-quote* \'"\'\n\ngroup-open = "[" label "]" NEWLINE\n | "group" WS quoted-string WS "{"? NEWLINE\ngroup-close = "}" NEWLINE\nseparator = "---" NEWLINE\n\nsignal = name ":" WS wave-string ( WS data-clause )? NEWLINE\nname = any text before the first ":"\nwave-string = wave-char+\nwave-char = "0"|"1"|"x"|"z"\n | "p"|"P"|"n"|"N"\n | "h"|"H"|"l"|"L"\n | "u"|"d"|"D"\n | "="|"."|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"\n\ndata-clause = "data:" WS ( "[" quoted-string ("," quoted-string)* "]"\n | quoted-string+ )\n\ncomment = "#" any NEWLINE\n```\n\nAuthoritative source: `src/diagrams/timing/parser.ts`. If this diverges from the parser, the parser wins \u2014 please open an issue.\n\n---'
2549
2587
  },
2550
2588
  "logic": {
2551
2589
  "title": "Logic gate diagram",
@@ -2553,7 +2591,7 @@ var SYNTAX = {
2553
2591
  },
2554
2592
  "circuit": {
2555
2593
  "title": "Circuit schematic",
2556
- "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---'
2594
+ "content": '## 1. A minimal circuit (netlist mode \u2014 recommended)\n\nThe smallest useful circuit: a voltage source, a resistor, and a capacitor to ground \u2014 an RC low-pass filter.\n\n```\ncircuit "RC Low-Pass" netlist\nV1 in 0 5V\nR1 in out 1k\nC1 out 0 100n\n```\n\nThree rules cover ~90% of netlist usage:\n\n1. Start with `circuit "Title" netlist` (the `netlist` keyword switches on this mode).\n2. Each line is `componentId nodeA nodeB value` \u2014 one component, the two (or more) named nodes it connects to, then its value.\n3. **Two components that share a node name are wired together.** `0`, `gnd`, or `GND` is the ground net (a ground symbol is drawn automatically).\n\nThe component-id prefix sets the symbol: `R*`\u2192resistor, `C*`\u2192capacitor, `L*`\u2192inductor, `V*`\u2192voltage source, `D*`\u2192diode, `Q*`\u2192BJT. When the prefix is ambiguous, add `type=` (e.g. `X1 a b type=opamp`). You never compute coordinates \u2014 the engine derives placement from the connectivity.\n\n> Comments must start with `#` on their own line.\n\n---\n\n## 2. Components\n\n### 2.1 Netlist mode syntax\n\nA netlist line has the form:\n\n```\ncomponentId node... [value] [type=\u2026] [label="\u2026"]\n```\n\nThe positional nodes come first; a trailing token that doesn\'t look like a node becomes the value. Example \u2014 a transistor (4 nodes) and a resistor:\n\n```\nQ1 c b e npn # collector, base, emitter nodes + model\nRc vcc c 2.2k # two nodes + value\n```\n\n**Optional orientation hint.** The engine auto-orients symbols by role (sources up, ground down, the rest horizontal). To nudge a single symbol, add `dir=right|left|up|down` \u2014 connectivity is unchanged, only the symbol\'s facing rotates:\n\n```\nC1 out 0 100n dir=down # draw C1 as a shunt cap hanging to ground\n```\n\nThis is the lightweight layout-control layer (like Lcapy\'s per-component orientation): netlist connectivity does the heavy lifting, `dir=` only refines appearance. For full geometric control, use positional mode below.\n\n### 2.2 Positional mode syntax (hand-drawing)\n\n> Positional mode is for manually laying out a schematic geometrically. **Prefer netlist mode for generated output** \u2014 positional mode requires tracking a moving "cursor" across lines, which is error-prone for LLMs.\n\nA named component line has the form:\n\n```\nid: type direction [value="\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.3 Passive components\n\n| DSL type | Description |\n|---|---|\n| `resistor` | Zigzag (ANSI) or rectangle (IEC) |\n| `potentiometer` | Resistor + wiper arrow, 3-pin |\n| `rheostat` | 2-pin variable resistor |\n| `thermistor_ntc` | NTC thermistor (also: `therm`, `ntc`) |\n| `thermistor_ptc` | PTC thermistor (also: `ptc`) |\n| `ldr` | Light-dependent resistor |\n| `varistor` | Voltage-dependent resistor |\n| `fuse` | Standard fuse |\n| `fuse_slow` | Slow-blow fuse (`T` designation) |\n| `capacitor` | Non-polar capacitor |\n| `electrolytic_cap` | Polar/electrolytic capacitor (also: `ecap`) |\n| `variable_cap` | Variable capacitor |\n| `inductor` | Air-core inductor |\n| `inductor_iron` | Iron-core inductor |\n| `inductor_ferrite` | Ferrite-core inductor |\n| `variable_inductor` | Variable inductor |\n| `ferrite_bead` | EMI ferrite bead |\n| `crystal` | Quartz crystal oscillator (also: `xtal`) |\n| `transformer` | Coupled coils (also: `xfmr`) |\n\n```\ncircuit "Passive components gallery"\n# Row 1: resistor \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.4 Sources and power\n\n| DSL type | Description |\n|---|---|\n| `voltage_source` | Circle + polarity (also: `vsource`) |\n| `current_source` | Circle + arrow (also: `isource`) |\n| `ac_source` | Circle + sine symbol (also: `acsource`) |\n| `battery` | Alternating long/short terminal lines |\n| `vcc` | Power rail arrow (pointing up) |\n| `ground` | Earth ground \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.5 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.6 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.7 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.8 Switches and relays\n\n| DSL type | Description |\n|---|---|\n| `switch_spst` | Single-pole single-throw |\n| `switch_spdt` | Single-pole double-throw |\n| `switch_dpdt` | Double-pole double-throw |\n| `push_no` | Push button normally-open |\n| `push_nc` | Push button normally-closed |\n| `relay_coil` | Relay coil (2-pin rect) |\n| `relay_no` | Relay contact normally-open |\n| `relay_nc` | Relay contact normally-closed |\n\n```\ncircuit "Switch and relay gallery"\n# SPST switch\nS1: switch_spst right\nwire right\nwire right\n# SPDT switch\nS2: switch_spdt right\nwire right\nwire right\n# normally-open push button\nS3: push_no right\nwire right\nwire right\n# relay coil + contact pair\nK1: relay_coil right\nwire right\nK2: relay_no right\n```\n\n### 2.9 Electromechanical and measurement\n\n| DSL type | Description |\n|---|---|\n| `motor` | Circle + M |\n| `speaker` | Cone + box |\n| `microphone` | Capsule symbol |\n| `buzzer` | Piezo buzzer |\n| `ammeter` | Circle + A |\n| `voltmeter` | Circle + V |\n| `wattmeter` | Circle + W |\n| `oscilloscope` | Circle + waveform |\n\n### 2.10 Connectors and annotations\n\n| DSL type | Description |\n|---|---|\n| `wire` | Plain wire segment |\n| `dot` | Junction dot (T-junction marker) |\n| `label` | Net label / flag |\n| `port` | Named port (hollow circle) |\n| `test_point` | TP marker |\n| `no_connect` | X \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---'
2557
2595
  },
2558
2596
  "block": {
2559
2597
  "title": "Block diagram",
@@ -2653,7 +2691,7 @@ var SYNTAX = {
2653
2691
  },
2654
2692
  "network": {
2655
2693
  "title": "Network Topology",
2656
- "content": '## 1. Your first diagram\n\nEvery document starts with the `network` keyword and an optional title, then declares **devices** before connecting them with **links**:\n\n```\nnetwork "Home"\n layout: star\n router gw "Gateway"\n pc pc1\n laptop lt1\n gw -- pc1\n gw -- lt1 : wireless\n```\n\n- `<kind> <id> ["label"]` \u2014 a typed device. The kind picks the icon.\n- `<a> -- <b>` \u2014 an undirected link. `->` is directed; `==` is a LAG (aggregated) link.\n- Anything after `:` on a link is the **link spec** (type, mode, VLAN, speed, ports).\n\nDevices are **not** auto-declared from links \u2014 an undeclared id can\'t be safely typed, so a link to an unknown device is a readable error. Use `;` to put several statements on one line, and `a b c : kind` shorthand to declare several same-kind devices at once.\n\n---\n\n## 2. Device kinds\n\nPick the kind that matches the box; the icon follows the Cisco-convention silhouette.\n\n- **Infrastructure** \u2014 `router`, `switch`, `l3switch`, `firewall`, `loadbalancer`, `ap`, `wlc`, `gateway`, `modem`, `ids`, `proxy`, `vpngw`\n- **Endpoints** \u2014 `server`, `serverfarm` (`count: n`), `pc`, `laptop`, `mobile`, `ipphone`, `printer`, `storage`\n- **CCTV / security** \u2014 `camera` (with `type: fixed | bullet | dome | ptz | turret`), `nvr`, `dvr`, `poeswitch`, `encoder`, `monitor`\n- **Clouds** \u2014 `internet`, `wan`, `pstn`, `cloud`, plus `lan` (a bus bar)\n\nAliases are accepted: `multilayer`\u2192`l3switch`, `workstation`\u2192`pc`, `wifi`\u2192`ap`, `nas`/`san`\u2192`storage`, `voip`\u2192`ipphone`.\n\n```\ncamera cam1 type: dome ip: 192.168.20.11\nserverfarm farm "Server Farm" count: 4\nl3switch core1 tier: core model: "C9500"\n```\n\n---\n\n## 3. Links & annotations\n\nA link\'s appearance follows its type; everything after `:` is order-free.\n\n```\na -- b # copper / ethernet (default solid)\na -- b : fiber 10G # fiber \u2014 orange with slash ticks\na -- b : wireless # dashed\na -- b : serial # leased / WAN circuit\na -- b : poe # Power-over-Ethernet (green + tag)\na -- b : vpn "site-to-site" # dashed tunnel\na == b : lag 40G # aggregated / EtherChannel (double line)\na -- b : trunk vlan: 10,20 1G port: Gi0/1>Gi1/0/24\n```\n\n- `trunk` / `access` \u2014 port mode (a trunk should connect switch-class devices).\n- `vlan: 10` or `vlan: 10,20` \u2014 a single VLAN tints the link (skipping the reserved alarm-red).\n- `1G` / `10G` / `100M` / `40G` \u2014 speed, shown mid-link.\n- `port: near>far` \u2014 interface labels at each end.\n\n---\n\n## 4. Layout modes\n\n```\nlayout: tiered # default \u2014 band by tier: edge \u2192 core \u2192 distribution \u2192 access\nlayout: tree # hierarchical from the root\nlayout: star # hub at center, spokes on a ring\nlayout: ring # nodes on a circle\nlayout: bus # shared backbone\nlayout: mesh # full/partial mesh on a circle\nlayout: spine-leaf # two rows, every leaf auto-meshed to every spine\nlayout: manual # explicit at: x,y per device\ndirection: tb | lr # flow axis for tiered/tree\n```\n\nFor `tiered`, set `tier:` (`edge` / `core` / `distribution` / `access`) on infrastructure; untiered endpoints are placed below their switch. For `spine-leaf`, declare `spines:` and `leaves:` and the spine\u2194leaf links are generated for you.\n\n---\n\n## 5. Boundaries: sites, racks, subnets, VLANs\n\nA device can live inside nested boundary blocks. **Physical** containers (site/rack) draw a solid border; **logical** overlays (subnet/VLAN/zone/DMZ) draw a dashed tinted region.\n\n```\nnetwork "Branch"\n site hq "HQ Building" {\n rack mdf "MDF Rack" {\n firewall fw1 tier: edge\n l3switch core1 tier: core\n }\n }\n subnet lan "10.0.10.0/24" {\n switch a1 tier: access\n pc u1 "User PC" ip: 10.0.10.50\n }\n zone dmz "DMZ" {\n server web\n }\n fw1 -- core1 : 10G\n core1 -- a1 : trunk vlan: 10\n a1 -- u1\n```\n\nA device declared inside a `subnet` whose label is a CIDR has its `ip:` validated \u2014 an address outside the range is a readable error. A bare id on its own line inside a block adds an already-declared device to that group.\n\n---\n\n## 6. Validation & the no-drop guarantee\n\nThe engine guarantees every declared device and link renders \u2014 the dropped-device failure of generic tools is structurally impossible. It also checks:\n\n- **duplicate id** \u2192 error;\n- **unknown kind** \u2192 error with the nearest suggestion (`"swtich" \u2192 did you mean "switch"?`);\n- **link to an undeclared device** \u2192 error;\n- **VLAN id outside 1\u20134094** \u2192 warning (still renders);\n- **device IP outside its subnet CIDR** \u2192 error.\n\nThe SVG `<desc>` records device/link counts, the detected topology class (star / ring / bus / mesh / tree / hierarchical / spine-leaf), and any warnings.\n\n---\n\n## 7. Themes\n\n```\ntheme: default # house "network blue" Cisco-style bodies\ntheme: monochrome # clean line-art for print/audit (link meaning via line-style + tags)\ntheme: dark # Catppuccin Mocha\n```\n\nCJK labels and `\u300C\u2026\u300D` / `"\u2026"` quotes parse cleanly:\n\n```\nnetwork "\u529E\u516C\u5BA4"\n multilayer core1 \u300C\u6838\u5FC3\u4EA4\u6362\u673A\u300D\n poeswitch poe1\n camera cam1 type: dome\n core1 -- poe1 : trunk vlan: 10\n poe1 -- cam1 : poe\n```\n\n---'
2694
+ "content": '## 1. Your first diagram\n\nA complete network diagram needs only two kinds of line: **device declarations** and **links**. Nothing else is required.\n\n```\nnetwork "Tiny LAN"\nrouter r1 "Edge Router"\nswitch sw1 "Core Switch"\npc pc1 "Workstation"\nr1 -- sw1\nsw1 -- pc1\n```\n\nThat\'s it \u2014 a valid, laid-out diagram. Just two rules:\n\n- `<kind> <id> ["label"]` \u2014 a typed device. The kind picks the icon.\n- `<a> -- <b>` \u2014 an undirected link between two declared devices.\n\n**Everything else is optional and additive \u2014 but not all of it is equal.** Two cheap, high-value structural hints are worth adding whenever hierarchy matters: `layout:` (tiered/tree/star/ring/bus/mesh/spine-leaf) and `tier:` (edge/core/distribution/access). They drive a readable top-down hierarchy at almost no syntax cost:\n\n```\nnetwork "Branch"\n layout: tiered\n router r1 "Edge Router" tier: edge\n l3switch core1 "Core SW" tier: core\n switch acc1 "Access SW" tier: access\n pc pc1 "Workstation"\n r1 -- core1\n core1 -- acc1\n acc1 -- pc1\n```\n\nBy contrast, the **per-link annotations** \u2014 link types (`fiber`/`wireless`/`poe`\u2026), speeds, `vlan:`, `port:`, `trunk`/`access`, and `subnet { }` boundaries \u2014 don\'t affect layout and are where generation most often breaks. Add them only when the request calls for them. Rule of thumb: keep the structural hints, drop the decorative annotations unless asked.\n\nDevices are **not** auto-declared from links \u2014 an undeclared id can\'t be safely typed, so a link to an unknown device is a readable error. Use `;` to put several statements on one line, and `a b c : kind` shorthand to declare several same-kind devices at once.\n\nOnce the skeleton works, you can layer on direction and annotations \u2014 `->` is a directed link, `==` is a LAG, and anything after `:` is the link spec:\n\n```\nnetwork "Home"\n layout: star\n router gw "Gateway"\n pc pc1\n laptop lt1\n gw -- pc1\n gw -- lt1 : wireless\n```\n\n---\n\n## 2. Device kinds\n\nPick the kind that matches the box; the icon follows the Cisco-convention silhouette.\n\n- **Infrastructure** \u2014 `router`, `switch`, `l3switch`, `firewall`, `loadbalancer`, `ap`, `wlc`, `gateway`, `modem`, `ids`, `proxy`, `vpngw`\n- **Endpoints** \u2014 `server`, `serverfarm` (`count: n`), `pc`, `laptop`, `mobile`, `ipphone`, `printer`, `storage`\n- **CCTV / security** \u2014 `camera` (with `type: fixed | bullet | dome | ptz | turret`), `nvr`, `dvr`, `poeswitch`, `encoder`, `monitor`\n- **Clouds** \u2014 `internet`, `wan`, `pstn`, `cloud`, plus `lan` (a bus bar)\n\nAliases are accepted: `multilayer`\u2192`l3switch`, `workstation`\u2192`pc`, `wifi`\u2192`ap`, `nas`/`san`\u2192`storage`, `voip`\u2192`ipphone`.\n\n```\ncamera cam1 type: dome ip: 192.168.20.11\nserverfarm farm "Server Farm" count: 4\nl3switch core1 tier: core model: "C9500"\n```\n\n---\n\n## 3. Links & annotations\n\nA link\'s appearance follows its type; everything after `:` is order-free.\n\n```\na -- b # copper / ethernet (default solid)\na -- b : fiber 10G # fiber \u2014 orange with slash ticks\na -- b : wireless # dashed\na -- b : serial # leased / WAN circuit\na -- b : poe # Power-over-Ethernet (green + tag)\na -- b : vpn "site-to-site" # dashed tunnel\na == b : lag 40G # aggregated / EtherChannel (double line)\na -- b : trunk vlan: 10,20 1G port: Gi0/1>Gi1/0/24\n```\n\n- `trunk` / `access` \u2014 port mode (a trunk should connect switch-class devices).\n- `vlan: 10` or `vlan: 10,20` \u2014 a single VLAN tints the link (skipping the reserved alarm-red).\n- `1G` / `10G` / `100M` / `40G` \u2014 speed, shown mid-link.\n- `port: near>far` \u2014 interface labels at each end.\n\n---\n\n## 4. Layout modes\n\n```\nlayout: tiered # default \u2014 band by tier: edge \u2192 core \u2192 distribution \u2192 access\nlayout: tree # hierarchical from the root\nlayout: star # hub at center, spokes on a ring\nlayout: ring # nodes on a circle\nlayout: bus # shared backbone\nlayout: mesh # full/partial mesh on a circle\nlayout: spine-leaf # two rows, every leaf auto-meshed to every spine\nlayout: manual # explicit at: x,y per device\ndirection: tb | lr # flow axis for tiered/tree\n```\n\nFor `tiered`, set `tier:` (`edge` / `core` / `distribution` / `access`) on infrastructure; untiered endpoints are placed below their switch. For `spine-leaf`, declare `spines:` and `leaves:` and the spine\u2194leaf links are generated for you.\n\n---\n\n## 5. Boundaries: sites, racks, subnets, VLANs\n\nA device can live inside nested boundary blocks. **Physical** containers (site/rack) draw a solid border; **logical** overlays (subnet/VLAN/zone/DMZ) draw a dashed tinted region.\n\n```\nnetwork "Branch"\n site hq "HQ Building" {\n rack mdf "MDF Rack" {\n firewall fw1 tier: edge\n l3switch core1 tier: core\n }\n }\n subnet lan "10.0.10.0/24" {\n switch a1 tier: access\n pc u1 "User PC" ip: 10.0.10.50\n }\n zone dmz "DMZ" {\n server web\n }\n fw1 -- core1 : 10G\n core1 -- a1 : trunk vlan: 10\n a1 -- u1\n```\n\nA device declared inside a `subnet` whose label is a CIDR has its `ip:` validated \u2014 an address outside the range is a readable error. A bare id on its own line inside a block adds an already-declared device to that group.\n\n---\n\n## 6. Validation & the no-drop guarantee\n\nThe engine guarantees every declared device and link renders \u2014 the dropped-device failure of generic tools is structurally impossible. It also checks:\n\n- **duplicate id** \u2192 error;\n- **unknown kind** \u2192 error with the nearest suggestion (`"swtich" \u2192 did you mean "switch"?`);\n- **link to an undeclared device** \u2192 error;\n- **VLAN id outside 1\u20134094** \u2192 warning (still renders);\n- **device IP outside its subnet CIDR** \u2192 error.\n\nThe SVG `<desc>` records device/link counts, the detected topology class (star / ring / bus / mesh / tree / hierarchical / spine-leaf), and any warnings.\n\n---\n\n## 7. Themes\n\n```\ntheme: default # house "network blue" Cisco-style bodies\ntheme: monochrome # clean line-art for print/audit (link meaning via line-style + tags)\ntheme: dark # Catppuccin Mocha\n```\n\nCJK labels and `\u300C\u2026\u300D` / `"\u2026"` quotes parse cleanly:\n\n```\nnetwork "\u529E\u516C\u5BA4"\n multilayer core1 \u300C\u6838\u5FC3\u4EA4\u6362\u673A\u300D\n poeswitch poe1\n camera cam1 type: dome\n core1 -- poe1 : trunk vlan: 10\n poe1 -- cam1 : poe\n```\n\n---'
2657
2695
  }
2658
2696
  };
2659
2697
 
@@ -2754,11 +2792,23 @@ var PROFILES = {
2754
2792
  timing: {
2755
2793
  type: "timing",
2756
2794
  header: 'timing "Title"',
2757
- mode: "WaveDrom-compatible signals",
2758
- forms: ["CLK: pppppppp", 'DATA: x======x data: ["A", "B"]'],
2759
- prefer: ["Keep wave strings contiguous with no internal spaces.", "Use `data:` labels for bus segments."],
2760
- avoid: ["Avoid unsupported WaveDrom annotation syntax."],
2761
- repair: ["Invalid wave strings usually contain a character outside the timing wave table."]
2795
+ mode: "WaveDrom signals, with clock/run-length shorthands",
2796
+ forms: [
2797
+ "CLK: clock 8 (clock generator, 8 periods \u2014 no char-counting)",
2798
+ "RST: rle 1*2 0*6 (run-length: two 1s then six 0s)",
2799
+ 'DATA: x====x data: ["A","B"] (raw WaveDrom wave + bus labels)'
2800
+ ],
2801
+ prefer: [
2802
+ "Use `clock N` for clocks instead of counting `p` characters.",
2803
+ "Use `rle <state>*<count> ...` for level/data signals instead of counting characters \u2014 it auto-aligns length.",
2804
+ "Drop to a raw wave string only for fine control; keep all signals the same total length so they align.",
2805
+ "Use `data:` labels for bus segments (`=` or digit states)."
2806
+ ],
2807
+ avoid: ["Avoid hand-counting long runs of identical characters \u2014 that is the main source of misaligned waves."],
2808
+ repair: [
2809
+ "Wave-state errors name the offending character and list the valid states.",
2810
+ "If two signals don't line up, make their total cell counts equal (clock N and rle make this easy)."
2811
+ ]
2762
2812
  },
2763
2813
  logic: {
2764
2814
  type: "logic",
@@ -2772,11 +2822,23 @@ var PROFILES = {
2772
2822
  circuit: {
2773
2823
  type: "circuit",
2774
2824
  header: 'circuit "Title" netlist',
2775
- mode: "SPICE-style netlist",
2776
- forms: ["V1 vcc 0 5V", "R1 vcc out 10k", "C1 out 0 100n"],
2777
- prefer: ["Use netlist mode for generated schematics unless geometry is the task.", "Add explicit `type=` when an ID prefix is ambiguous."],
2778
- avoid: ["Avoid positional cursor routing (`wire`, `at:`) for first-shot output."],
2779
- repair: ["If a component type or pin count is ambiguous, make the symbol type explicit."]
2825
+ mode: "SPICE-style netlist (recommended for generation)",
2826
+ forms: [
2827
+ "V1 in 0 5V (component-id node-A node-B value)",
2828
+ "R1 in out 1k",
2829
+ "C1 out 0 100n"
2830
+ ],
2831
+ prefer: [
2832
+ "Always use netlist mode (`... netlist` header). Each line is one component; no spatial state to track.",
2833
+ "Two components that share a node name are wired together. `0`, `gnd`, or `GND` is the ground net.",
2834
+ "The component-id prefix sets the type (R=resistor, C=capacitor, L=inductor, V=source, D=diode, Q=BJT). Add explicit `type=` only when the prefix is ambiguous.",
2835
+ "Optional orientation hint `dir=` (right|left|up|down) nudges a single symbol's facing, e.g. `C1 out 0 100n dir=down` for a shunt cap. Connectivity is unaffected; omit it unless layout readability needs it."
2836
+ ],
2837
+ avoid: [
2838
+ "Avoid positional cursor routing (`wire`, `at:`) \u2014 that mode is for hand-drawing, not generation.",
2839
+ "Do not invent coordinates; the layout engine places components from the net connectivity. `dir=` only rotates a symbol, it does not set position."
2840
+ ],
2841
+ repair: ["If a component type or pin count is ambiguous, make the symbol type explicit with `type=`."]
2780
2842
  },
2781
2843
  blockdiagram: {
2782
2844
  type: "blockdiagram",
@@ -2888,12 +2950,26 @@ var PROFILES = {
2888
2950
  },
2889
2951
  state: {
2890
2952
  type: "state",
2891
- header: 'state "Title"',
2892
- mode: "Schematex statechart core",
2893
- forms: ["initial Start", "Start --> Running : event", "Running --> Done", "final Done"],
2894
- prefer: ["Use `state` header for generated DSL.", "Use Mermaid `stateDiagram-v2` only when adapting Mermaid input."],
2895
- avoid: ["Avoid composite/concurrent-state syntax until the request needs it."],
2896
- repair: ["Use `-->` transitions and a named state between initial/final aliases."]
2953
+ header: "stateDiagram-v2",
2954
+ mode: "Mermaid stateDiagram-v2 (recommended for generation)",
2955
+ forms: [
2956
+ "[*] --> Idle",
2957
+ "Idle --> Running : start",
2958
+ "Running --> Done : finish",
2959
+ "Done --> [*]"
2960
+ ],
2961
+ prefer: [
2962
+ "Use Mermaid `stateDiagram-v2` syntax: `[*]` for the start/end pseudo-states, `-->` for transitions, `: label` for the event/guard.",
2963
+ 'This matches the most common training data, so prefer it over the native `state "Title"` + `initial`/`final` form (which is also accepted).'
2964
+ ],
2965
+ avoid: [
2966
+ "Avoid composite/concurrent-state syntax until the request needs it.",
2967
+ "Do not mix the two styles in one file (e.g. `[*]` together with `initial X`); pick `[*]`."
2968
+ ],
2969
+ repair: [
2970
+ "Every transition uses `-->`; place at least one named state between a `[*]` start and a `[*]` end.",
2971
+ 'If the header is rejected, use exactly `stateDiagram-v2` (or `state "Title"`).'
2972
+ ]
2897
2973
  },
2898
2974
  pid: {
2899
2975
  type: "pid",
@@ -2906,12 +2982,25 @@ var PROFILES = {
2906
2982
  },
2907
2983
  erd: {
2908
2984
  type: "erd",
2909
- header: "erd",
2910
- mode: "table blocks + named cardinality refs",
2911
- forms: ["table User { id int PK; email varchar }", "table Order { id int PK; user_id int FK -> User.id }", "ref Order.user_id many-mandatory -- one-mandatory User.id"],
2912
- prefer: ["Use named cardinality tokens for generated refs.", "Keep FK targets explicit."],
2913
- avoid: ["Avoid Mermaid cardinality glyphs unless converting Mermaid input."],
2914
- repair: ["Unknown cardinality tokens and unterminated table blocks fail validation."]
2985
+ header: "erDiagram",
2986
+ mode: "Mermaid erDiagram (recommended for generation)",
2987
+ forms: [
2988
+ "CUSTOMER ||--o{ ORDER : places",
2989
+ "ORDER {",
2990
+ " int id PK",
2991
+ " string customerId FK",
2992
+ "}"
2993
+ ],
2994
+ prefer: [
2995
+ "Use Mermaid `erDiagram` syntax: relationships `A <card>--<card> B : label` with crow's-foot glyphs (`||` one, `o{` zero-or-many, `|{` one-or-many, `|o` zero-or-one); entity blocks `NAME { type name KEY }` with attributes **type-first** and KEY \u2208 PK/FK/UK.",
2996
+ "Entities are auto-created from relationships; you only need a `{ \u2026 }` block to list attributes.",
2997
+ "This matches the dominant training-data prior. The native `erd` header with `table NAME { name type PK }` + `ref \u2026 many-mandatory -- one-mandatory \u2026` is also accepted."
2998
+ ],
2999
+ avoid: ["Do not mix the two header styles; under `erDiagram`, attributes are type-first (`int id PK`), not name-first."],
3000
+ repair: [
3001
+ "Crow's-foot glyph pairs must be valid (`||`, `|o`, `}o`, `}|` on the left; `||`, `o|`, `o{`, `|{` on the right).",
3002
+ "If the header is rejected, use exactly `erDiagram` (or native `erd`)."
3003
+ ]
2915
3004
  },
2916
3005
  breadboard: {
2917
3006
  type: "breadboard",
@@ -2978,12 +3067,25 @@ var PROFILES = {
2978
3067
  },
2979
3068
  sequence: {
2980
3069
  type: "sequence",
2981
- header: 'sequence "Title"',
2982
- mode: "participants + messages",
2983
- forms: ["actor User", 'participant API as "API"', "User -> API : request", "API --> User : response"],
2984
- prefer: ["Start with participants/messages, then add fragments only if control flow matters."],
2985
- avoid: ["Avoid Mermaid `sequenceDiagram` header; this parser uses `sequence`."],
2986
- repair: ["Unmatched `end`, `else`, or activation statements are validation failures."]
3070
+ header: "sequenceDiagram",
3071
+ mode: "Mermaid sequenceDiagram (recommended for generation)",
3072
+ forms: [
3073
+ "participant Alice",
3074
+ "participant Bob",
3075
+ "Alice->>Bob: request",
3076
+ "Bob-->>Alice: response",
3077
+ "Note over Alice,Bob: handshake"
3078
+ ],
3079
+ prefer: [
3080
+ "Use Mermaid `sequenceDiagram` syntax: `->>` is a sync call, `-->>` a reply/return, `-)` async; `participant`/`actor`, `Note over A,B:`, and `loop`/`alt`/`opt`/`par \u2026 end` all work.",
3081
+ 'This matches the dominant training-data prior; the native `sequence "Title"` header (where `->>` means async) is also accepted.',
3082
+ "Add combined fragments only when control flow matters."
3083
+ ],
3084
+ avoid: ["Do not mix the two header styles; pick `sequenceDiagram` and keep Mermaid arrow meanings throughout."],
3085
+ repair: [
3086
+ "Every fragment (`loop`/`alt`/`opt`/`par`/`break`/`critical`) needs a matching `end`; `else` only inside `alt`.",
3087
+ 'If the header is rejected, use exactly `sequenceDiagram` (or `sequence "Title"`).'
3088
+ ]
2987
3089
  },
2988
3090
  petri: {
2989
3091
  type: "petri",
@@ -3013,29 +3115,29 @@ var PROFILES = {
3013
3115
  network: {
3014
3116
  type: "network",
3015
3117
  header: 'network "Title"',
3016
- mode: "typed device declarations + links + optional boundaries",
3118
+ mode: "device declarations + links (annotations are optional)",
3017
3119
  forms: [
3018
- "layout: tiered",
3019
- 'router r1 "Edge Router"',
3020
- "switch core1 tier: core",
3021
- "camera cam1 type: dome ip: 192.168.20.11",
3022
- "core1 -- poe1 : trunk vlan: 20 1G",
3023
- "poe1 -- cam1 : poe",
3024
- 'subnet cams "192.168.20.0/24" { cam1 poe1 }'
3120
+ 'router r1 "Edge Router" (kind id "label")',
3121
+ 'l3switch core1 "Core" tier: core (optional structural hint)',
3122
+ 'switch acc1 "Access" tier: access',
3123
+ 'pc pc1 "Workstation"',
3124
+ "r1 -- core1 (link: id -- id)",
3125
+ "core1 -- acc1",
3126
+ "acc1 -- pc1"
3025
3127
  ],
3026
3128
  prefer: [
3027
- "Declare every device with its kind before any link references it.",
3028
- "Pick one `layout:` \u2014 tiered (default), tree, star, ring, bus, mesh, spine-leaf, or manual.",
3029
- "Set `tier:` (edge/core/distribution/access) on infrastructure to drive the hierarchical bands.",
3030
- "Annotate links after `:` with link-type (fiber/wireless/serial/poe/vpn/lag), mode (trunk/access), `vlan:`, `port:`, and a speed like 1G/10G."
3129
+ 'Start from the skeleton: `kind id "label"` device lines plus `a -- b` links. That alone renders a complete, valid diagram.',
3130
+ "Declare every device before any link references it.",
3131
+ "Keep the cheap structural hints `layout:` (tiered/tree/star/ring/bus/mesh/spine-leaf) and `tier:` (edge/core/distribution/access) \u2014 they cost little and drive a readable hierarchy. They are recommended, not noise.",
3132
+ "Common kinds: router, switch, l3switch, firewall, ap, server, pc, laptop, camera, nvr, poeswitch, internet, cloud."
3031
3133
  ],
3032
3134
  avoid: [
3033
3135
  "Avoid linking to an undeclared device id.",
3034
- "Avoid VLAN ids outside 1\u20134094 and device IPs outside their subnet's CIDR."
3136
+ 'Add the verbose per-link annotations \u2014 `vlan:`, `port:`, speeds (1G/10G), `trunk`/`access` \u2014 and `subnet "cidr" { ... }` boundaries ONLY when the request explicitly needs them. These don\'t affect the layout and are where generation most often breaks.'
3035
3137
  ],
3036
3138
  repair: [
3037
3139
  "An 'undeclared device' error means a link references an id with no `kind id` declaration \u2014 declare it first.",
3038
- "A subnet-membership error means a device `ip:` falls outside the subnet label CIDR \u2014 fix the IP or the CIDR."
3140
+ "If the layout looks flat/messy, add `layout: tiered` + `tier:` on infrastructure; if unsure about per-link annotations, drop them \u2014 the skeleton always renders."
3039
3141
  ]
3040
3142
  }
3041
3143
  };
@@ -3181,5 +3283,5 @@ function repairHint(type) {
3181
3283
  }
3182
3284
 
3183
3285
  export { DIAGRAM_REGISTRY, DIAGRAM_SINCE, getAllDiagramTypes, getDiagramMeta, getDiagramSince, getExamples, getSyntax, listDiagrams, renderDsl, resolveDiagramType, validateDsl };
3184
- //# sourceMappingURL=chunk-OTSVMKII.js.map
3185
- //# sourceMappingURL=chunk-OTSVMKII.js.map
3286
+ //# sourceMappingURL=chunk-ITUPR7G5.js.map
3287
+ //# sourceMappingURL=chunk-ITUPR7G5.js.map