@milehimikey/em 1.20.0 → 1.22.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 (208) hide show
  1. package/.claude/agents/em-implementer.md +10 -0
  2. package/.claude/agents/em-validator.md +1 -0
  3. package/.claude/skills/event-modeling/SKILL.md +1 -1
  4. package/.claude/skills/event-modeling-conform/SKILL.md +7 -4
  5. package/.claude/skills/event-modeling-conform/reference/conform.md +82 -4
  6. package/.claude/skills/event-modeling-design/SKILL.md +23 -8
  7. package/.claude/skills/event-modeling-discover/SKILL.md +2 -2
  8. package/.claude/skills/event-modeling-discover/reference/extract.md +5 -1
  9. package/.claude/skills/event-modeling-engagement/SKILL.md +1 -1
  10. package/.claude/skills/event-modeling-engagement/reference/engagement.md +1 -0
  11. package/.claude/skills/event-modeling-implement/SKILL.md +5 -3
  12. package/.claude/skills/event-modeling-implement/reference/implement.md +14 -0
  13. package/.claude/skills/event-modeling-review/SKILL.md +19 -7
  14. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +54 -9
  15. package/.claude/skills/event-modeling-shared/reference/methodology.md +35 -2
  16. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +26 -15
  17. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +2 -1
  18. package/.claude/skills/event-modeling-shared/templates/model-readme.md +10 -2
  19. package/.claude/skills/event-modeling-shared/templates/slice.md +7 -1
  20. package/.claude-plugin/marketplace.json +2 -2
  21. package/dist/catalog/build.js +6 -5
  22. package/dist/catalog/build.js.map +1 -1
  23. package/dist/catalog/coverage.d.ts +3 -0
  24. package/dist/catalog/coverage.js +12 -0
  25. package/dist/catalog/coverage.js.map +1 -1
  26. package/dist/catalog/docLocate.d.ts +17 -0
  27. package/dist/catalog/docLocate.js +97 -0
  28. package/dist/catalog/docLocate.js.map +1 -0
  29. package/dist/catalog/frontmatterCoherenceValidate.js +16 -1
  30. package/dist/catalog/frontmatterCoherenceValidate.js.map +1 -1
  31. package/dist/catalog/orphanedSliceDocValidate.js +15 -10
  32. package/dist/catalog/orphanedSliceDocValidate.js.map +1 -1
  33. package/dist/catalog/readSliceDoc.js +5 -4
  34. package/dist/catalog/readSliceDoc.js.map +1 -1
  35. package/dist/catalog/scenarioQualityValidate.js +2 -2
  36. package/dist/catalog/scenarioQualityValidate.js.map +1 -1
  37. package/dist/catalog/sliceDoc.d.ts +8 -0
  38. package/dist/catalog/sliceDoc.js +9 -0
  39. package/dist/catalog/sliceDoc.js.map +1 -1
  40. package/dist/catalog/sliceSections.d.ts +18 -1
  41. package/dist/catalog/sliceSections.js +38 -4
  42. package/dist/catalog/sliceSections.js.map +1 -1
  43. package/dist/cli/api.d.ts +84 -0
  44. package/dist/cli/api.js +146 -15
  45. package/dist/cli/api.js.map +1 -1
  46. package/dist/cli/bindings.d.ts +152 -0
  47. package/dist/cli/bindings.js +462 -0
  48. package/dist/cli/bindings.js.map +1 -0
  49. package/dist/cli/conformScope.d.ts +32 -0
  50. package/dist/cli/conformScope.js +68 -5
  51. package/dist/cli/conformScope.js.map +1 -1
  52. package/dist/cli/defer.js +3 -2
  53. package/dist/cli/defer.js.map +1 -1
  54. package/dist/cli/engagement.d.ts +24 -1
  55. package/dist/cli/engagement.js +50 -6
  56. package/dist/cli/engagement.js.map +1 -1
  57. package/dist/cli/engagementBrief.d.ts +127 -0
  58. package/dist/cli/engagementBrief.js +313 -0
  59. package/dist/cli/engagementBrief.js.map +1 -0
  60. package/dist/cli/engagementFile.d.ts +14 -0
  61. package/dist/cli/engagementFile.js +54 -0
  62. package/dist/cli/engagementFile.js.map +1 -1
  63. package/dist/cli/ledgerCheck.js +11 -8
  64. package/dist/cli/ledgerCheck.js.map +1 -1
  65. package/dist/cli/markImplemented.js +2 -2
  66. package/dist/cli/markImplemented.js.map +1 -1
  67. package/dist/cli/ratify.js +2 -2
  68. package/dist/cli/ratify.js.map +1 -1
  69. package/dist/cli/refsCheck.js +3 -2
  70. package/dist/cli/refsCheck.js.map +1 -1
  71. package/dist/cli/render-inputs.d.ts +1 -1
  72. package/dist/cli/render-inputs.js +3 -2
  73. package/dist/cli/render-inputs.js.map +1 -1
  74. package/dist/cli/review.js +2 -2
  75. package/dist/cli/review.js.map +1 -1
  76. package/dist/cli/revise.js +2 -2
  77. package/dist/cli/revise.js.map +1 -1
  78. package/dist/cli/skillDirs.d.ts +22 -0
  79. package/dist/cli/skillDirs.js +24 -0
  80. package/dist/cli/skillDirs.js.map +1 -1
  81. package/dist/cli/sliceConform.js +2 -1
  82. package/dist/cli/sliceConform.js.map +1 -1
  83. package/dist/cli/sliceIndex.d.ts +19 -3
  84. package/dist/cli/sliceIndex.js +81 -17
  85. package/dist/cli/sliceIndex.js.map +1 -1
  86. package/dist/cli/sliceNew.js +2 -0
  87. package/dist/cli/sliceNew.js.map +1 -1
  88. package/dist/cli/sliceStubAll.js +7 -2
  89. package/dist/cli/sliceStubAll.js.map +1 -1
  90. package/dist/cli/sliceSync.d.ts +12 -0
  91. package/dist/cli/sliceSync.js +42 -4
  92. package/dist/cli/sliceSync.js.map +1 -1
  93. package/dist/cli/status.d.ts +8 -4
  94. package/dist/cli/status.js +6 -4
  95. package/dist/cli/status.js.map +1 -1
  96. package/dist/cli/storylineSplit.d.ts +18 -0
  97. package/dist/cli/storylineSplit.js +110 -0
  98. package/dist/cli/storylineSplit.js.map +1 -0
  99. package/dist/cli/upgrade.js +47 -23
  100. package/dist/cli/upgrade.js.map +1 -1
  101. package/dist/cli/watchStoryline.d.ts +6 -0
  102. package/dist/cli/watchStoryline.js +10 -0
  103. package/dist/cli/watchStoryline.js.map +1 -1
  104. package/dist/cli.js +408 -78
  105. package/dist/cli.js.map +1 -1
  106. package/dist/emit/api.d.ts +8 -1
  107. package/dist/emit/api.js +68 -24
  108. package/dist/emit/api.js.map +1 -1
  109. package/dist/emit/apiSurfaceJson.d.ts +3 -0
  110. package/dist/emit/apiSurfaceJson.js +26 -0
  111. package/dist/emit/apiSurfaceJson.js.map +1 -0
  112. package/dist/emit/engagementJson.d.ts +8 -3
  113. package/dist/emit/engagementJson.js +31 -4
  114. package/dist/emit/engagementJson.js.map +1 -1
  115. package/dist/emit/json.d.ts +22 -1
  116. package/dist/emit/json.js +12 -1
  117. package/dist/emit/json.js.map +1 -1
  118. package/dist/mcp/server.js +111 -9
  119. package/dist/mcp/server.js.map +1 -1
  120. package/dist/model/edges.d.ts +1 -1
  121. package/dist/model/edges.js +8 -1
  122. package/dist/model/edges.js.map +1 -1
  123. package/dist/model/loadModel.d.ts +38 -0
  124. package/dist/model/loadModel.js +122 -0
  125. package/dist/model/loadModel.js.map +1 -0
  126. package/dist/model/model.d.ts +26 -9
  127. package/dist/model/model.js +22 -17
  128. package/dist/model/model.js.map +1 -1
  129. package/dist/model/rules.d.ts +23 -0
  130. package/dist/model/rules.js +23 -0
  131. package/dist/model/rules.js.map +1 -1
  132. package/dist/model/shapeLint.js +95 -0
  133. package/dist/model/shapeLint.js.map +1 -1
  134. package/dist/model/sliceDocIndex.js +13 -5
  135. package/dist/model/sliceDocIndex.js.map +1 -1
  136. package/dist/model/sliceDocPath.d.ts +19 -0
  137. package/dist/model/sliceDocPath.js +49 -0
  138. package/dist/model/sliceDocPath.js.map +1 -0
  139. package/dist/model/storylineMap.d.ts +20 -0
  140. package/dist/model/storylineMap.js +55 -0
  141. package/dist/model/storylineMap.js.map +1 -0
  142. package/dist/model/validate.d.ts +7 -0
  143. package/dist/model/validate.js +8 -0
  144. package/dist/model/validate.js.map +1 -1
  145. package/dist/parser/ast.d.ts +19 -0
  146. package/dist/parser/parser.d.ts +17 -1
  147. package/dist/parser/parser.js +91 -2
  148. package/dist/parser/parser.js.map +1 -1
  149. package/dist/pipeline.d.ts +16 -0
  150. package/dist/pipeline.js +19 -2
  151. package/dist/pipeline.js.map +1 -1
  152. package/dist/render/drawEdges.d.ts +5 -1
  153. package/dist/render/drawEdges.js +57 -4
  154. package/dist/render/drawEdges.js.map +1 -1
  155. package/dist/render/drawNotes.d.ts +4 -1
  156. package/dist/render/drawNotes.js +40 -10
  157. package/dist/render/drawNotes.js.map +1 -1
  158. package/dist/render/render.d.ts +11 -0
  159. package/dist/render/render.js +94 -11
  160. package/dist/render/render.js.map +1 -1
  161. package/dist/render/serve.d.ts +5 -0
  162. package/dist/render/serve.js +18 -2
  163. package/dist/render/serve.js.map +1 -1
  164. package/dist/render/sliceDiagram.js +3 -0
  165. package/dist/render/sliceDiagram.js.map +1 -1
  166. package/dist/render/sliceOverlay.d.ts +4 -5
  167. package/dist/render/sliceOverlay.js +4 -7
  168. package/dist/render/sliceOverlay.js.map +1 -1
  169. package/dist/render/sliceStatus.d.ts +8 -0
  170. package/dist/render/sliceStatus.js +22 -15
  171. package/dist/render/sliceStatus.js.map +1 -1
  172. package/dist/render/storylineBands.d.ts +0 -3
  173. package/dist/render/storylineBands.js +2 -22
  174. package/dist/render/storylineBands.js.map +1 -1
  175. package/dist/render/storylineDiagram.js +17 -69
  176. package/dist/render/storylineDiagram.js.map +1 -1
  177. package/dist/render/storylineMap.d.ts +18 -0
  178. package/dist/render/storylineMap.js +263 -0
  179. package/dist/render/storylineMap.js.map +1 -0
  180. package/dist/render/svgGeometry.d.ts +9 -0
  181. package/dist/render/svgGeometry.js +16 -0
  182. package/dist/render/svgGeometry.js.map +1 -1
  183. package/dist/render/viewerHtml.js +1 -1
  184. package/dist/render/viewerHtml.js.map +1 -1
  185. package/dist/templates.d.ts +5 -1
  186. package/dist/templates.js +39 -2
  187. package/dist/templates.js.map +1 -1
  188. package/package.json +1 -1
  189. package/plugin/.claude-plugin/plugin.json +2 -2
  190. package/plugin/agents/em-implementer.md +10 -0
  191. package/plugin/agents/em-validator.md +1 -0
  192. package/plugin/shared/reference/em-dsl.md +54 -9
  193. package/plugin/shared/reference/methodology.md +35 -2
  194. package/plugin/shared/reference/operating-principles.md +26 -15
  195. package/plugin/shared/reference/slice-doc-schema.md +2 -1
  196. package/plugin/shared/templates/model-readme.md +10 -2
  197. package/plugin/shared/templates/slice.md +7 -1
  198. package/plugin/skills/conform/SKILL.md +7 -4
  199. package/plugin/skills/conform/reference/conform.md +82 -4
  200. package/plugin/skills/design/SKILL.md +23 -8
  201. package/plugin/skills/discover/SKILL.md +2 -2
  202. package/plugin/skills/discover/reference/extract.md +5 -1
  203. package/plugin/skills/engagement/SKILL.md +1 -1
  204. package/plugin/skills/engagement/reference/engagement.md +1 -0
  205. package/plugin/skills/event-modeling/SKILL.md +1 -1
  206. package/plugin/skills/implement/SKILL.md +5 -3
  207. package/plugin/skills/implement/reference/implement.md +14 -0
  208. package/plugin/skills/review/SKILL.md +19 -7
@@ -4,6 +4,14 @@ import { SliceDoc } from "../catalog/sliceDoc.js";
4
4
  * MIL-208 originating slice's own file, or null), same order as model.slices (and so the same
5
5
  * order as the header row's columns — see layout/grid.ts's sliceNames). */
6
6
  export declare function readSliceDocs(model: NormalizedModel, baseDir: string): (SliceDoc | null)[];
7
+ /** A resolved slice doc and where it is: `path` is relative to `baseDir`, posix separators
8
+ * (`slices/<key>.md`), so a render can link a slice's header cell to it (owner ruling
9
+ * 2026-11-03: every slice header in an SVG is a link to its doc). */
10
+ export interface SliceDocFile {
11
+ path: string;
12
+ doc: SliceDoc;
13
+ }
14
+ export declare function readSliceDocFiles(model: NormalizedModel, baseDir: string): (SliceDocFile | null)[];
7
15
  /** One status per slice, same order/resolution as readSliceDocs. null means no doc was found
8
16
  * (own or covering), or the doc has no `- **Status:** ...` line. */
9
17
  export declare function readSliceStatuses(model: NormalizedModel, baseDir: string): (string | null)[];
@@ -20,35 +20,42 @@
20
20
  // directly — same predicate/resolution as catalog/docJoin.ts's note-gated join, model/
21
21
  // continuation.ts, just applied to this module's filename-convention resolution instead of
22
22
  // notes.
23
- import { existsSync, readFileSync } from "node:fs";
24
- import { join } from "node:path";
23
+ import { readFileSync } from "node:fs";
24
+ import { relative, sep } from "node:path";
25
25
  import { computeRefs } from "../model/refs.js";
26
26
  import { continuationOf } from "../model/continuation.js";
27
- import { readCoverageDocs } from "../catalog/coverage.js";
27
+ import { readCoverageDocsAll } from "../catalog/coverage.js";
28
+ import { locateDoc } from "../catalog/docLocate.js";
28
29
  import { parseSliceDoc } from "../catalog/sliceDoc.js";
29
30
  /** Each slice's resolved design doc (own `slices/<key>.md`, the MIL-121 covering doc, the
30
31
  * MIL-208 originating slice's own file, or null), same order as model.slices (and so the same
31
32
  * order as the header row's columns — see layout/grid.ts's sliceNames). */
32
33
  export function readSliceDocs(model, baseDir) {
34
+ return readSliceDocFiles(model, baseDir).map((f) => f?.doc ?? null);
35
+ }
36
+ export function readSliceDocFiles(model, baseDir) {
33
37
  const refs = computeRefs(model);
34
38
  const { sliceKeys } = refs;
35
- const slicesDir = join(baseDir, "slices");
36
39
  let coverage = null; // built lazily, only if ever needed
40
+ // GH #421 step 2: a doc sits beside the file that declares its slice; docLocate finds it by key
41
+ // and `path` is where it IS, relative to the root (`<dir>/slices/<key>.md`), so a header link
42
+ // from any output location resolves to the real file.
43
+ const file = (key) => {
44
+ const abs = locateDoc(baseDir, `slices/${key}.md`);
45
+ return abs ? { path: relative(baseDir, abs).split(sep).join("/"), doc: parseSliceDoc(readFileSync(abs, "utf8")) } : null;
46
+ };
37
47
  return model.slices.map((_slice, i) => {
38
48
  const sliceKey = sliceKeys[i];
39
- const docPath = join(slicesDir, `${sliceKey}.md`);
40
- if (existsSync(docPath))
41
- return parseSliceDoc(readFileSync(docPath, "utf8"));
42
- coverage ??= readCoverageDocs(slicesDir);
43
- const covering = coverage.get(sliceKey)?.doc;
49
+ const own = file(sliceKey);
50
+ if (own)
51
+ return own;
52
+ coverage ??= readCoverageDocsAll(baseDir);
53
+ const covering = coverage.get(sliceKey);
44
54
  if (covering)
45
- return covering;
55
+ return file(covering.key) ?? { path: `slices/${covering.key}.md`, doc: covering.doc };
46
56
  const continuation = continuationOf(model, refs, i);
47
- if (continuation) {
48
- const originatingPath = join(slicesDir, `${continuation.sliceKey}.md`);
49
- if (existsSync(originatingPath))
50
- return parseSliceDoc(readFileSync(originatingPath, "utf8"));
51
- }
57
+ if (continuation)
58
+ return file(continuation.sliceKey);
52
59
  return null;
53
60
  });
54
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sliceStatus.js","sourceRoot":"","sources":["../../src/render/sliceStatus.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,qEAAqE;AACrE,kFAAkF;AAClF,kFAAkF;AAClF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,EAAE;AACF,gGAAgG;AAChG,4FAA4F;AAC5F,+FAA+F;AAC/F,qFAAqF;AACrF,EAAE;AACF,6FAA6F;AAC7F,yFAAyF;AACzF,uFAAuF;AACvF,2FAA2F;AAC3F,SAAS;AAET,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAe,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAY,MAAM,wBAAwB,CAAC;AAEjE;;4EAE4E;AAC5E,MAAM,UAAU,aAAa,CAAC,KAAsB,EAAE,OAAe;IACnE,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,IAAI,QAAQ,GAAoC,IAAI,CAAC,CAAC,oCAAoC;IAE1F,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,aAAa,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7E,QAAQ,KAAK,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,YAAY,GAAG,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACpD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,YAAY,CAAC,QAAQ,KAAK,CAAC,CAAC;YACvE,IAAI,UAAU,CAAC,eAAe,CAAC;gBAAE,OAAO,aAAa,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,iBAAiB,CAAC,KAAsB,EAAE,OAAe;IACvE,OAAO,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"sliceStatus.js","sourceRoot":"","sources":["../../src/render/sliceStatus.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,3 @@ export declare function storylineBandIds(grid: Grid): string[];
6
6
  /** One `<g class="em-storyline-band">` per run, in graph space (append inside the graph group,
7
7
  * after the nodes). Returns "" when the model has no storylines. */
8
8
  export declare function buildStorylineBands(model: NormalizedModel, grid: Grid, rects: Map<string, Rect>): string;
9
- /** Dim every node of the stub columns (`Slice.stub`) — the header cell and each element — by
10
- * adding an opacity attribute to its node group. */
11
- export declare function dimStubColumns(svg: string, model: NormalizedModel): string;
@@ -3,9 +3,8 @@
3
3
  //
4
4
  // Graphviz lays the storyline row out as one filled box per column belonging to a storyline
5
5
  // (emit/dot.ts). This reads those boxes' rectangles back out and draws one continuous labelled
6
- // band per run of columns — bridging the inter-column gaps — plus, for an `em render
7
- // --storyline` subset, dims the stub columns (elements the storyline reads from outside it).
8
- import { STORYLINE_KEY, headerCellId, placeholderId } from "../layout/grid.js";
6
+ // band per run of columns — bridging the inter-column gaps.
7
+ import { STORYLINE_KEY, placeholderId } from "../layout/grid.js";
9
8
  import { storylineStyle } from "../emit/theme.js";
10
9
  import { storylineRuns } from "../model/storylines.js";
11
10
  /** Row index of the storyline band row, or -1 when the grid has none. */
@@ -58,23 +57,4 @@ export function buildStorylineBands(model, grid, rects) {
58
57
  }
59
58
  return parts.join("");
60
59
  }
61
- const STUB_OPACITY = 0.4;
62
- /** Dim every node of the stub columns (`Slice.stub`) — the header cell and each element — by
63
- * adding an opacity attribute to its node group. */
64
- export function dimStubColumns(svg, model) {
65
- let out = svg;
66
- model.slices.forEach((slice, c) => {
67
- if (!slice.stub)
68
- return;
69
- const ids = [headerCellId(c), ...slice.elements.map((e) => e.id)];
70
- for (const id of ids) {
71
- const re = new RegExp(`(<g\\b[^>]*class="node")([^>]*>\\s*<title>${escapeRe(id)}</title>)`);
72
- out = out.replace(re, `$1 opacity="${STUB_OPACITY}"$2`);
73
- }
74
- });
75
- return out;
76
- }
77
- function escapeRe(s) {
78
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
79
- }
80
60
  //# sourceMappingURL=storylineBands.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storylineBands.js","sourceRoot":"","sources":["../../src/render/storylineBands.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storylineBands.js","sourceRoot":"","sources":["../../src/render/storylineBands.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,mEAAmE;AACnE,EAAE;AACF,4FAA4F;AAC5F,+FAA+F;AAC/F,4DAA4D;AAG5D,OAAO,EAAQ,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,yEAAyE;AACzE,SAAS,OAAO,CAAC,IAAU;IACzB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACtG,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,mBAAmB,CAAC,KAAsB,EAAE,IAAU,EAAE,KAAwB;IAC9F,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;YAAE,SAAS;QAC9B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACtC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;QAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;QAChG,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1G,KAAK,CAAC,IAAI,CACR,gDAAgD,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;YACzE,UAAU,GAAG,CAAC,GAAG,CAAC,UAAU;YAC5B,YAAY,IAAI,QAAQ,KAAK,CAAC,GAAG,YAAY,KAAK,aAAa,MAAM,WAAW;YAChF,SAAS,KAAK,CAAC,IAAI,aAAa,KAAK,CAAC,MAAM,sBAAsB;YAClE,iCAAiC,IAAI,GAAG,KAAK,GAAG,CAAC,QAAQ,KAAK,CAAC,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI;YACvF,+FAA+F;YAC/F,SAAS,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,KAAK,CAAC,aAAa,CACvD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC"}
@@ -2,18 +2,16 @@
2
2
  // Renders ONE storyline alone (`em render --storyline <name>`, GH #277): a subset of the
3
3
  // normal timeline's columns, not a redrawn pattern shape (that is `--slice`).
4
4
  //
5
- // The columns are the storyline's own slices, in order, preceded by dimmed STUB columns: every
6
- // element a slice of the storyline reads from outside it (so each arrow still has a source), and
7
- // for a storyline declared `after "<other>"` the referenced storyline's end state — the latest
8
- // earlier instance of each read model the storyline continues with `again`. A stub column holds
9
- // only the referenced elements of its origin slice, never the whole slice, so the picture can
10
- // never balloon into the rest of the model. Like render/sliceDiagram.ts this builds a small
11
- // synthetic NormalizedModel from shallow clones of the real Elements (same ids, fields, notes)
12
- // and runs it through the unmodified layout()/emitDot()/composeSvg() pipeline.
5
+ // The columns are the storyline's own slices and nothing else (owner ruling 2026-11-03: a
6
+ // storyline render shows only what is in the storyline — no dimmed "stub" columns borrowed from
7
+ // the slices it reads from outside). An element the storyline reads from another storyline has
8
+ // no box here, so its arrow is not drawn; the storyline map carries that flow between stories.
9
+ // Like render/sliceDiagram.ts this builds a small synthetic NormalizedModel from shallow clones
10
+ // of the real Elements (same ids, fields, notes) and runs it through the unmodified
11
+ // layout()/emitDot()/composeSvg() pipeline.
13
12
  import { AUTOMATION_KINDS } from "../parser/ast.js";
14
13
  import { normalizeName } from "../model/model.js";
15
- import { semanticEdges } from "../model/edges.js";
16
- import { findStoryline, latestOnTimeline, composedRank } from "../model/storylines.js";
14
+ import { findStoryline, composedRank } from "../model/storylines.js";
17
15
  import { layout } from "../layout/grid.js";
18
16
  import { emitDot } from "../emit/dot.js";
19
17
  /** The storyline named `name`, or an error message naming the available ones. */
@@ -30,34 +28,23 @@ export function resolveStorylineArg(model, name) {
30
28
  };
31
29
  }
32
30
  export function buildStorylineDiagram(model, storyline, opts = {}) {
33
- const own = [...storyline.sliceIndexes].sort((a, b) => a - b);
34
- const ownSet = new Set(own);
35
- const stubs = collectStubs(model, storyline, ownSet);
36
- // Left to right: the storyline's own slices and every stub column in ONE sequence ordered on
37
- // the composed timeline (model/storylines.ts's relationOnTimeline — the ordering validation
38
- // uses), file order as the fallback. The storylines this one comes `after` precede it on that
39
- // timeline, so their end-state stubs land on the left naturally, while a stub from a slice
40
- // between two blocks of this storyline is interleaved with its own columns: no arrow in the
41
- // subset points right-to-left.
42
- const columns = [
43
- ...own.map((i) => ({ i, stub: false })),
44
- ...[...stubs.keys()].map((i) => ({ i, stub: true })),
45
- ].sort((x, y) => {
46
- return composedRank(model, x.i) - composedRank(model, y.i);
47
- });
31
+ // Left to right on the composed timeline (model/storylines.ts's relationOnTimeline — the
32
+ // ordering validation uses), file order as the fallback: a storyline's blocks stay in the
33
+ // order the whole model reads them.
34
+ const own = [...storyline.sliceIndexes].sort((a, b) => composedRank(model, a) - composedRank(model, b));
48
35
  const slices = [];
49
36
  const elements = [];
50
37
  const byId = new Map();
51
38
  const byName = new Map();
52
- const addColumn = (origin, els, isStub) => {
39
+ for (const i of own) {
40
+ const origin = model.slices[i];
53
41
  const index = slices.length;
54
- const cloned = els.map((el) => ({ ...el, sliceIndex: index }));
42
+ const cloned = origin.elements.map((el) => ({ ...el, sliceIndex: index }));
55
43
  slices.push({
56
44
  name: origin.name,
57
45
  index,
58
46
  source: origin.source,
59
- storyline: isStub ? undefined : storyline.name,
60
- stub: isStub || undefined,
47
+ storyline: storyline.name,
61
48
  elements: cloned,
62
49
  line: origin.line,
63
50
  });
@@ -71,9 +58,6 @@ export function buildStorylineDiagram(model, storyline, opts = {}) {
71
58
  else
72
59
  byName.set(key, [el]);
73
60
  }
74
- };
75
- for (const { i, stub } of columns) {
76
- addColumn(model.slices[i], stub ? [...stubs.get(i).values()] : model.slices[i].elements, stub);
77
61
  }
78
62
  const dedupe = (values) => [...new Set(values.filter((v) => !!v))];
79
63
  const synthetic = {
@@ -88,7 +72,7 @@ export function buildStorylineDiagram(model, storyline, opts = {}) {
88
72
  name: storyline.name,
89
73
  source: storyline.source,
90
74
  after: storyline.after,
91
- sliceIndexes: slices.filter((s) => !s.stub).map((s) => s.index),
75
+ sliceIndexes: slices.map((s) => s.index),
92
76
  line: storyline.line,
93
77
  },
94
78
  ],
@@ -103,40 +87,4 @@ export function buildStorylineDiagram(model, storyline, opts = {}) {
103
87
  const grid = layout(synthetic, opts);
104
88
  return { model: synthetic, grid, dot: emitDot(synthetic, grid) };
105
89
  }
106
- /** origin slice index -> the elements of that slice the storyline needs as stubs. */
107
- function collectStubs(model, storyline, ownSet) {
108
- const stubs = new Map();
109
- const add = (el) => {
110
- if (!el || ownSet.has(el.sliceIndex))
111
- return;
112
- let bucket = stubs.get(el.sliceIndex);
113
- if (!bucket)
114
- stubs.set(el.sliceIndex, (bucket = new Map()));
115
- bucket.set(el.id, el);
116
- };
117
- for (const edge of semanticEdges(model)) {
118
- const from = model.byId.get(edge.from);
119
- const to = model.byId.get(edge.to);
120
- if (!from || !to)
121
- continue;
122
- if (edge.source === "loops-to") {
123
- if (ownSet.has(from.sliceIndex))
124
- add(to); // the earlier view a loop re-feeds
125
- }
126
- else if (ownSet.has(to.sliceIndex)) {
127
- add(from); // something the storyline reads
128
- }
129
- }
130
- // The referenced storyline's end state: the latest earlier instance of every read model this
131
- // storyline continues with `again`.
132
- for (const i of storyline.sliceIndexes) {
133
- for (const el of model.slices[i].elements) {
134
- if (el.kind !== "view" || !el.again)
135
- continue;
136
- const earlier = model.elements.filter((x) => x.kind === "view" && x.logicalId === el.logicalId && x.id !== el.id);
137
- add(latestOnTimeline(model, earlier, el.sliceIndex, true));
138
- }
139
- }
140
- return stubs;
141
- }
142
90
  //# sourceMappingURL=storylineDiagram.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storylineDiagram.js","sourceRoot":"","sources":["../../src/render/storylineDiagram.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storylineDiagram.js","sourceRoot":"","sources":["../../src/render/storylineDiagram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { StorylineMap } from "../model/storylineMap.js";
3
+ export interface StorylineFrame {
4
+ name: string;
5
+ slug: string;
6
+ sliceCount: number;
7
+ /** The storyline's own rendered SVG (render/storylineDiagram.ts through composeSvg). */
8
+ svg: string;
9
+ /** Where the frame's open link goes. Default `./<slug>.svg` (the file `em render --map` writes
10
+ * beside the page); the live viewer passes `/?svg=<subset file>` (GH #422). */
11
+ href?: string;
12
+ }
13
+ export interface StorylineMapOptions {
14
+ /** GH #422: served by `em watch --serve` — open links drill down in the same tab, the page
15
+ * reloads itself on the server's reload push and shows a render error in its bar. */
16
+ live?: boolean;
17
+ }
18
+ export declare function buildStorylineMapHtml(model: NormalizedModel, frames: StorylineFrame[], map: StorylineMap, opts?: StorylineMapOptions): string;
@@ -0,0 +1,263 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // The storyline canvas (`em render --map`, owner ruling 2026-11-03): one self-contained HTML page
3
+ // with every storyline's real diagram in a draggable frame and the flow between storylines drawn
4
+ // as connectors between frames. No server, no external assets: open `storylines/map.html` from
5
+ // disk. Frame positions are remembered per model in the browser's localStorage ("Reset layout"
6
+ // forgets them); the first layout places root storylines left and every `after` storyline one
7
+ // column to the right of what it follows.
8
+ //
9
+ // GH #422: `em watch --serve` serves the same page live at /map (src/render/serve.ts) — built by
10
+ // this one function with `live: true`: each frame's open link drills into that storyline's own
11
+ // subset in the viewer (`/?svg=<frame.href>`), and the page listens on the server's /__events
12
+ // stream and reloads itself after every successful render (positions and camera survive the
13
+ // reload: they live in localStorage). No second canvas implementation.
14
+ /** GH #422: the served canvas follows the same /__events stream the viewer does (serve.ts) — a
15
+ * successful render reloads the page (positions and camera are in localStorage, so the layout
16
+ * holds); a failed render lands in the bar without touching the frames on screen. */
17
+ const LIVE_SCRIPT = `
18
+ // --- live (em watch --serve): reload on the server's push, keep the last good canvas on an error
19
+ const liveEl = document.getElementById("live"), errEl = document.getElementById("liveError");
20
+ const es = new EventSource("/__events");
21
+ es.onopen = () => { liveEl.textContent = "live"; };
22
+ es.onerror = () => { liveEl.textContent = "reconnecting…"; };
23
+ es.onmessage = () => { location.reload(); };
24
+ es.addEventListener("renderError", (e) => { errEl.textContent = e.data; errEl.hidden = false; errEl.title = e.data; });
25
+ `;
26
+ function esc(s) {
27
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
28
+ }
29
+ export function buildStorylineMapHtml(model, frames, map, opts = {}) {
30
+ const title = `${model.name} — storylines`;
31
+ const live = opts.live === true;
32
+ const data = {
33
+ model: model.name,
34
+ nodes: map.nodes.map((n) => ({ name: n.name, slug: n.slug, after: n.after })),
35
+ edges: map.edges.map((e) => ({
36
+ from: e.from,
37
+ to: e.to,
38
+ kind: e.kind,
39
+ labels: e.elementIds.map((id) => model.byId.get(id)?.name ?? id),
40
+ })),
41
+ };
42
+ const frameHtml = frames
43
+ .map((f) => `<section class="frame" data-name="${esc(f.name)}" data-slug="${esc(f.slug)}">` +
44
+ `<header><span class="title">${esc(f.name)}</span><span class="meta">${f.sliceCount} slice${f.sliceCount === 1 ? "" : "s"}</span>` +
45
+ `<a class="open" href="${esc(f.href ?? `./${f.slug}.svg`)}"${live ? "" : ' target="_blank"'} title="${live ? "open this storyline in the live viewer" : "open this storyline's diagram"}">${live ? "open ›" : "↗"}</a></header>` +
46
+ `<div class="body">${f.svg}</div></section>`)
47
+ .join("\n");
48
+ // `</script>` can't appear in the JSON (names are model text; the escape keeps it safe anyway).
49
+ const json = JSON.stringify(data).replace(/<\//g, "<\\/");
50
+ return `<!doctype html>
51
+ <html lang="en">
52
+ <head>
53
+ <meta charset="utf-8" />
54
+ <title>${esc(title)}</title>
55
+ <style>
56
+ :root { color-scheme: light; }
57
+ html, body { height: 100%; margin: 0; }
58
+ body { font-family: system-ui, sans-serif; background: #f3f4f6; overflow: hidden; }
59
+ header.bar { position: fixed; top: 0; left: 0; right: 0; height: 40px; display: flex; align-items: center; gap: .75rem;
60
+ padding: 0 .9rem; background: #1f2933; color: #fff; font-size: 14px; z-index: 10; }
61
+ header.bar .title { font-weight: 600; }
62
+ header.bar .hint { opacity: .7; margin-left: auto; }
63
+ header.bar button { background: #334155; color: #fff; border: 0; border-radius: 4px; padding: .25rem .6rem; cursor: pointer; font-size: 13px; }
64
+ header.bar button:hover { background: #475569; }
65
+ header.bar .live { opacity: .7; }
66
+ header.bar .error { background: #b91c1c; color: #fff; padding: .2rem .6rem; border-radius: 4px; max-width: 40%;
67
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
68
+ header.bar .error[hidden] { display: none; }
69
+ #viewport { position: absolute; inset: 40px 0 0 0; overflow: hidden; cursor: grab; }
70
+ #viewport.panning { cursor: grabbing; }
71
+ #world { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
72
+ svg.links { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
73
+ svg.links text { font-size: 12px; font-family: system-ui, sans-serif; }
74
+ .frame { position: absolute; background: #fff; border: 2px solid #4a6fb5; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,.12);
75
+ display: flex; flex-direction: column; overflow: hidden; }
76
+ .frame header { display: flex; align-items: center; gap: .6rem; padding: .35rem .6rem; background: #dbe7fb; color: #1e3a8a;
77
+ font-size: 13px; cursor: move; user-select: none; }
78
+ .frame header .title { font-weight: 700; }
79
+ .frame header .meta { opacity: .75; }
80
+ .frame header .open { margin-left: auto; color: #1e3a8a; text-decoration: none; font-weight: 700; cursor: pointer; }
81
+ .frame .body { flex: 1; min-height: 0; background: #fff; padding: 16px; box-sizing: border-box; }
82
+ .frame .body svg { width: 100%; height: 100%; display: block; }
83
+ .frame.dragging { box-shadow: 0 6px 24px rgba(0,0,0,.25); z-index: 5; }
84
+ </style>
85
+ </head>
86
+ <body>
87
+ <header class="bar">
88
+ <span class="title">${esc(title)}</span>
89
+ <button id="fit" type="button">Fit</button>
90
+ <button id="reset" type="button">Reset layout</button>${live ? `\n <span class="live" id="live">live</span><span class="error" id="liveError" hidden></span>` : ""}
91
+ <span class="hint">drag a frame's title to move it · drag the background to pan · wheel to zoom${live ? " · click a storyline's “open ›” to step through it" : ""}</span>
92
+ </header>
93
+ <div id="viewport"><div id="world"><svg class="links" width="1" height="1">
94
+ <defs>
95
+ <marker id="m-after" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#4a6fb5"/></marker>
96
+ <marker id="m-reads" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#b36b00"/></marker>
97
+ </defs>
98
+ <g id="link-paths"></g><g id="link-labels"></g>
99
+ </svg>
100
+ ${frameHtml}
101
+ </div></div>
102
+ <script id="map-data" type="application/json">${json}</script>
103
+ <script>
104
+ (() => {
105
+ const DATA = JSON.parse(document.getElementById("map-data").textContent);
106
+ const KEY = "em-storyline-map:" + DATA.model;
107
+ const SCALE = 0.3; // diagram units -> frame pixels at zoom 1
108
+ const PAD = 16, HEAD = 34; // frame body padding (each side) and the title bar's height
109
+ const GAP_X = 160, GAP_Y = 90;
110
+ const viewport = document.getElementById("viewport");
111
+ const world = document.getElementById("world");
112
+ const links = world.querySelector("svg.links");
113
+ const paths = document.getElementById("link-paths");
114
+ const labels = document.getElementById("link-labels");
115
+ const frames = [...world.querySelectorAll(".frame")];
116
+ const byName = new Map(frames.map((f) => [f.dataset.name, f]));
117
+
118
+ // --- frame size from each diagram's own viewBox, so a 3-slice story is small and a 29-slice one is wide
119
+ for (const f of frames) {
120
+ const svg = f.querySelector("svg");
121
+ const vb = (svg && svg.getAttribute("viewBox") || "0 0 1200 600").split(/\\s+/).map(Number);
122
+ const w = Math.max(240, vb[2] * SCALE) + 2 * PAD, h = Math.max(120, vb[3] * SCALE) + 2 * PAD + HEAD;
123
+ f.style.width = w + "px"; f.style.height = h + "px";
124
+ if (svg) { svg.removeAttribute("width"); svg.removeAttribute("height"); svg.setAttribute("preserveAspectRatio", "xMinYMin meet"); }
125
+ }
126
+
127
+ // --- state: positions + camera, remembered per model
128
+ let state = { pos: {}, cam: { x: 24, y: 24, s: 1 } };
129
+ try { const saved = JSON.parse(localStorage.getItem(KEY) || "null"); if (saved && saved.pos) state = saved; } catch {}
130
+ const save = () => { try { localStorage.setItem(KEY, JSON.stringify(state)); } catch {} };
131
+
132
+ function autoLayout() {
133
+ // column = depth along the after chain; rows stack within a column
134
+ const depth = new Map();
135
+ const nodeByName = new Map(DATA.nodes.map((n) => [n.name, n]));
136
+ const depthOf = (name, seen = new Set()) => {
137
+ if (depth.has(name)) return depth.get(name);
138
+ const n = nodeByName.get(name);
139
+ let d = 0;
140
+ if (n && n.after && nodeByName.has(n.after) && !seen.has(name)) { seen.add(name); d = depthOf(n.after, seen) + 1; }
141
+ depth.set(name, d); return d;
142
+ };
143
+ for (const n of DATA.nodes) depthOf(n.name);
144
+ const cols = new Map();
145
+ for (const n of DATA.nodes) { const d = depth.get(n.name) || 0; if (!cols.has(d)) cols.set(d, []); cols.get(d).push(n.name); }
146
+ let x = 0;
147
+ state.pos = {};
148
+ for (const d of [...cols.keys()].sort((a, b) => a - b)) {
149
+ let y = 0, colW = 0;
150
+ for (const name of cols.get(d)) {
151
+ const f = byName.get(name); if (!f) continue;
152
+ state.pos[f.dataset.slug] = { x, y };
153
+ y += f.offsetHeight + GAP_Y; colW = Math.max(colW, f.offsetWidth);
154
+ }
155
+ x += colW + GAP_X;
156
+ }
157
+ }
158
+ if (!frames.every((f) => state.pos[f.dataset.slug])) autoLayout();
159
+
160
+ function applyPositions() {
161
+ for (const f of frames) { const p = state.pos[f.dataset.slug] || { x: 0, y: 0 }; f.style.left = p.x + "px"; f.style.top = p.y + "px"; }
162
+ drawLinks();
163
+ }
164
+ function applyCamera() { world.style.transform = "translate(" + state.cam.x + "px," + state.cam.y + "px) scale(" + state.cam.s + ")"; }
165
+
166
+ // --- connectors: centre-to-centre line clipped to each frame's border; labels at the midpoint
167
+ function rectOf(f) { const p = state.pos[f.dataset.slug] || { x: 0, y: 0 }; return { x: p.x, y: p.y, w: f.offsetWidth, h: f.offsetHeight }; }
168
+ function exitPoint(r, tx, ty) {
169
+ const cx = r.x + r.w / 2, cy = r.y + r.h / 2, dx = tx - cx, dy = ty - cy;
170
+ if (dx === 0 && dy === 0) return { x: cx, y: cy };
171
+ const sx = dx !== 0 ? (r.w / 2) / Math.abs(dx) : Infinity, sy = dy !== 0 ? (r.h / 2) / Math.abs(dy) : Infinity;
172
+ const t = Math.min(sx, sy);
173
+ return { x: cx + dx * t, y: cy + dy * t };
174
+ }
175
+ function drawLinks() {
176
+ paths.innerHTML = ""; labels.innerHTML = "";
177
+ const NS = "http://www.w3.org/2000/svg";
178
+ for (const e of DATA.edges) {
179
+ const a = byName.get(e.from), b = byName.get(e.to); if (!a || !b) continue;
180
+ const ra = rectOf(a), rb = rectOf(b);
181
+ const bc = { x: rb.x + rb.w / 2, y: rb.y + rb.h / 2 }, ac = { x: ra.x + ra.w / 2, y: ra.y + ra.h / 2 };
182
+ const p1 = exitPoint(ra, bc.x, bc.y), p2 = exitPoint(rb, ac.x, ac.y);
183
+ const path = document.createElementNS(NS, "path");
184
+ path.setAttribute("d", "M" + p1.x + "," + p1.y + " L" + p2.x + "," + p2.y);
185
+ path.setAttribute("fill", "none");
186
+ path.setAttribute("stroke", e.kind === "after" ? "#4a6fb5" : "#b36b00");
187
+ path.setAttribute("stroke-width", e.kind === "after" ? "4" : "2");
188
+ if (e.kind !== "after") path.setAttribute("stroke-dasharray", "8 6");
189
+ path.setAttribute("marker-end", "url(#m-" + e.kind + ")");
190
+ paths.appendChild(path);
191
+ const mx = (p1.x + p2.x) / 2, my = (p1.y + p2.y) / 2;
192
+ const text = e.kind === "after" ? "after" : (e.labels.slice(0, 3).join(", ") + (e.labels.length > 3 ? " +" + (e.labels.length - 3) : ""));
193
+ const t = document.createElementNS(NS, "text");
194
+ t.setAttribute("x", mx); t.setAttribute("y", my - 6); t.setAttribute("text-anchor", "middle");
195
+ t.setAttribute("fill", e.kind === "after" ? "#4a6fb5" : "#7a4a00");
196
+ if (e.kind === "after") t.setAttribute("font-weight", "700");
197
+ t.setAttribute("paint-order", "stroke"); t.setAttribute("stroke", "#f3f4f6"); t.setAttribute("stroke-width", "4");
198
+ t.textContent = text;
199
+ labels.appendChild(t);
200
+ }
201
+ }
202
+
203
+ // --- interaction: drag frames by their header, pan the background, zoom with the wheel
204
+ let drag = null;
205
+ for (const f of frames) {
206
+ f.querySelector("header").addEventListener("pointerdown", (ev) => {
207
+ if (ev.target.closest("a")) return;
208
+ const p = state.pos[f.dataset.slug];
209
+ drag = { f, sx: ev.clientX, sy: ev.clientY, ox: p.x, oy: p.y };
210
+ f.classList.add("dragging"); f.setPointerCapture(ev.pointerId); ev.preventDefault(); ev.stopPropagation();
211
+ });
212
+ f.addEventListener("pointermove", (ev) => {
213
+ if (!drag || drag.f !== f) return;
214
+ state.pos[f.dataset.slug] = { x: drag.ox + (ev.clientX - drag.sx) / state.cam.s, y: drag.oy + (ev.clientY - drag.sy) / state.cam.s };
215
+ applyPositions();
216
+ });
217
+ const end = () => { if (drag && drag.f === f) { f.classList.remove("dragging"); drag = null; save(); } };
218
+ f.addEventListener("pointerup", end); f.addEventListener("pointercancel", end);
219
+ }
220
+ let pan = null;
221
+ viewport.addEventListener("pointerdown", (ev) => {
222
+ if (ev.target.closest(".frame")) return;
223
+ pan = { sx: ev.clientX, sy: ev.clientY, ox: state.cam.x, oy: state.cam.y };
224
+ viewport.classList.add("panning"); viewport.setPointerCapture(ev.pointerId);
225
+ });
226
+ viewport.addEventListener("pointermove", (ev) => {
227
+ if (!pan) return;
228
+ state.cam.x = pan.ox + (ev.clientX - pan.sx); state.cam.y = pan.oy + (ev.clientY - pan.sy); applyCamera();
229
+ });
230
+ const endPan = () => { if (pan) { pan = null; viewport.classList.remove("panning"); save(); } };
231
+ viewport.addEventListener("pointerup", endPan); viewport.addEventListener("pointercancel", endPan);
232
+ viewport.addEventListener("wheel", (ev) => {
233
+ ev.preventDefault();
234
+ const rect = viewport.getBoundingClientRect();
235
+ const mx = ev.clientX - rect.left, my = ev.clientY - rect.top;
236
+ const factor = Math.exp(-ev.deltaY * 0.0015);
237
+ const s = Math.min(4, Math.max(0.05, state.cam.s * factor));
238
+ state.cam.x = mx - (mx - state.cam.x) * (s / state.cam.s);
239
+ state.cam.y = my - (my - state.cam.y) * (s / state.cam.s);
240
+ state.cam.s = s; applyCamera(); save();
241
+ }, { passive: false });
242
+
243
+ function fit() {
244
+ if (frames.length === 0) return;
245
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
246
+ for (const f of frames) { const r = rectOf(f); minX = Math.min(minX, r.x); minY = Math.min(minY, r.y); maxX = Math.max(maxX, r.x + r.w); maxY = Math.max(maxY, r.y + r.h); }
247
+ const vw = viewport.clientWidth, vh = viewport.clientHeight, pad = 32;
248
+ const s = Math.min(4, Math.max(0.05, Math.min((vw - 2 * pad) / (maxX - minX), (vh - 2 * pad) / (maxY - minY))));
249
+ state.cam = { s, x: pad - minX * s + ((vw - 2 * pad) - (maxX - minX) * s) / 2, y: pad - minY * s + ((vh - 2 * pad) - (maxY - minY) * s) / 2 };
250
+ applyCamera(); save();
251
+ }
252
+ document.getElementById("fit").addEventListener("click", fit);
253
+ document.getElementById("reset").addEventListener("click", () => { autoLayout(); applyPositions(); fit(); });
254
+
255
+ applyPositions();
256
+ if (!localStorage.getItem(KEY)) fit(); else applyCamera();
257
+ ${live ? LIVE_SCRIPT : ""}})();
258
+ </script>
259
+ </body>
260
+ </html>
261
+ `;
262
+ }
263
+ //# sourceMappingURL=storylineMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storylineMap.js","sourceRoot":"","sources":["../../src/render/storylineMap.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,15 @@ export declare const NODE_GROUP: RegExp;
10
10
  export declare const TITLE: RegExp;
11
11
  /** Map each requested node id to its rectangle in SVG coordinates. */
12
12
  export declare function parseNodeRects(svg: string, ids: Set<string>): Map<string, Rect>;
13
+ /** One `<text>` line inside a node group: its decoded text and baseline y (SVG user space). */
14
+ export interface TextRow {
15
+ text: string;
16
+ y: number;
17
+ }
18
+ /** The text lines of one node, top to bottom, with their baselines — how a box that lists
19
+ * alternatives (GH #278, one Graphviz HTML table per group) tells which row is which
20
+ * alternative, so an arrow or a marker can anchor to that alternative's own row (GH #324). */
21
+ export declare function parseNodeTextRows(svg: string, id: string): TextRow[];
13
22
  /** A bounding box in the graph's own (post-transform) coordinate space. */
14
23
  export interface Box {
15
24
  minX: number;