@diagrammo/dgmo 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.cursorrules +7 -2
  2. package/.github/copilot-instructions.md +7 -2
  3. package/.windsurfrules +7 -2
  4. package/SKILL.md +7 -2
  5. package/dist/advanced.cjs +981 -170
  6. package/dist/advanced.d.cts +35 -1
  7. package/dist/advanced.d.ts +35 -1
  8. package/dist/advanced.js +980 -170
  9. package/dist/auto.cjs +915 -171
  10. package/dist/auto.js +93 -93
  11. package/dist/auto.mjs +915 -171
  12. package/dist/cli.cjs +136 -134
  13. package/dist/index.cjs +981 -170
  14. package/dist/index.d.cts +35 -1
  15. package/dist/index.d.ts +35 -1
  16. package/dist/index.js +980 -170
  17. package/docs/ai-integration.md +7 -2
  18. package/docs/language-reference.md +55 -24
  19. package/package.json +2 -2
  20. package/src/advanced.ts +6 -1
  21. package/src/boxes-and-lines/layout-grouped.ts +909 -0
  22. package/src/boxes-and-lines/layout-search.ts +18 -1
  23. package/src/boxes-and-lines/parser.ts +3 -2
  24. package/src/c4/layout.ts +2 -1
  25. package/src/c4/parser.ts +3 -2
  26. package/src/c4/renderer.ts +3 -2
  27. package/src/cli.ts +68 -0
  28. package/src/er/parser.ts +2 -1
  29. package/src/er/renderer.ts +2 -1
  30. package/src/gantt/parser.ts +3 -5
  31. package/src/gantt/renderer.ts +7 -6
  32. package/src/index.ts +6 -1
  33. package/src/infra/parser.ts +2 -1
  34. package/src/infra/renderer.ts +4 -3
  35. package/src/journey-map/parser.ts +27 -8
  36. package/src/journey-map/renderer.ts +26 -9
  37. package/src/kanban/parser.ts +4 -3
  38. package/src/kanban/renderer.ts +6 -5
  39. package/src/map/completion.ts +116 -0
  40. package/src/map/layout.ts +4 -3
  41. package/src/map/parser.ts +3 -2
  42. package/src/mindmap/parser.ts +4 -3
  43. package/src/mindmap/renderer.ts +2 -1
  44. package/src/org/layout.ts +3 -2
  45. package/src/org/parser.ts +3 -2
  46. package/src/org/renderer.ts +5 -4
  47. package/src/pert/parser.ts +3 -2
  48. package/src/sequence/renderer.ts +10 -12
  49. package/src/sequence/tag-resolution.ts +2 -1
  50. package/src/sitemap/layout.ts +3 -2
  51. package/src/sitemap/parser.ts +36 -2
  52. package/src/sitemap/renderer.ts +12 -6
  53. package/src/timeline/renderer.ts +4 -3
  54. package/src/utils/legend-d3.ts +4 -3
  55. package/src/utils/legend-svg.ts +3 -2
  56. package/src/utils/tag-groups.ts +28 -7
  57. package/src/visualizations/parse.ts +2 -1
@@ -64,6 +64,7 @@ LLMs default to Mermaid / PlantUML habits; DGMO differs. These rules prevent the
64
64
  - **Show-everything is the default.** Every label / value / percent renders by default. Emit `no-name` / `no-value` / `no-percent` / `no-*` ONLY when the user explicitly asks to hide something — never defensively.
65
65
  - **`//` comments only** (never `#`). **Indentation closes blocks** — never `end`.
66
66
  - **Declare before reference.** An edge target must be declared on a prior line; put metadata and edges on/under one declaration to avoid `Duplicate node` warnings.
67
+ - **No reference scaffolding in output.** Emit only DGMO source. This doc is organized with HTML-comment anchors (the `TYPE`, `TIPS`, and `AI-CORE` markers, each wrapped in comment delimiters); never copy any such `<!-- … -->` comment into a diagram. They mark sections of the docs, not DGMO syntax; the parser flags a stray HTML comment as an `Unexpected line` warning. (DGMO's only comment form is `//`.)
67
68
 
68
69
  Two traps in the *other* direction (DGMO wants a colon / a space where you might not expect):
69
70
 
@@ -90,8 +91,12 @@ Billing t: Product
90
91
 
91
92
  Valid markup is the floor, not the goal. A good diagram reads at a glance. Apply these unless the prompt says otherwise:
92
93
 
93
- - **Title it.** Put a short title on the type-declaration line (`flowchart Checkout Flow`, `boxes-and-lines Service Map`) so the diagram is self-describing.
94
- - **Color by grouping, not at random.** When items fall into categories, declare a tag group and assign members so each category shares one color — far clearer than ad-hoc per-node colors. Use the tag-group syntax shown in the per-type section below (declare `tag Team as t`, indent the values — a trailing color is optional, bare values auto-pick a palette color — then assign `Node t: Team`). Only the 11 named palette colors exist.
94
+ <!-- TITLE start -->
95
+ - **Always title it.** Every diagram gets a short title on the type-declaration line (`flowchart Checkout Flow`, `sequence Checkout`, `boxes-and-lines Service Map`) so it is self-describing — never leave the bare type keyword alone. Infer a fitting title from the request when the user gives none.
96
+ <!-- TITLE end -->
97
+ <!-- CATEGORIZE start -->
98
+ - **Categorize and color — by default, not only when obvious.** Before drawing, find the axis that sorts the items into kinds and color by it: layer (frontend / backend / data), role (client / service / datastore), trust zone (internal / external / third-party), status (done / active / blocked), owner/team, or read-path vs write-path. Almost every diagram has such an axis — actively look for one rather than leaving everything monochrome. Express it with a **tag group**, never ad-hoc per-node colors: declare `tag <Axis> as t` (the name is a single word — `tag TrustZone as tz` — or quote a multi-word name: `tag "Trust Zone" as tz`), indent the category values (a trailing color is optional — bare values auto-pick a palette color), set `active-tag <Axis>`, then assign each item `Node t: <Category>` (see the tag-group syntax in the per-type section below). Only the 11 named palette colors exist, and they re-resolve per palette/theme. Color the grouping so the categories — and the boundaries between them — read at a glance. **Buckets, not name tags — never 1:1.** A tag group must have *fewer* values than it has members: each color should bucket two or more items so the palette compresses the diagram into a few meaningful kinds (aim for ~2–4 categories, and keep distinct colors well under half the item count). If you find yourself giving nearly every item its own value, you've enumerated, not categorized — merge the singletons up a level until each color groups at least two (a `cache` and a `database` are both `datastore`; a caller and a gateway are both `client`; two microservices are both `service`). One color per item is the same visual noise as random colors — the grouping only earns its place when a color means "these belong together." Leave items uncolored only when they genuinely form a single undifferentiated kind, or the user asked for no color.
99
+ <!-- CATEGORIZE end -->
95
100
  - **Keep labels short.** A few words per node. Move detail into notes or metadata, never a full sentence inside a label.
96
101
  - **Let the defaults show.** Don't add `no-*` opt-outs unless the user asked to hide or disable something — they strip helpful labels, values, and color.
97
102
  - **Pick a fitting direction.** Top-to-bottom for hierarchies and processes; left-to-right for pipelines and flows (where the type supports a direction).
@@ -60,6 +60,7 @@ LLMs default to Mermaid / PlantUML habits; DGMO differs. These rules prevent the
60
60
  - **Show-everything is the default.** Every label / value / percent renders by default. Emit `no-name` / `no-value` / `no-percent` / `no-*` ONLY when the user explicitly asks to hide something — never defensively.
61
61
  - **`//` comments only** (never `#`). **Indentation closes blocks** — never `end`.
62
62
  - **Declare before reference.** An edge target must be declared on a prior line; put metadata and edges on/under one declaration to avoid `Duplicate node` warnings.
63
+ - **No reference scaffolding in output.** Emit only DGMO source. This doc is organized with HTML-comment anchors (the `TYPE`, `TIPS`, and `AI-CORE` markers, each wrapped in comment delimiters); never copy any such `<!-- … -->` comment into a diagram. They mark sections of the docs, not DGMO syntax; the parser flags a stray HTML comment as an `Unexpected line` warning. (DGMO's only comment form is `//`.)
63
64
 
64
65
  Two traps in the *other* direction (DGMO wants a colon / a space where you might not expect):
65
66
 
@@ -88,8 +89,12 @@ Billing t: Product
88
89
 
89
90
  Valid markup is the floor, not the goal. A good diagram reads at a glance. Apply these unless the prompt says otherwise:
90
91
 
91
- - **Title it.** Put a short title on the type-declaration line (`flowchart Checkout Flow`, `boxes-and-lines Service Map`) so the diagram is self-describing.
92
- - **Color by grouping, not at random.** When items fall into categories, declare a tag group and assign members so each category shares one color — far clearer than ad-hoc per-node colors. Use the tag-group syntax shown in the per-type section below (declare `tag Team as t`, indent the values — a trailing color is optional, bare values auto-pick a palette color — then assign `Node t: Team`). Only the 11 named palette colors exist.
92
+ <!-- TITLE start -->
93
+ - **Always title it.** Every diagram gets a short title on the type-declaration line (`flowchart Checkout Flow`, `sequence Checkout`, `boxes-and-lines Service Map`) so it is self-describing — never leave the bare type keyword alone. Infer a fitting title from the request when the user gives none.
94
+ <!-- TITLE end -->
95
+ <!-- CATEGORIZE start -->
96
+ - **Categorize and color — by default, not only when obvious.** Before drawing, find the axis that sorts the items into kinds and color by it: layer (frontend / backend / data), role (client / service / datastore), trust zone (internal / external / third-party), status (done / active / blocked), owner/team, or read-path vs write-path. Almost every diagram has such an axis — actively look for one rather than leaving everything monochrome. Express it with a **tag group**, never ad-hoc per-node colors: declare `tag <Axis> as t` (the name is a single word — `tag TrustZone as tz` — or quote a multi-word name: `tag "Trust Zone" as tz`), indent the category values (a trailing color is optional — bare values auto-pick a palette color), set `active-tag <Axis>`, then assign each item `Node t: <Category>` (see the tag-group syntax in the per-type section below). Only the 11 named palette colors exist, and they re-resolve per palette/theme. Color the grouping so the categories — and the boundaries between them — read at a glance. **Buckets, not name tags — never 1:1.** A tag group must have *fewer* values than it has members: each color should bucket two or more items so the palette compresses the diagram into a few meaningful kinds (aim for ~2–4 categories, and keep distinct colors well under half the item count). If you find yourself giving nearly every item its own value, you've enumerated, not categorized — merge the singletons up a level until each color groups at least two (a `cache` and a `database` are both `datastore`; a caller and a gateway are both `client`; two microservices are both `service`). One color per item is the same visual noise as random colors — the grouping only earns its place when a color means "these belong together." Leave items uncolored only when they genuinely form a single undifferentiated kind, or the user asked for no color.
97
+ <!-- CATEGORIZE end -->
93
98
  - **Keep labels short.** A few words per node. Move detail into notes or metadata, never a full sentence inside a label.
94
99
  - **Let the defaults show.** Don't add `no-*` opt-outs unless the user asked to hide or disable something — they strip helpful labels, values, and color.
95
100
  - **Pick a fitting direction.** Top-to-bottom for hierarchies and processes; left-to-right for pipelines and flows (where the type supports a direction).
@@ -502,7 +507,7 @@ rarely benefit. Aliases should aid comprehension, not obscure it.
502
507
  <!-- TYPE:sequence -->
503
508
 
504
509
  <!-- TIPS start -->
505
- **Styling tips:** stay terse — participants are created by the messages that name them, so a plain flow needs only the arrow lines (no participant declarations). Skip `is a TYPE`: the glyph is inferred from the name (`User`→actor, `*DB`→database, `Redis`→cache, `Kafka`→queue); add a declaration, a `[Group]`, or `position: N` only when it genuinely aids reading order or grouping, never as boilerplate. Give each participant a short role name; group related exchanges under `== Section ==` dividers rather than a wall of arrows; label a return arrow only when its value matters (unlabeled returns are auto-pruned). Drop a `note` where something subtle happens. When participants fall into trust or role categories, color the participants (not the messages) by category with a tag group using the named palette colors, so the boundary reads at a glance.
510
+ **Styling tips:** stay terse — participants are created by the messages that name them, so a plain flow needs only the arrow lines (no participant declarations). Skip `is a TYPE`: the glyph is inferred from the name (`User`→actor, `*DB`→database, `Redis`→cache, `Kafka`→queue); add a declaration, a `[Group]`, or `position: N` only when it genuinely aids reading order or grouping, never as boilerplate. Give each participant a short role name. Reach for `== Section ==` dividers only when the flow splits into **two or more** distinct phases (e.g. `== Authentication ==` then `== Checkout ==`) — a single divider over one run of arrows just repeats the diagram's subject and adds a redundant band, so a one-phase flow should have no dividers at all. Label a return arrow only when its value matters (unlabeled returns are auto-pruned). Drop a `note` where something subtle happens. Categorize the participants and color them (not the messages) by that category with a tag group using the named palette colors — client vs service vs datastore, trust zones (internal / external), or owning team are almost always present, so default to coloring by one rather than leaving the lifelines monochrome, and the boundaries read at a glance.
506
511
  <!-- TIPS end -->
507
512
 
508
513
  ### 2.1 Participants
@@ -1279,7 +1284,7 @@ Optional label: `--|> Vessel : extends` (colon optional before label)
1279
1284
  <!-- TYPE:kanban -->
1280
1285
 
1281
1286
  <!-- TIPS start -->
1282
- **Styling tips:** name columns for workflow stages (`Todo`, `Doing`, `Done`); keep card titles to a short task phrase; color cards by owner or priority with a tag group; let column length convey WIP instead of annotating counts. If you use a tag group, tag EVERY card — an untagged card currently inherits the first tag value (mislabeling it), so omit the tag group entirely for an uncolored board.
1287
+ **Styling tips:** Color EVERY column — write a lowercase color word right after the closing bracket (`[Done] green`). Don't match on column names; reason about what each column *means* for a card sitting in it, then pick the color whose everyday connotation fits, so the board reads at a glance. The guiding sense: green = good / finished / success, red = bad / stuck / needs attention, yellow = waiting / caution / in review, blue = active work in motion, gray = inert / not yet started / parked. Apply that to whatever columns exist — e.g. a terminal success column reads green even if it's called `Shipped`, `Hired`, or `Live`; a column meaning a card is stuck reads red whether it's `Blocked`, `On Hold`, or `Rejected`; an early holding column reads gray whether it's `Backlog`, `Ideas`, or `Inbox`. When several columns share a sense (two active-work stages), it's fine to keep a couple uncolored or reuse a color rather than force eleven distinct hues. Name columns for workflow stages, keep card titles to a short task phrase, and let column length convey WIP instead of annotating counts. Card color is separate from column color: color cards by owner or priority with a tag group, and if you use one, tag EVERY card — an untagged card currently inherits the first tag value (mislabeling it), so omit the tag group entirely for cards you want left uncolored.
1283
1288
  <!-- TIPS end -->
1284
1289
 
1285
1290
  ### 10.1 Declaration
@@ -1328,7 +1333,7 @@ tag Crew as c
1328
1333
  <!-- TYPE:sitemap -->
1329
1334
 
1330
1335
  <!-- TIPS start -->
1331
- **Styling tips:** Connect pages by indenting `-> Target` lines under a parent page (not a top-level `Home -> Products`, which becomes one box), and declare each target as its own page too — bare indentation alone draws no connectors. Default flow is left-to-right; use `direction-tb` for a vertical tree. Keep labels to short page names.
1336
+ **Styling tips:** Build a real navigation graph, not a flat column of boxes. Three things make a sitemap read well, and a good one uses all three. (1) **Cluster pages into `[Area]` group sections** when the site has distinct areas — e.g. `[Shop]`, `[Account]`, `[Admin]` — indenting each page under its bracket header, and leave only the true entry page (`Home` / `Landing`) at the top level. (2) **Show how a visitor moves** with an indented labeled arrow under the source page: `-submit-> Home`, `-checkout-> Payment`, `-back-> Dashboard`, where the label is the action or link text. Every arrow target must be declared as its own page; an arrow can point at a whole area with `-> [Admin]`. If pages share no links you've drawn a list, not a sitemap — connect them. (3) **Classify pages with a colored tag group**, so the legend organizes the map by meaning rather than by position. Declare a facet with colored values and assign it to every page in same-line metadata — access level works well: `tag Access` with `Public green`, `Member blue`, `Admin red`, then `Pricing Access: Public`; or a functional facet (`Browse`, `Purchase`, `Admin`). A second tag group for page kind (`Landing purple`, `Form orange`, `Content cyan`) adds a second color dimension. Reason about which facet actually distinguishes this site's pages rather than reaching for a fixed list. Keep the tree shallow and order siblings by prominence.
1332
1337
  <!-- TIPS end -->
1333
1338
 
1334
1339
  ### 11.1 Declaration
@@ -1541,7 +1546,7 @@ want; anything left un-chained starts together at the parent's start.
1541
1546
  <!-- TYPE:pert -->
1542
1547
 
1543
1548
  <!-- TIPS start -->
1544
- **Styling tips:** Give each task a duration and wire dependencies with `-> next`. Provide a single (most-likely) estimate plus `default-confidence medium` to auto-expand to a 3-point estimate, or give optimistic/likely/pessimistic explicitly. The critical path and slack are computed for you.
1549
+ **Styling tips:** Name each task as a short action and wire the real finish-to-start dependencies — branch and merge them so the critical path and per-task slack become meaningful. Give one most-likely estimate per task (the engine derives optimistic/pessimistic), or explicit O/M/P when you know them.
1545
1550
  <!-- TIPS end -->
1546
1551
 
1547
1552
  PERT diagrams visualize project networks with three-point duration estimates, surfacing critical path, slack, and project μ/σ. Each activity renders as a node card (rectangle, or diamond for milestones); dependencies are arrows between them. Monte Carlo simulation runs automatically whenever any activity carries duration data.
@@ -1707,7 +1712,7 @@ See spec §13A for full date-anchoring semantics, S-curve axes, and diagnostic c
1707
1712
  <!-- TYPE:boxes-and-lines -->
1708
1713
 
1709
1714
  <!-- TIPS start -->
1710
- **Styling tips:** Write each connection as `Source -> Target` on its own line; boxes are auto-created from the labels. Group related boxes with a `[Group]` bracket and indent its members. Keep every box label a short noun phrase.
1715
+ **Styling tips:** Show one clear direction of flow, label each edge with the relationship rather than a bare arrow, and keep every box a short noun phrase. **Color by category with a tag group:** declare a `tag <Facet> as <alias>` with a distinct color per value, then assign each box `<alias>: <Value>` so like things share a color and unlike things visibly differ — pick the facet that actually divides this system (tier: `Client`/`Edge`/`Compute`/`Data`, ownership, internal vs external, stateful vs stateless) rather than coloring at random. **Organize when it gets busy:** with more than ~4 boxes there is almost always a structure to surface — cluster the boxes that belong together into `[Group]` sections (a backend tier, a region, a subsystem) and draw edges to the group with `-> [Group]` where a whole cluster is the target. A flat row of many boxes is a missed opportunity; derive the grouping from how the parts relate. The `[Group]` brackets handle spatial clustering and the tag group handles color — use both, and they can cut across each other (e.g. group by subsystem, color by tier).
1711
1716
  <!-- TIPS end -->
1712
1717
 
1713
1718
  ### 13.1 Declaration
@@ -1843,6 +1848,30 @@ Flagship -> Sloop
1843
1848
  legend shows a gradient capsule; boxes without a `value:` get a neutral fill.
1844
1849
  - `show-values` additionally prints each box's number as text.
1845
1850
 
1851
+ ### 13.9 Tag groups (categorical color)
1852
+
1853
+ Color boxes by a category. Declare a `tag <Facet> as <alias>` group (§1.3) with one color per value — **values are indented under the `tag` header**, one per line, color as a trailing word — then assign each box `<alias>: <Value>` in its metadata. Do **not** write the values as `<alias> <Value>` lines; that is not the grammar.
1854
+
1855
+ ```
1856
+ boxes-and-lines Service Map
1857
+ tag Tier as t
1858
+ Client blue
1859
+ Edge teal
1860
+ Compute green
1861
+ Data purple
1862
+
1863
+ [Client]
1864
+ Web App t: Client
1865
+ [Edge]
1866
+ API Gateway t: Edge
1867
+ [Compute]
1868
+ Auth Service t: Compute
1869
+ [Data]
1870
+ Postgres t: Data
1871
+ ```
1872
+
1873
+ The tag group (color) composes with `[Group]` clustering (spatial) and can cut across it — group by subsystem, color by tier. The group must be declared before any content line (§1.3).
1874
+
1846
1875
  ---
1847
1876
 
1848
1877
  ## 15. Timeline Diagrams
@@ -2085,7 +2114,7 @@ Point names render by default. Use `no-name` to hide them.
2085
2114
  <!-- TYPE:heatmap -->
2086
2115
 
2087
2116
  <!-- TIPS start -->
2088
- **Styling tips:** Declare the column headers in a `columns` block, then one row per item with space-separated numeric values (`Dana 5 2 4 3 2`). The values drive the color scale, so keep them on a consistent range.
2117
+ **Styling tips:** Sort rows and columns by their totals (not alphabetically) so the strongest cells gather in one corner and the high-to-low pattern reads at a glance; keep every cell on the same numeric scale so the colors stay comparable.
2089
2118
  <!-- TIPS end -->
2090
2119
 
2091
2120
  **Columns** — follows §15 Rule B (prefer the indented block for multiple columns):
@@ -2110,7 +2139,7 @@ RowLabel 5 4 3
2110
2139
  <!-- TYPE:function -->
2111
2140
 
2112
2141
  <!-- TIPS start -->
2113
- **Styling tips:** Set the domain once with `x <min> to <max>`. Give each curve a short plain-text name and put the math after the colon (`Sine blue: sin(x)`); the text before the colon is a label, so prefer a word like `Sine` over repeating the expression.
2142
+ **Styling tips:** Pick a domain (`x <min> to <max>`) that frames the interesting behavior and keep to a few curves for legibility. Give each curve a short readable name before the colon (`Sine: sin(x)`), not the expression repeated.
2114
2143
  <!-- TIPS end -->
2115
2144
 
2116
2145
  ```
@@ -2134,7 +2163,7 @@ The colon between name and expression is **required** — both sides can contain
2134
2163
  <!-- TYPE:sankey -->
2135
2164
 
2136
2165
  <!-- TIPS start -->
2137
- **Styling tips:** Write each flow as `Source -> Target value` (space-separated value, no comma). The value sets the band width; flow reads left-to-right, so order sources upstream of targets.
2166
+ **Styling tips:** Feed flows in process order (left to right) and let each connection’s value set its band width — the layout already orders nodes to reduce crossings. Fold flows into one "Other" band only when many are individually negligible; never rename a single meaningful node.
2138
2167
  <!-- TIPS end -->
2139
2168
 
2140
2169
  **Tree structure (indented, space-separated):**
@@ -2159,7 +2188,7 @@ Source -- Target 2000
2159
2188
  <!-- TYPE:chord -->
2160
2189
 
2161
2190
  <!-- TIPS start -->
2162
- **Styling tips:** Write each connection as `Source -> Target value` (or `--` for undirected). Every node becomes an arc on the circle and each value sets the ribbon thickness — good for dense many-to-many relationships.
2191
+ **Styling tips:** Chord shines for genuinely reciprocal, many-to-many relationships; if your flows are mostly one-directional or hub-and-spoke, a sankey reads clearer. List heavily-connected nodes consecutively — arcs follow first-appearance order, so this keeps the thickest ribbons short.
2163
2192
  <!-- TIPS end -->
2164
2193
 
2165
2194
  ```
@@ -2194,7 +2223,7 @@ Purchases 200
2194
2223
  <!-- TYPE:slope -->
2195
2224
 
2196
2225
  <!-- TIPS start -->
2197
- **Styling tips:** Declare exactly two periods with `period <A> <B>`, then one line per item as `Label <from> <to>`. Slope charts compare two points in time only — use a line/bar chart for more periods.
2226
+ **Styling tips:** Slope auto-labels both endpoints and colors each line — recolor only when one line is the story, then color just that mover and leave the rest to the default palette. It compares exactly two periods; use a line chart for more.
2198
2227
  <!-- TIPS end -->
2199
2228
 
2200
2229
  ```
@@ -2222,7 +2251,7 @@ Roberts 12 52
2222
2251
  <!-- TYPE:wordcloud -->
2223
2252
 
2224
2253
  <!-- TIPS start -->
2225
- **Styling tips:** One `term weight` per line (`TypeScript 95`); the weight drives font size, so spread weights across a wide range for visual contrast. Keep terms to single words or short phrases.
2254
+ **Styling tips:** Make the largest and smallest terms differ enough in size to read at a glance — set an explicit `size <min> <max>` when raw weights are bunched together. Keep to the signal terms: cap the list (~30–40) and drop filler words.
2226
2255
  <!-- TIPS end -->
2227
2256
 
2228
2257
  ```
@@ -2243,7 +2272,7 @@ navigation 88
2243
2272
  <!-- TYPE:arc -->
2244
2273
 
2245
2274
  <!-- TIPS start -->
2246
- **Styling tips:** Write each link as `Source -> Target value`; nodes sit on a single axis and arcs are sized by value. Order nodes so the busiest connections form short arcs where possible.
2275
+ **Styling tips:** Set `order appearance` and list links so the busiest pairs sit next to each other — heavy connections then read as short arcs hugging the axis instead of long sweeps (otherwise placement is automatic and row order is ignored).
2247
2276
  <!-- TIPS end -->
2248
2277
 
2249
2278
  ```
@@ -2264,7 +2293,7 @@ order group
2264
2293
  <!-- TYPE:venn -->
2265
2294
 
2266
2295
  <!-- TIPS start -->
2267
- **Styling tips:** Declare each set as `Name as <alias> <color>`, then intersections as `<alias> + <alias> <count>` (and a triple `a + b + c <count>`). Note: all circles render the same size — overlap labels, not circle area, convey the numbers.
2296
+ **Styling tips:** Use 2–3 sets and write the count of each meaningful overlap directly on its intersection; circle area is NOT proportional, so the numbers — not the sizes — carry the comparison.
2268
2297
  <!-- TIPS end -->
2269
2298
 
2270
2299
  ```
@@ -2287,7 +2316,7 @@ sw + nav + lead Legendary Pirates
2287
2316
  <!-- TYPE:quadrant -->
2288
2317
 
2289
2318
  <!-- TIPS start -->
2290
- **Styling tips:** Plot points as `Label x y` (space-separated, no comma between x and y). Normalize raw metrics to a 0–1 range yourself — axes are not auto-scaled. Name the four regions with `top-left`/`top-right`/`bottom-left`/`bottom-right` + a color so each quadrant reads as a category.
2319
+ **Styling tips:** Name the four quadrants as meaningful categories (not just positions) and call out the outliers; normalize values to 0–1 so the points spread across the whole space.
2291
2320
  <!-- TIPS end -->
2292
2321
 
2293
2322
  ```
@@ -2447,7 +2476,7 @@ Universal options (`palette`, `theme`) apply as elsewhere.
2447
2476
  <!-- TYPE:wireframe -->
2448
2477
 
2449
2478
  <!-- TIPS start -->
2450
- **Styling tips:** There is no link element — render hyperlinks as bare text (`Forgot password?`), NOT `[brackets]` (which is a text INPUT). Use `#`/`##` for headings, `(Label) primary` for the main button, and the `password` flag to mask a field.
2479
+ **Styling tips:** Keep it low-fidelity — boxes, labels, and one primary action `(Sign in) primary` per screen, grouped by region. Links are bare text (`Forgot password?`); `[brackets]` is an input field.
2451
2480
  <!-- TIPS end -->
2452
2481
 
2453
2482
  Wireframe diagrams use **visual-mnemonic syntax** where bracket characters communicate element type.
@@ -2585,7 +2614,7 @@ wireframe Login Page
2585
2614
  <!-- TYPE:tech-radar -->
2586
2615
 
2587
2616
  <!-- TIPS start -->
2588
- **Styling tips:** Use exactly four quadrants and place each item in one with `quadrant: <name>`; every blip needs a `ring:`. When the source is a numeric score rather than adopt/trial/assess/hold, bucket the scores into rings yourself and note the raw value in the blip description.
2617
+ **Styling tips:** Group blips into the four domain quadrants and let the rings carry adoption stage (Adopt→Hold); annotate movement with a `trend`. When the source is a numeric score, bucket it into a ring and keep the number in the description.
2589
2618
  <!-- TIPS end -->
2590
2619
 
2591
2620
  ```
@@ -2657,7 +2686,7 @@ Blips receive sequential global numbers. Order: quadrants clockwise (top-left
2657
2686
  <!-- TYPE:cycle -->
2658
2687
 
2659
2688
  <!-- TIPS start -->
2660
- **Styling tips:** List the stages in order — the renderer closes the loop back to the first automatically, so do not add a wrap-around edge. An indented line under a stage becomes its description.
2689
+ **Styling tips:** Aim for 3–6 stages so the loop stays legible; name each as a short step and let the closed ring imply repetition (no wrap-around edge needed). An indented line adds a description.
2661
2690
  <!-- TIPS end -->
2662
2691
 
2663
2692
  Circular process flows where nodes sit on a ring and directed edges connect each to the next, wrapping from last back to first. Common use: OODA loops, PDCA, product lifecycles, continuous improvement.
@@ -2794,7 +2823,7 @@ Act red
2794
2823
  <!-- TYPE:journey-map -->
2795
2824
 
2796
2825
  <!-- TIPS start -->
2797
- **Styling tips:** Write each stage as `Stage score: <1-5>` with an indented `description:` for the action; add `persona <name>` once at the top. The scores draw the emotion curve, so vary them to show highs and lows.
2826
+ **Styling tips:** A journey map is a story about one specific person, so author it richly even when the prompt is thin — fill the gaps with plausible, concrete detail rather than leaving it skeletal. **Persona:** give them a real first name, a color, and a short background — `persona Gina green`, then a sentence or 2–3 indented bullet (`- …`) lines covering who they are, their goal, and their constraints. Always color the persona (trailing color word after the name, or `persona Name color: green`) so the protagonist's card stands out. When the prompt implies a customer archetype, let the name's first letter echo it (a fanatic → Fred, a casual user → Carl, a beginner → Betty) — a light touch, never forced. **Structure:** organize the journey into 2–4 `[Phase]` sections, each holding 1–3 steps — and never one step per phase across the board. If every phase has exactly one step you've just bracketed a flat list; that 1:1 mapping is wrong — either give phases multiple steps or drop the brackets and let the steps run flat. Give every step a 1–5 `score:` (and a single-word `emotion:` at the highs and lows) so the mood curve has shape. **Depth per step:** every step gets a `description:` (what actually happens there) plus 2–5 annotations drawn from `pain:` (friction, red), `opportunity:` (a fix, green), and `thought:` (what they're thinking, italic) — choose the ones that genuinely fit that moment; a smooth early step might be all `thought:`/`opportunity:`, a trough heavy on `pain:`. Don't pad every step identically — let the friction cluster where the score dips so the arc reads true.
2798
2827
  <!-- TIPS end -->
2799
2828
 
2800
2829
  Persona-centric mood landscapes. Steps carry a 1–5 score and optional emotion label; the renderer draws an emotion curve over phase-grouped step cards. **Declaration is required** — the `journey-map` keyword must appear on the first line (no inference, to avoid colliding with kanban's `[Column]` + indented items shape).
@@ -2923,7 +2952,7 @@ Got resolution score: 5, emotion: Relieved
2923
2952
  <!-- TYPE:pyramid -->
2924
2953
 
2925
2954
  <!-- TIPS start -->
2926
- **Styling tips:** Source order is apex-first (first line = top). For a funnel-shaped dataset, list the smallest stage first so the widest tier lands at the base. Bands are uniform height (not value-proportional) — put counts in an indented description.
2955
+ **Styling tips:** Keep to a few tiers (3–5), widest at the base, and label each tier with its value — bands are uniform height, so the number carries the magnitude. For a funnel-shaped dataset, list the smallest stage first.
2927
2956
  <!-- TIPS end -->
2928
2957
 
2929
2958
  Hierarchical pyramid visualization with stacked layers, descriptions, and optional per-layer color. Source order reads apex-first (top of file = top of pyramid).
@@ -2990,7 +3019,7 @@ When descriptions don't fit a layer's band the renderer wraps at the column edge
2990
3019
  <!-- TYPE:ring -->
2991
3020
 
2992
3021
  <!-- TIPS start -->
2993
- **Styling tips:** Source order is innermost→outermost (first line = center disc). Bands are uniform thickness, not value-proportional; put the value in an indented description line. For a true part-of-whole proportion use pie or funnel instead.
3022
+ **Styling tips:** Order rings core→outward by hierarchy, not by size — band thickness is uniform and carries no proportional meaning (use pie/funnel for part-of-whole). Keep any value you want read at a glance in the ring’s own label.
2994
3023
  <!-- TIPS end -->
2995
3024
 
2996
3025
  Concentric-ring visualization for nested or hierarchical categories. Source order reads core-out: top of file = innermost element (rendered as a filled disc), last line = outermost ring. Min 2 layers, max 15.
@@ -3063,7 +3092,7 @@ When ring band thickness would force the in-band label below the readable floor
3063
3092
  <!-- TYPE:raci -->
3064
3093
 
3065
3094
  <!-- TIPS start -->
3066
- **Styling tips:** Put each task at indent-0 and its role cells one level in (`Role: A`/`R`/`C`/`I`); declare the roles with a top-level `roles <A>, <B>, ...` line. Give every task exactly one A and one R to avoid lint warnings. A `[Phase]` header is optional — only use the indented `roles` block form when a `[Phase]` header follows.
3095
+ **Styling tips:** Put each task at indent-0 with its `Role: A/R/C/I` cells indented one level under it — never nest tasks inside the `roles` block (it swallows them). Give every task exactly one Accountable (ideally one Responsible) and keep roles small (≤~6) so the matrix stays scannable.
3067
3096
  <!-- TIPS end -->
3068
3097
 
3069
3098
  A tasks × roles responsibility matrix with author-time linting. **One chart type — `raci` — covers all three variants.** Variant is inferred from the markers used; an optional `variant-*` directive locks it explicitly.
@@ -3159,7 +3188,7 @@ Markers in cells are always **rendered in canonical alphabet order** (`R A C I`,
3159
3188
  <!-- TYPE:map -->
3160
3189
 
3161
3190
  <!-- TIPS start -->
3162
- **Styling tips:** the zero-config map already looks good — name places and stop. When POIs fall into categories, tag them so each category gets its own color; keep place labels to the place name; leave region colorize and coastlines on unless the user asks to hide them. **For routes/flows from a hub** (e.g. an airport's daily flights, a distribution center's shipments), write ONE edge per line and repeat the origin — `JFK ~daily~> LAX`, `JFK ~daily~> LHR`, … — never indented edges (those error). Use **arcs** (`~>`) for flights and long-haul links so the spokes separate; the connector label carries the relationship (`~daily~>`, `~2x daily~>`). Endpoints auto-create POIs, so don't add separate `poi` lines for places that already appear in an edge. Reach for a `route` block only when the trip is an **ordered voyage** that continues stop→stop (a cruise itinerary), not a set of independent routes from one origin.
3191
+ **Styling tips:** the zero-config map already looks good — name places and stop. When POIs fall into categories, tag them so each category gets its own color; keep place labels to the place name; leave region colorize and coastlines on unless the user asks to hide them. **For flights and airport routes, use IATA codes, not city names** — `LHR ~> JFK`, `LHR ~> DXB`, `LHR ~> SIN`, `LHR ~> HND` — the bundled airport set (large international hubs + all US commercial airports) resolves them to the right coordinates and labels them with the code. **For cities, use the exact canonical name**: "New York City" (NOT "New York"), "Washington, D.C.", etc. — a name the gazetteer doesn't have **silently drops that point** and the map just reframes around the rest, so it looks fine but is wrong. When unsure of the exact token, look it up: `dgmo map search "<place>"` (or the `lookup_map_location` MCP tool) returns the city name or airport code to paste; fall back to coordinates (`poi Name as 40.71,-74.0`) for anything not found. **For routes/flows from a hub** (an airport's daily flights, a distribution center's shipments), write ONE edge per line and repeat the origin — never indented edges (those error). Use **arcs** (`~>`) for flights and long-haul links so the spokes separate; the connector label carries the relationship (`~daily~>`, `~2x daily~>`). Endpoints auto-create POIs, so don't add separate `poi` lines for places already in an edge. Reach for a `route` block only when the trip is an **ordered voyage** that continues stop→stop (a cruise itinerary), not a set of independent routes from one origin.
3163
3192
  <!-- TIPS end -->
3164
3193
 
3165
3194
  Geographic concept maps: highlight/shade political subdivisions, drop points of interest (POIs), and connect them with routes or edges. For "share a concept" business maps, not cartography. Renders at a fixed, auto-fit position — no pan/zoom. Basemap and viewport are **inferred from the content you reference** — most maps need no directives. v1 boundaries: world countries + US states.
@@ -3302,6 +3331,8 @@ cove -> hav l: March # the LINE turns green
3302
3331
  - **Name + scope** (readable): `Georgia US value: 5` → the state, `Georgia GE value: 5` → the country.
3303
3332
  - The redundant `Georgia US-GA` still works but isn't needed (a mismatched code like `Georgia US-CA` is rejected). A bare ambiguous `Georgia` follows the inferred US-scope signal and warns with both fixes named.
3304
3333
  - **IATA airport codes** resolve to airport coordinates — `poi JFK`, `route JFK -> LAX` — with no new syntax (large international hubs + all US scheduled-commercial airports). Case-insensitive (`jfk`/`JFK`). Airports are the **lowest-precedence** identifier: a token that is both a city and a code resolves to the **city** (`Ufa` → the city, not UFA airport), with a hint naming the airport. Resolution is by **code only** (never by airport name); the POI label is the typed code. An unknown three-letter code errors with an `as <CODE>` coordinates hint.
3334
+ - **A city name must match the gazetteer's canonical form** — `New York City`, not `New York`; `Washington, D.C.`, not `Washington`. An unrecognized name is dropped (with a did-you-mean note) and the map reframes around the places that *did* resolve, so the result can look complete but be missing a point. Use the exact name or coordinates.
3335
+ - **Discover the exact token** with the lookup surface rather than guessing — `dgmo map search "<place>"` (CLI; `--json` for machine output) or the `lookup_map_location` MCP tool. It substring-searches cities **and** the bundled airports and returns the precise token to paste (e.g. `york` → `New York City`; `heathrow` → `LHR`). There is intentionally **no exhaustive printed list** — the gazetteer holds thousands of cities plus ~1,500 airports; search is the interface.
3305
3336
  - Positional coordinates are the escape hatch for anything missing/ambiguous (including forcing an airport over a colliding city: `poi 54.56 55.87 as UFA`).
3306
3337
 
3307
3338
  ### Directives & reserved keys
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diagrammo/dgmo",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "DGMO diagram markup language — parser, renderer, and color system",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -134,7 +134,7 @@
134
134
  "check:deadcode": "knip",
135
135
  "check:spelling": "cspell \"src/**/*.ts\" \"tests/**/*.ts\"",
136
136
  "check:all": "pnpm check:deadcode && pnpm check:spelling && pnpm check:duplication && pnpm check:circular && pnpm check:deps && pnpm check:security && pnpm build && bash scripts/check-api.sh check && pnpm check:publish && pnpm check:types",
137
- "check:circular": "madge --circular --extensions ts src/ --json | node -e \"const c=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const n=c.length; if(n>5){console.error('New circular deps found ('+n+' > 5 known type-only/dynamic cycles)');process.exit(1)}else if(n>0){console.log(n+' known type-only/dynamic cycles (safe)')}else{console.log('No circular dependencies')}\"",
137
+ "check:circular": "madge --circular --extensions ts src/ --json | node -e \"const c=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const n=c.length; if(n>6){console.error('New circular deps found ('+n+' > 6 known type-only/dynamic cycles)');process.exit(1)}else if(n>0){console.log(n+' known type-only/dynamic cycles (safe)')}else{console.log('No circular dependencies')}\"",
138
138
  "check:deps": "depcheck --ignores='@diagrammo/dgmo,@codemirror/language,@lezer/*,husky,lint-staged,tsup,axe-core,type-coverage'",
139
139
  "check:security": "pnpm audit --prod",
140
140
  "check:publish": "publint",
package/src/advanced.ts CHANGED
@@ -569,11 +569,16 @@ export type {
569
569
  ProjectionFamily,
570
570
  GeoExtent,
571
571
  } from './map/resolved-types';
572
- export { completeMapPlaces, completeMapRegions } from './map/completion';
572
+ export {
573
+ completeMapPlaces,
574
+ completeMapRegions,
575
+ searchMapLocations,
576
+ } from './map/completion';
573
577
  export type {
574
578
  MapPlaceCompletion,
575
579
  MapRegionCompletion,
576
580
  MapCompletionOptions,
581
+ MapLocationMatch,
577
582
  } from './map/completion';
578
583
  export type {
579
584
  Gazetteer,