@sgummalla-works/sketchon 0.1.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 (89) hide show
  1. package/LICENSE +34 -0
  2. package/README.md +197 -0
  3. package/assets/emoji/1f4a1.svg +1 -0
  4. package/assets/emoji/1f4c8.svg +1 -0
  5. package/assets/emoji/1f4ca.svg +1 -0
  6. package/assets/emoji/1f4cb.svg +1 -0
  7. package/assets/emoji/1f4da.svg +1 -0
  8. package/assets/emoji/1f4dd.svg +1 -0
  9. package/assets/emoji/1f4e5.svg +1 -0
  10. package/assets/emoji/1f501.svg +1 -0
  11. package/assets/emoji/1f50d.svg +1 -0
  12. package/assets/emoji/1f517.svg +1 -0
  13. package/assets/emoji/1f525.svg +1 -0
  14. package/assets/emoji/1f5c4.svg +1 -0
  15. package/assets/emoji/1f9e0.svg +1 -0
  16. package/assets/emoji/1f9ee.svg +1 -0
  17. package/assets/emoji/23f8.svg +1 -0
  18. package/assets/emoji/2699.svg +1 -0
  19. package/assets/emoji/26a1.svg +1 -0
  20. package/assets/emoji/2705.svg +1 -0
  21. package/assets/emoji/2753.svg +1 -0
  22. package/assets/inter-400.ttf +0 -0
  23. package/assets/inter-600.ttf +0 -0
  24. package/assets/inter-700.ttf +0 -0
  25. package/dist/adapters/baseline.d.ts +3 -0
  26. package/dist/adapters/baseline.d.ts.map +1 -0
  27. package/dist/adapters/baseline.js +196 -0
  28. package/dist/adapters/baseline.js.map +1 -0
  29. package/dist/adapters/elk.d.ts +3 -0
  30. package/dist/adapters/elk.d.ts.map +1 -0
  31. package/dist/adapters/elk.js +230 -0
  32. package/dist/adapters/elk.js.map +1 -0
  33. package/dist/adapters/emoji.d.ts +10 -0
  34. package/dist/adapters/emoji.d.ts.map +1 -0
  35. package/dist/adapters/emoji.js +80 -0
  36. package/dist/adapters/emoji.js.map +1 -0
  37. package/dist/adapters/fonts.d.ts +13 -0
  38. package/dist/adapters/fonts.d.ts.map +1 -0
  39. package/dist/adapters/fonts.js +27 -0
  40. package/dist/adapters/fonts.js.map +1 -0
  41. package/dist/adapters/satori-helpers.d.ts +48 -0
  42. package/dist/adapters/satori-helpers.d.ts.map +1 -0
  43. package/dist/adapters/satori-helpers.js +43 -0
  44. package/dist/adapters/satori-helpers.js.map +1 -0
  45. package/dist/adapters/satori.d.ts +3 -0
  46. package/dist/adapters/satori.d.ts.map +1 -0
  47. package/dist/adapters/satori.js +269 -0
  48. package/dist/adapters/satori.js.map +1 -0
  49. package/dist/adapters/sequence.d.ts +3 -0
  50. package/dist/adapters/sequence.d.ts.map +1 -0
  51. package/dist/adapters/sequence.js +136 -0
  52. package/dist/adapters/sequence.js.map +1 -0
  53. package/dist/adapters/svg.d.ts +43 -0
  54. package/dist/adapters/svg.d.ts.map +1 -0
  55. package/dist/adapters/svg.js +92 -0
  56. package/dist/adapters/svg.js.map +1 -0
  57. package/dist/application/registry.d.ts +43 -0
  58. package/dist/application/registry.d.ts.map +1 -0
  59. package/dist/application/registry.js +45 -0
  60. package/dist/application/registry.js.map +1 -0
  61. package/dist/application/router.d.ts +56 -0
  62. package/dist/application/router.d.ts.map +1 -0
  63. package/dist/application/router.js +59 -0
  64. package/dist/application/router.js.map +1 -0
  65. package/dist/constants.d.ts +25 -0
  66. package/dist/constants.d.ts.map +1 -0
  67. package/dist/constants.js +35 -0
  68. package/dist/constants.js.map +1 -0
  69. package/dist/domain/spec.d.ts +163 -0
  70. package/dist/domain/spec.d.ts.map +1 -0
  71. package/dist/domain/spec.js +17 -0
  72. package/dist/domain/spec.js.map +1 -0
  73. package/dist/domain/theme.d.ts +68 -0
  74. package/dist/domain/theme.d.ts.map +1 -0
  75. package/dist/domain/theme.js +60 -0
  76. package/dist/domain/theme.js.map +1 -0
  77. package/dist/domain/validate.d.ts +19 -0
  78. package/dist/domain/validate.d.ts.map +1 -0
  79. package/dist/domain/validate.js +69 -0
  80. package/dist/domain/validate.js.map +1 -0
  81. package/dist/index.d.ts +62 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +83 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/ports/Technique.d.ts +69 -0
  86. package/dist/ports/Technique.d.ts.map +1 -0
  87. package/dist/ports/Technique.js +2 -0
  88. package/dist/ports/Technique.js.map +1 -0
  89. package/package.json +52 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Satori technique — the PRIMARY engine for the north-star (case #11).
3
+ *
4
+ * The model declares a coordinate-free spec; here we map it to a flexbox tree
5
+ * and Satori (Vercel's headless HTML/CSS→SVG engine) computes every pixel. This
6
+ * is the whole thesis made real: no hand-computed coordinates, so the failure
7
+ * mode that killed the original SVG attempt (overlaps on weak models) cannot
8
+ * occur — flexbox children never overlap.
9
+ *
10
+ * It renders the reference aesthetic: a vertical pipeline of category-coloured
11
+ * rich CARDS (icon chip + title + ·-joined sub-capabilities, white-on-fill),
12
+ * interspersed gold CHECKPOINT pills, a paired muted annotation column with
13
+ * column headers, thin connectors between stages, and a category LEGEND.
14
+ *
15
+ * Geometry eval returns no boxes (Satori can't report coordinates and can't
16
+ * overlap) — fidelity + the visual gallery are the real signal here.
17
+ */
18
+ import satori from 'satori';
19
+ import { loadFonts } from './fonts.js';
20
+ import { emojiToDataUri } from './emoji.js';
21
+ import { CARD_PALETTE, CHECKPOINT_COLORS, el, monogram, stripEmoji, } from './satori-helpers.js';
22
+ /**
23
+ * Render a node's leading glyph. If the node carries an emoji `icon`, emit it as
24
+ * text at `size` — Satori turns it into a Twemoji image via loadAdditionalAsset.
25
+ * Otherwise fall back to a tinted monogram chip so iconless cards still read.
26
+ */
27
+ function iconEl(node, size, onCard) {
28
+ if (node.icon) {
29
+ return el('div', { display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: size }, node.icon);
30
+ }
31
+ return el('div', {
32
+ display: 'flex',
33
+ alignItems: 'center',
34
+ justifyContent: 'center',
35
+ width: 32,
36
+ height: 32,
37
+ borderRadius: 8,
38
+ background: onCard ? 'rgba(255,255,255,0.18)' : 'rgba(15,23,42,0.08)',
39
+ color: onCard ? '#ffffff' : '#334155',
40
+ fontSize: 15,
41
+ fontWeight: 700,
42
+ }, monogram(node.label));
43
+ }
44
+ // Layout constants (container-level only — never per-node coordinates).
45
+ const WIDTH = 1100;
46
+ const PAD = 32;
47
+ const LEFT_W = 560; // pipeline column width
48
+ const GAP_COL = 28; // gap to the annotation column
49
+ const CARD_H = 66;
50
+ const CHECKPOINT_H = 40;
51
+ const CONNECTOR_H = 24;
52
+ const HEADER_H = 34;
53
+ const LEGEND_H = 52;
54
+ const ARROW_W = 10; // connector arrowhead width
55
+ const ARROW_H = 7; // connector arrowhead height
56
+ const CONNECTOR_COLOR = '#cbd5e1';
57
+ const TITLE_H = 40;
58
+ /** Map a node to its fill colour via category → emphasis → palette. */
59
+ function nodeEmphasis(spec, node) {
60
+ if (node.category) {
61
+ const cat = spec.categories?.find((c) => c.id === node.category);
62
+ if (cat?.emphasis)
63
+ return cat.emphasis;
64
+ }
65
+ return node.emphasis ?? 'normal';
66
+ }
67
+ /** The `·`-joined sub-line for a card. */
68
+ function subline(node) {
69
+ if (node.sublabelParts?.length)
70
+ return node.sublabelParts.map(stripEmoji).join(' · ');
71
+ return node.sublabel ? stripEmoji(node.sublabel) : '';
72
+ }
73
+ function cardEl(spec, node) {
74
+ const fill = CARD_PALETTE[nodeEmphasis(spec, node)];
75
+ const sub = subline(node);
76
+ return el('div', {
77
+ display: 'flex',
78
+ flexDirection: 'row',
79
+ alignItems: 'center',
80
+ gap: 14,
81
+ width: LEFT_W,
82
+ height: CARD_H,
83
+ padding: '0 18px',
84
+ borderRadius: 12,
85
+ background: fill,
86
+ }, [
87
+ iconEl(node, 28, true),
88
+ el('div', { display: 'flex', flexDirection: 'column', gap: 2 }, [
89
+ el('div', { color: '#ffffff', fontSize: 16, fontWeight: 700 }, stripEmoji(node.label)),
90
+ sub
91
+ ? el('div', { color: 'rgba(255,255,255,0.82)', fontSize: 12, fontWeight: 400 }, sub)
92
+ : null,
93
+ ]),
94
+ ]);
95
+ }
96
+ function checkpointEl(node) {
97
+ return el('div', {
98
+ display: 'flex',
99
+ flexDirection: 'row',
100
+ alignItems: 'center',
101
+ alignSelf: 'flex-start',
102
+ gap: 8,
103
+ height: CHECKPOINT_H,
104
+ padding: '0 18px',
105
+ borderRadius: 999,
106
+ background: CHECKPOINT_COLORS.fill,
107
+ border: `1px solid ${CHECKPOINT_COLORS.border}`,
108
+ color: CHECKPOINT_COLORS.text,
109
+ fontSize: 14,
110
+ fontWeight: 600,
111
+ }, [
112
+ node.icon
113
+ ? el('div', { display: 'flex', fontSize: 14 }, node.icon)
114
+ : el('div', { display: 'flex', fontWeight: 700 }, 'II'),
115
+ el('div', { display: 'flex' }, stripEmoji(node.label)),
116
+ ]);
117
+ }
118
+ /**
119
+ * Thin vertical connector + downward arrowhead between consecutive stages. The
120
+ * arrowhead is a CSS-border triangle (a 0×0 box with transparent side borders
121
+ * and a coloured top border) — pure flexbox, no coordinates, matches the
122
+ * reference's arrowed connectors.
123
+ */
124
+ function connectorEl() {
125
+ const stem = CONNECTOR_H - ARROW_H - 2;
126
+ return el('div', {
127
+ display: 'flex',
128
+ flexDirection: 'column',
129
+ width: LEFT_W,
130
+ height: CONNECTOR_H,
131
+ alignItems: 'center',
132
+ justifyContent: 'center',
133
+ }, [
134
+ el('div', { width: 2, height: stem, background: CONNECTOR_COLOR }, undefined),
135
+ el('div', {
136
+ width: 0,
137
+ height: 0,
138
+ borderLeft: `${ARROW_W / 2}px solid transparent`,
139
+ borderRight: `${ARROW_W / 2}px solid transparent`,
140
+ borderTop: `${ARROW_H}px solid ${CONNECTOR_COLOR}`,
141
+ }, undefined),
142
+ ]);
143
+ }
144
+ function buildTree(spec) {
145
+ const annByTarget = new Map();
146
+ for (const a of spec.annotations ?? []) {
147
+ if (a.target)
148
+ annByTarget.set(a.target, stripEmoji(a.text));
149
+ }
150
+ const bodyRows = [];
151
+ spec.nodes.forEach((node, idx) => {
152
+ if (idx > 0) {
153
+ bodyRows.push(el('div', { display: 'flex', flexDirection: 'row', width: '100%' }, [
154
+ connectorEl(),
155
+ el('div', { display: 'flex', flex: 1 }, undefined),
156
+ ]));
157
+ }
158
+ const left = node.shape === 'checkpoint' ? checkpointEl(node) : cardEl(spec, node);
159
+ const ann = annByTarget.get(node.id);
160
+ bodyRows.push(el('div', { display: 'flex', flexDirection: 'row', width: '100%', alignItems: 'center' }, [
161
+ el('div', { display: 'flex', width: LEFT_W }, [left]),
162
+ el('div', {
163
+ display: 'flex',
164
+ flex: 1,
165
+ paddingLeft: GAP_COL,
166
+ color: '#64748b',
167
+ fontSize: 14,
168
+ fontWeight: 400,
169
+ alignItems: 'center',
170
+ }, ann ?? ''),
171
+ ]));
172
+ });
173
+ const children = [];
174
+ if (spec.title) {
175
+ children.push(el('div', { display: 'flex', color: '#0f172a', fontSize: 18, fontWeight: 700, height: TITLE_H }, stripEmoji(spec.title)));
176
+ }
177
+ if (spec.columns) {
178
+ children.push(el('div', {
179
+ display: 'flex',
180
+ flexDirection: 'row',
181
+ width: '100%',
182
+ height: HEADER_H,
183
+ alignItems: 'center',
184
+ borderBottom: '1px solid #e2e8f0',
185
+ marginBottom: 6,
186
+ }, [
187
+ el('div', { display: 'flex', width: LEFT_W, color: '#94a3b8', fontSize: 13, fontWeight: 600 }, spec.columns.primary),
188
+ el('div', { display: 'flex', flex: 1, paddingLeft: GAP_COL, color: '#94a3b8', fontSize: 13, fontWeight: 600 }, spec.columns.annotation),
189
+ ]));
190
+ }
191
+ children.push(el('div', { display: 'flex', flexDirection: 'column', width: '100%' }, bodyRows));
192
+ if (spec.categories?.length) {
193
+ const items = spec.categories.map((c) => el('div', { display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8, marginRight: 22 }, [
194
+ el('div', { width: 14, height: 14, borderRadius: 4, background: CARD_PALETTE[c.emphasis ?? 'normal'] }, undefined),
195
+ el('div', { display: 'flex', color: '#475569', fontSize: 13 }, c.label),
196
+ ]));
197
+ children.push(el('div', {
198
+ display: 'flex',
199
+ flexDirection: 'row',
200
+ flexWrap: 'wrap',
201
+ width: '100%',
202
+ height: LEGEND_H,
203
+ alignItems: 'center',
204
+ marginTop: 8,
205
+ borderTop: '1px solid #e2e8f0',
206
+ paddingTop: 12,
207
+ }, items));
208
+ }
209
+ return el('div', {
210
+ display: 'flex',
211
+ flexDirection: 'column',
212
+ width: '100%',
213
+ height: '100%',
214
+ padding: PAD,
215
+ background: '#ffffff',
216
+ }, children);
217
+ }
218
+ /** Estimate container height from row counts (container-level math, not per-node placement). */
219
+ function estimateHeight(spec) {
220
+ let h = PAD * 2;
221
+ if (spec.title)
222
+ h += TITLE_H;
223
+ if (spec.columns)
224
+ h += HEADER_H + 6;
225
+ spec.nodes.forEach((n, idx) => {
226
+ if (idx > 0)
227
+ h += CONNECTOR_H;
228
+ h += n.shape === 'checkpoint' ? CHECKPOINT_H : CARD_H;
229
+ });
230
+ if (spec.categories?.length)
231
+ h += LEGEND_H + 12;
232
+ return Math.ceil(h) + 8;
233
+ }
234
+ export const satoriTechnique = {
235
+ key: 'satori',
236
+ name: 'Satori (flexbox → SVG)',
237
+ blurb: 'Model declares structure; Satori computes every pixel via flexbox. Primary engine for cards/columns/legend.',
238
+ async render(spec) {
239
+ const fonts = loadFonts();
240
+ const height = estimateHeight(spec);
241
+ const tree = buildTree(spec);
242
+ const svg = await satori(tree, {
243
+ width: WIDTH,
244
+ height,
245
+ fonts: fonts,
246
+ // Satori has no emoji font; resolve each emoji grapheme to a Twemoji SVG.
247
+ loadAdditionalAsset: async (code, segment) => {
248
+ if (code === 'emoji')
249
+ return emojiToDataUri(segment);
250
+ return '';
251
+ },
252
+ });
253
+ const nodes = spec.nodes ?? [];
254
+ return {
255
+ svg,
256
+ width: WIDTH,
257
+ height,
258
+ // No boxes/edges: flexbox can't overlap + Satori doesn't report coords.
259
+ features: {
260
+ cards: nodes.some((n) => n.shape === 'card'),
261
+ checkpoints: nodes.some((n) => n.shape === 'checkpoint'),
262
+ twoColumn: !!spec.columns,
263
+ legend: !!spec.categories?.length,
264
+ categoryColors: nodes.some((n) => !!n.category),
265
+ },
266
+ };
267
+ },
268
+ };
269
+ //# sourceMappingURL=satori.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"satori.js","sourceRoot":"","sources":["../../src/adapters/satori.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Technique } from '../ports/Technique.js';
2
+ export declare const sequenceTechnique: Technique;
3
+ //# sourceMappingURL=sequence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/adapters/sequence.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAiDrE,eAAO,MAAM,iBAAiB,EAAE,SA6G/B,CAAC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Sequence diagram adapter — proper lifeline rendering.
3
+ *
4
+ * Actors become equally-spaced columns; edges become ordered horizontal rows.
5
+ * The model declares actors in left-to-right order and messages in time order;
6
+ * this adapter computes every coordinate algorithmically.
7
+ * Labels never overlap because each message occupies a unique Y row.
8
+ */
9
+ import { NODE_LABEL_FONT_SIZE, EDGE_LABEL_FONT_SIZE, } from '../constants.js';
10
+ import { DARK_PRIMARY, DARK_ACCENT, DARK_SUCCESS, DARK_DANGER, DARK_NORMAL, DARK_MUTED, ACTOR_CYCLE_FILLS, COLOR_TEXT_WHITE, COLOR_TEXT_PRIMARY, COLOR_BORDER_DEFAULT, COLOR_EDGE_DASHED, COLOR_EDGE_DEFAULT, COLOR_TEXT_MUTED, COLOR_TEXT_BODY, } from '../domain/theme.js';
11
+ import { esc, svgDocument } from './svg.js';
12
+ // ── Layout constants ──────────────────────────────────────────────────────────
13
+ const ACTOR_COL_W = 210;
14
+ const ACTOR_BOX_W = 178;
15
+ const ACTOR_BOX_H = 50;
16
+ const ACTOR_BOX_RX = 10;
17
+ const CANVAS_PAD_X = 40;
18
+ const CANVAS_PAD_BOTTOM = 48;
19
+ const TITLE_H = 32;
20
+ const ACTOR_Y_PAD = 10;
21
+ const LIFELINE_GAP = 10;
22
+ const FIRST_MSG_OFFSET = 52;
23
+ const MSG_STEP = 52;
24
+ const ARROW_SIZE = 8;
25
+ const SELF_LOOP_W = 44;
26
+ // ─────────────────────────────────────────────────────────────────────────────
27
+ const EMPHASIS_DARK = {
28
+ primary: DARK_PRIMARY,
29
+ accent: DARK_ACCENT,
30
+ success: DARK_SUCCESS,
31
+ danger: DARK_DANGER,
32
+ normal: DARK_NORMAL,
33
+ muted: DARK_MUTED,
34
+ };
35
+ function actorFill(emphasis, index) {
36
+ if (emphasis && emphasis in EMPHASIS_DARK)
37
+ return EMPHASIS_DARK[emphasis];
38
+ return ACTOR_CYCLE_FILLS[index % ACTOR_CYCLE_FILLS.length];
39
+ }
40
+ function actorCx(i) {
41
+ return CANVAS_PAD_X + (i + 0.5) * ACTOR_COL_W;
42
+ }
43
+ function messageY(actorBoxBottom, rowIndex) {
44
+ return actorBoxBottom + FIRST_MSG_OFFSET + rowIndex * MSG_STEP;
45
+ }
46
+ function arrowhead(x1, x2, y, isDashed) {
47
+ const dir = x2 >= x1 ? 1 : -1;
48
+ const tip = x2;
49
+ const base = tip - dir * ARROW_SIZE;
50
+ const half = ARROW_SIZE * 0.5;
51
+ const fill = isDashed ? COLOR_EDGE_DASHED : COLOR_EDGE_DEFAULT;
52
+ return `<polygon points="${tip},${y} ${base},${y - half} ${base},${y + half}" fill="${fill}"/>`;
53
+ }
54
+ export const sequenceTechnique = {
55
+ key: 'sequence',
56
+ name: 'Sequence (lifeline)',
57
+ blurb: 'Actor columns + message rows — proper lifeline diagram, no ELK.',
58
+ render(spec) {
59
+ const nodes = spec.nodes;
60
+ const edges = spec.edges;
61
+ const n = nodes.length;
62
+ const width = CANVAS_PAD_X * 2 + n * ACTOR_COL_W;
63
+ const hasTitle = !!spec.title;
64
+ const actorBoxTop = (hasTitle ? TITLE_H : 0) + ACTOR_Y_PAD;
65
+ const actorBoxBottom = actorBoxTop + ACTOR_BOX_H;
66
+ const lifelineTop = actorBoxBottom + LIFELINE_GAP;
67
+ const lifelineBottom = actorBoxBottom + FIRST_MSG_OFFSET + edges.length * MSG_STEP + CANVAS_PAD_BOTTOM;
68
+ const height = lifelineBottom;
69
+ const colOf = new Map(nodes.map((nd, i) => [nd.id, i]));
70
+ const parts = [];
71
+ if (spec.title) {
72
+ parts.push(`<text x="${CANVAS_PAD_X}" y="${ACTOR_Y_PAD - 2}" ` +
73
+ `font-size="17" font-weight="700" fill="${COLOR_TEXT_PRIMARY}">${esc(spec.title)}</text>`);
74
+ }
75
+ nodes.forEach((_, i) => {
76
+ const cx = actorCx(i);
77
+ parts.push(`<line x1="${cx.toFixed(1)}" y1="${lifelineTop}" ` +
78
+ `x2="${cx.toFixed(1)}" y2="${lifelineBottom}" ` +
79
+ `stroke="${COLOR_BORDER_DEFAULT}" stroke-width="1.5" stroke-dasharray="6 4"/>`);
80
+ });
81
+ nodes.forEach((node, i) => {
82
+ const cx = actorCx(i);
83
+ const bx = cx - ACTOR_BOX_W / 2;
84
+ const fill = actorFill(node.emphasis, i);
85
+ const cy = actorBoxTop + ACTOR_BOX_H / 2;
86
+ parts.push(`<rect x="${bx.toFixed(1)}" y="${actorBoxTop}" ` +
87
+ `width="${ACTOR_BOX_W}" height="${ACTOR_BOX_H}" ` +
88
+ `rx="${ACTOR_BOX_RX}" fill="${fill}" stroke="none"/>`, `<text x="${cx.toFixed(1)}" y="${cy.toFixed(1)}" ` +
89
+ `font-size="${NODE_LABEL_FONT_SIZE}" font-weight="600" fill="${COLOR_TEXT_WHITE}" ` +
90
+ `text-anchor="middle" dominant-baseline="middle">${esc(node.label)}</text>`);
91
+ });
92
+ edges.forEach((edge, rowIdx) => {
93
+ const fromCol = colOf.get(edge.from) ?? 0;
94
+ const toCol = colOf.get(edge.to) ?? 0;
95
+ const y = messageY(actorBoxBottom, rowIdx);
96
+ const isDashed = edge.style === 'dashed' || edge.style === 'dotted' ||
97
+ edge.semantic === 'return';
98
+ const stroke = isDashed ? COLOR_EDGE_DASHED : COLOR_EDGE_DEFAULT;
99
+ const dash = isDashed ? ' stroke-dasharray="6 4"' : '';
100
+ if (fromCol === toCol) {
101
+ const cx = actorCx(fromCol);
102
+ const loopH = Math.round(MSG_STEP * 0.55);
103
+ parts.push(`<path d="M${cx.toFixed(1)},${y} L${(cx + SELF_LOOP_W).toFixed(1)},${y} ` +
104
+ `L${(cx + SELF_LOOP_W).toFixed(1)},${y + loopH} L${cx.toFixed(1)},${y + loopH}" ` +
105
+ `fill="none" stroke="${stroke}" stroke-width="1.5"${dash}/>`, arrowhead(cx + SELF_LOOP_W, cx, y + loopH, isDashed));
106
+ if (edge.label) {
107
+ parts.push(`<text x="${(cx + SELF_LOOP_W + 5).toFixed(1)}" y="${(y + loopH / 2).toFixed(1)}" ` +
108
+ `font-size="${EDGE_LABEL_FONT_SIZE}" fill="${COLOR_TEXT_MUTED}" dominant-baseline="middle">${esc(edge.label)}</text>`);
109
+ }
110
+ return;
111
+ }
112
+ const x1 = actorCx(fromCol);
113
+ const x2 = actorCx(toCol);
114
+ const xMid = (x1 + x2) / 2;
115
+ const dir = x2 > x1 ? 1 : -1;
116
+ parts.push(`<line x1="${x1.toFixed(1)}" y1="${y}" x2="${(x2 - dir * ARROW_SIZE).toFixed(1)}" y2="${y}" ` +
117
+ `stroke="${stroke}" stroke-width="1.5"${dash}/>`, arrowhead(x1, x2, y, isDashed));
118
+ if (edge.label) {
119
+ parts.push(`<text x="${xMid.toFixed(1)}" y="${(y - 7).toFixed(1)}" ` +
120
+ `font-size="${EDGE_LABEL_FONT_SIZE}" fill="${COLOR_TEXT_BODY}" text-anchor="middle">${esc(edge.label)}</text>`);
121
+ }
122
+ });
123
+ return {
124
+ svg: svgDocument(width, height, parts.join('\n')),
125
+ width,
126
+ height,
127
+ boxes: [],
128
+ edges: [],
129
+ features: {
130
+ cards: false, checkpoints: false, twoColumn: false,
131
+ legend: false, categoryColors: false,
132
+ },
133
+ };
134
+ },
135
+ };
136
+ //# sourceMappingURL=sequence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../../src/adapters/sequence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { Emphasis } from '../domain/spec.js';
2
+ /** Escape text for safe inclusion in SVG/XML text nodes + attributes. */
3
+ export declare function esc(s: string): string;
4
+ /**
5
+ * Estimate rendered text width with no font engine available.
6
+ *
7
+ * @param text the string to measure
8
+ * @param fontSize px font size
9
+ * @returns estimated width in px
10
+ */
11
+ export declare function estimateTextWidth(text: string, fontSize?: number): number;
12
+ /**
13
+ * Greedy word-wrap a label to fit a maximum pixel width. A single word longer
14
+ * than the limit is kept on its own line (it sets the line width) rather than
15
+ * being broken mid-word. Used so graph nodes with long sentence labels grow in
16
+ * height instead of overflowing their box.
17
+ *
18
+ * @param text the label to wrap
19
+ * @param maxWidth maximum line width in px
20
+ * @param fontSize px font size for width estimation
21
+ * @returns the wrapped lines (always ≥1)
22
+ */
23
+ export declare function wrapText(text: string, maxWidth: number, fontSize?: number): string[];
24
+ /**
25
+ * Theme tokens keyed by emphasis. A single light palette for the baseline;
26
+ * Phase 2 will add a dark variant + per-engine theming.
27
+ */
28
+ export declare const PALETTE: Record<Emphasis, {
29
+ fill: string;
30
+ stroke: string;
31
+ text: string;
32
+ }>;
33
+ /** Resolve a palette entry, defaulting to `normal`. */
34
+ export declare function palette(emphasis: Emphasis | undefined): {
35
+ fill: string;
36
+ stroke: string;
37
+ text: string;
38
+ };
39
+ /** Build the arrowhead marker defs (filled + open). */
40
+ export declare function arrowDefs(): string;
41
+ /** Wrap body markup in a complete, standalone SVG document. */
42
+ export declare function svgDocument(width: number, height: number, body: string): string;
43
+ //# sourceMappingURL=svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/adapters/svg.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,yEAAyE;AACzE,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAuB,GAAG,MAAM,CAEvF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAuB,GAAG,MAAM,EAAE,CAgBlG;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAOpF,CAAC;AAEF,uDAAuD;AACvD,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS;UAVP,MAAM;YAAU,MAAM;UAAQ,MAAM;EAYlF;AAED,uDAAuD;AACvD,wBAAgB,SAAS,IAAI,MAAM,CASlC;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM/E"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Tiny SVG building helpers. No dependency — just string assembly with proper
3
+ * escaping. Shared by techniques that emit SVG directly (the baseline today;
4
+ * Satori/resvg techniques in Phase 2 produce SVG via their own engines).
5
+ */
6
+ import { AVG_CHAR_WIDTH_EM, NODE_LABEL_FONT_SIZE, } from '../constants.js';
7
+ /** Escape text for safe inclusion in SVG/XML text nodes + attributes. */
8
+ export function esc(s) {
9
+ return s
10
+ .replace(/&/g, '&amp;')
11
+ .replace(/</g, '&lt;')
12
+ .replace(/>/g, '&gt;')
13
+ .replace(/"/g, '&quot;')
14
+ .replace(/'/g, '&#39;');
15
+ }
16
+ /**
17
+ * Estimate rendered text width with no font engine available.
18
+ *
19
+ * @param text the string to measure
20
+ * @param fontSize px font size
21
+ * @returns estimated width in px
22
+ */
23
+ export function estimateTextWidth(text, fontSize = NODE_LABEL_FONT_SIZE) {
24
+ return text.length * AVG_CHAR_WIDTH_EM * fontSize;
25
+ }
26
+ /**
27
+ * Greedy word-wrap a label to fit a maximum pixel width. A single word longer
28
+ * than the limit is kept on its own line (it sets the line width) rather than
29
+ * being broken mid-word. Used so graph nodes with long sentence labels grow in
30
+ * height instead of overflowing their box.
31
+ *
32
+ * @param text the label to wrap
33
+ * @param maxWidth maximum line width in px
34
+ * @param fontSize px font size for width estimation
35
+ * @returns the wrapped lines (always ≥1)
36
+ */
37
+ export function wrapText(text, maxWidth, fontSize = NODE_LABEL_FONT_SIZE) {
38
+ const words = text.split(/\s+/).filter(Boolean);
39
+ if (words.length === 0)
40
+ return [text];
41
+ const lines = [];
42
+ let line = '';
43
+ for (const word of words) {
44
+ const candidate = line ? `${line} ${word}` : word;
45
+ if (line && estimateTextWidth(candidate, fontSize) > maxWidth) {
46
+ lines.push(line);
47
+ line = word;
48
+ }
49
+ else {
50
+ line = candidate;
51
+ }
52
+ }
53
+ if (line)
54
+ lines.push(line);
55
+ return lines;
56
+ }
57
+ /**
58
+ * Theme tokens keyed by emphasis. A single light palette for the baseline;
59
+ * Phase 2 will add a dark variant + per-engine theming.
60
+ */
61
+ export const PALETTE = {
62
+ normal: { fill: '#f1f5f9', stroke: '#94a3b8', text: '#0f172a' },
63
+ primary: { fill: '#dbeafe', stroke: '#3b82f6', text: '#0c2a5b' },
64
+ accent: { fill: '#ede9fe', stroke: '#8b5cf6', text: '#3b1d80' },
65
+ muted: { fill: '#f8fafc', stroke: '#cbd5e1', text: '#475569' },
66
+ danger: { fill: '#fee2e2', stroke: '#ef4444', text: '#7f1d1d' },
67
+ success: { fill: '#dcfce7', stroke: '#22c55e', text: '#14532d' },
68
+ };
69
+ /** Resolve a palette entry, defaulting to `normal`. */
70
+ export function palette(emphasis) {
71
+ return PALETTE[emphasis ?? 'normal'];
72
+ }
73
+ /** Build the arrowhead marker defs (filled + open). */
74
+ export function arrowDefs() {
75
+ return `<defs>
76
+ <marker id="arrow-filled" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
77
+ <path d="M0,0 L10,5 L0,10 z" fill="#475569"/>
78
+ </marker>
79
+ <marker id="arrow-open" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
80
+ <path d="M0,0 L10,5 L0,10" fill="none" stroke="#475569" stroke-width="1.5"/>
81
+ </marker>
82
+ </defs>`;
83
+ }
84
+ /** Wrap body markup in a complete, standalone SVG document. */
85
+ export function svgDocument(width, height, body) {
86
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif">
87
+ <rect x="0" y="0" width="${width}" height="${height}" fill="#ffffff"/>
88
+ ${arrowDefs()}
89
+ ${body}
90
+ </svg>`;
91
+ }
92
+ //# sourceMappingURL=svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.js","sourceRoot":"","sources":["../../src/adapters/svg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * TechniqueRegistry — injectable registry for layout engines.
3
+ *
4
+ * HEXAGONAL ARCHITECTURE INVARIANT:
5
+ * This file MUST NEVER import from '../adapters/' or any concrete adapter.
6
+ * It depends only on the Technique port interface (application layer).
7
+ * Adapters are registered externally from the composition root (index.ts).
8
+ *
9
+ * OPEN/CLOSED:
10
+ * Adding a new engine = register it in index.ts + add its key to the
11
+ * EngineKey union in router.ts. This class itself never changes.
12
+ *
13
+ * DEPENDENCY INVERSION:
14
+ * High-level modules (router) depend on this abstraction.
15
+ * Low-level adapters register themselves at startup; they never appear here.
16
+ */
17
+ import type { Technique } from '../ports/Technique.js';
18
+ export declare class TechniqueRegistry {
19
+ private readonly map;
20
+ /**
21
+ * Register a layout engine.
22
+ * Returns `this` for fluent chaining at the composition root.
23
+ *
24
+ * @param key stable engine identifier
25
+ * @param technique the Technique implementation
26
+ * @throws if the key is already registered (prevents silent overwrites)
27
+ */
28
+ register(key: string, technique: Technique): this;
29
+ /**
30
+ * Look up a technique by engine key.
31
+ *
32
+ * @param key the engine identifier
33
+ * @throws if no technique is registered for that key
34
+ */
35
+ get(key: string): Technique;
36
+ /** Whether a key is registered. */
37
+ has(key: string): boolean;
38
+ /** All registered techniques in insertion order. */
39
+ techniques(): Technique[];
40
+ /** All registered engine keys in insertion order. */
41
+ keys(): string[];
42
+ }
43
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/application/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgC;IAEpD;;;;;;;OAOG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAUjD;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS;IAW3B,mCAAmC;IACnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,oDAAoD;IACpD,UAAU,IAAI,SAAS,EAAE;IAIzB,qDAAqD;IACrD,IAAI,IAAI,MAAM,EAAE;CAGjB"}