@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,69 @@
1
+ /**
2
+ * Validate structural integrity of a spec: unique node ids, edges/groups/
3
+ * annotations referencing real nodes, non-empty labels.
4
+ *
5
+ * @param spec the diagram spec to check
6
+ * @returns a list of issues; empty means valid
7
+ */
8
+ export function validateSpec(spec) {
9
+ const issues = [];
10
+ if (!spec.id)
11
+ issues.push({ path: 'id', message: 'spec.id is required' });
12
+ if (!spec.kind)
13
+ issues.push({ path: 'kind', message: 'spec.kind is required' });
14
+ if (!Array.isArray(spec.nodes) || spec.nodes.length === 0) {
15
+ issues.push({ path: 'nodes', message: 'spec.nodes must be a non-empty array' });
16
+ }
17
+ const ids = new Set();
18
+ spec.nodes?.forEach((n, i) => {
19
+ if (!n.id)
20
+ issues.push({ path: `nodes[${i}].id`, message: 'node id is required' });
21
+ else if (ids.has(n.id))
22
+ issues.push({ path: `nodes[${i}].id`, message: `duplicate node id "${n.id}"` });
23
+ else
24
+ ids.add(n.id);
25
+ if (!n.label?.trim())
26
+ issues.push({ path: `nodes[${i}].label`, message: `node "${n.id}" has an empty label` });
27
+ });
28
+ spec.edges?.forEach((e, i) => {
29
+ if (!ids.has(e.from))
30
+ issues.push({ path: `edges[${i}].from`, message: `edge from unknown node "${e.from}"` });
31
+ if (!ids.has(e.to))
32
+ issues.push({ path: `edges[${i}].to`, message: `edge to unknown node "${e.to}"` });
33
+ });
34
+ const groupIds = new Set();
35
+ spec.groups?.forEach((g, i) => {
36
+ if (groupIds.has(g.id))
37
+ issues.push({ path: `groups[${i}].id`, message: `duplicate group id "${g.id}"` });
38
+ groupIds.add(g.id);
39
+ g.members.forEach((m) => {
40
+ if (!ids.has(m))
41
+ issues.push({ path: `groups[${i}].members`, message: `group "${g.id}" has unknown member "${m}"` });
42
+ });
43
+ });
44
+ spec.groups?.forEach((g, i) => {
45
+ if (g.parent && !groupIds.has(g.parent))
46
+ issues.push({ path: `groups[${i}].parent`, message: `group "${g.id}" has unknown parent "${g.parent}"` });
47
+ });
48
+ spec.annotations?.forEach((a, i) => {
49
+ if (a.target && !ids.has(a.target) && !groupIds.has(a.target))
50
+ issues.push({ path: `annotations[${i}].target`, message: `annotation targets unknown id "${a.target}"` });
51
+ if (!a.text?.trim())
52
+ issues.push({ path: `annotations[${i}].text`, message: 'annotation has empty text' });
53
+ });
54
+ // Categories: unique ids; nodes referencing a category must reference a real one.
55
+ const categoryIds = new Set();
56
+ spec.categories?.forEach((c, i) => {
57
+ if (categoryIds.has(c.id))
58
+ issues.push({ path: `categories[${i}].id`, message: `duplicate category id "${c.id}"` });
59
+ categoryIds.add(c.id);
60
+ if (!c.label?.trim())
61
+ issues.push({ path: `categories[${i}].label`, message: `category "${c.id}" has an empty label` });
62
+ });
63
+ spec.nodes?.forEach((n, i) => {
64
+ if (n.category && categoryIds.size > 0 && !categoryIds.has(n.category))
65
+ issues.push({ path: `nodes[${i}].category`, message: `node "${n.id}" references unknown category "${n.category}"` });
66
+ });
67
+ return issues;
68
+ }
69
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/domain/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @sgummalla-works/sketchon — public API + COMPOSITION ROOT.
3
+ *
4
+ * ── HEXAGONAL ARCHITECTURE — COMPOSITION ROOT RULES ──────────────────────────
5
+ * This file is the ONLY place in the package that may import concrete adapters.
6
+ * All other application/domain files must be free of adapter imports.
7
+ * The dependency rules are enforced by architecture guard tests
8
+ * (src/application/architecture.test.ts).
9
+ *
10
+ * Dependency flow (all arrows point inward):
11
+ * adapters/ ──► application/ ──► domain/
12
+ * adapters/ ──► ports/
13
+ * index.ts (composition root) wires all layers together.
14
+ *
15
+ * ── STABLE PUBLIC API ────────────────────────────────────────────────────────
16
+ * renderDiagram(spec) → SVG + metadata (auto-routes engine)
17
+ * validateSpec(spec) → ValidationIssue[] (pure, zero deps)
18
+ * selectEngineKey(spec) → EngineKey
19
+ * selectEngine(spec) → Technique
20
+ * TECHNIQUES → all registered engines (for the lab)
21
+ * DiagramSpec + all spec types
22
+ */
23
+ export * from './domain/spec.js';
24
+ export * from './domain/validate.js';
25
+ export * from './domain/theme.js';
26
+ export type { Technique, RenderResult, PlacedBox, PlacedEdge, StructuralFeatures, } from './ports/Technique.js';
27
+ export { TechniqueRegistry } from './application/registry.js';
28
+ export { type EngineKey } from './application/router.js';
29
+ export * from './constants.js';
30
+ export { esc, estimateTextWidth, wrapText, palette, PALETTE, arrowDefs, svgDocument, } from './adapters/svg.js';
31
+ export { loadFonts } from './adapters/fonts.js';
32
+ export { emojiToDataUri, emojiCode } from './adapters/emoji.js';
33
+ export { satoriTechnique } from './adapters/satori.js';
34
+ export { elkTechnique } from './adapters/elk.js';
35
+ export { sequenceTechnique } from './adapters/sequence.js';
36
+ export { baselineTechnique } from './adapters/baseline.js';
37
+ import { TechniqueRegistry } from './application/registry.js';
38
+ /**
39
+ * The application-wide registry. Pre-populated with all built-in engines.
40
+ * Consumers may call `.register()` to add custom engines.
41
+ */
42
+ export declare const REGISTRY: TechniqueRegistry;
43
+ /** All registered techniques — used by the lab harness. */
44
+ export declare const TECHNIQUES: import("./ports/Technique.js").Technique[];
45
+ /**
46
+ * Select the engine key that would render a spec.
47
+ * Useful for logging / debugging which engine was chosen.
48
+ */
49
+ export declare const selectEngineKey: (spec: import("./domain/spec.js").DiagramSpec) => import("./application/router.js").EngineKey;
50
+ /**
51
+ * Resolve the Technique that will render a spec.
52
+ */
53
+ export declare const selectEngine: (spec: import("./domain/spec.js").DiagramSpec) => import("./ports/Technique.js").Technique;
54
+ /**
55
+ * Production render entry point.
56
+ * Validates routing and delegates to the chosen layout engine.
57
+ *
58
+ * @param spec the coordinate-free diagram spec
59
+ * @returns the rendered SVG + width/height/metadata
60
+ */
61
+ export declare const renderDiagram: (spec: import("./domain/spec.js").DiagramSpec) => import("./ports/Technique.js").RenderResult | Promise<import("./ports/Technique.js").RenderResult>;
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAGlC,YAAY,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,UAAU,EACV,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGzD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,GAAG,EACH,iBAAiB,EACjB,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,SAAS,EAAE,MAAsB,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAE,MAAQ,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAW,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAK3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAO9D;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,iBAImB,CAAC;AAQ3C,2DAA2D;AAC3D,eAAO,MAAM,UAAU,4CAAwB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,eAAe,+FAAsC,CAAC;AAEnE;;GAEG;AACH,eAAO,MAAM,YAAY,4FAAmC,CAAC;AAE7D;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,sJAAoC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @sgummalla-works/sketchon — public API + COMPOSITION ROOT.
3
+ *
4
+ * ── HEXAGONAL ARCHITECTURE — COMPOSITION ROOT RULES ──────────────────────────
5
+ * This file is the ONLY place in the package that may import concrete adapters.
6
+ * All other application/domain files must be free of adapter imports.
7
+ * The dependency rules are enforced by architecture guard tests
8
+ * (src/application/architecture.test.ts).
9
+ *
10
+ * Dependency flow (all arrows point inward):
11
+ * adapters/ ──► application/ ──► domain/
12
+ * adapters/ ──► ports/
13
+ * index.ts (composition root) wires all layers together.
14
+ *
15
+ * ── STABLE PUBLIC API ────────────────────────────────────────────────────────
16
+ * renderDiagram(spec) → SVG + metadata (auto-routes engine)
17
+ * validateSpec(spec) → ValidationIssue[] (pure, zero deps)
18
+ * selectEngineKey(spec) → EngineKey
19
+ * selectEngine(spec) → Technique
20
+ * TECHNIQUES → all registered engines (for the lab)
21
+ * DiagramSpec + all spec types
22
+ */
23
+ // ── Domain (pure — zero external deps) ───────────────────────────────────────
24
+ export * from './domain/spec.js';
25
+ export * from './domain/validate.js';
26
+ export * from './domain/theme.js';
27
+ // ── Application (registry + router — no adapter imports) ──────────────────────
28
+ export { TechniqueRegistry } from './application/registry.js';
29
+ export {} from './application/router.js';
30
+ // ── Constants + shared render helpers ────────────────────────────────────────
31
+ export * from './constants.js';
32
+ export { esc, estimateTextWidth, wrapText, palette, PALETTE, arrowDefs, svgDocument, } from './adapters/svg.js';
33
+ // ── Node-only loaders (filesystem — not browser-safe) ────────────────────────
34
+ export { loadFonts } from './adapters/fonts.js';
35
+ export { emojiToDataUri, emojiCode } from './adapters/emoji.js';
36
+ // ── Concrete adapters (exported for advanced use + the lab) ───────────────────
37
+ export { satoriTechnique } from './adapters/satori.js';
38
+ export { elkTechnique } from './adapters/elk.js';
39
+ export { sequenceTechnique } from './adapters/sequence.js';
40
+ export { baselineTechnique } from './adapters/baseline.js';
41
+ // ── COMPOSITION ROOT ──────────────────────────────────────────────────────────
42
+ // Wire all adapters into the registry. This is the only place that is allowed
43
+ // to import adapters. Everything below is infrastructure glue.
44
+ import { TechniqueRegistry } from './application/registry.js';
45
+ import { Router } from './application/router.js';
46
+ import { satoriTechnique } from './adapters/satori.js';
47
+ import { elkTechnique } from './adapters/elk.js';
48
+ import { sequenceTechnique } from './adapters/sequence.js';
49
+ import { baselineTechnique } from './adapters/baseline.js';
50
+ /**
51
+ * The application-wide registry. Pre-populated with all built-in engines.
52
+ * Consumers may call `.register()` to add custom engines.
53
+ */
54
+ export const REGISTRY = new TechniqueRegistry()
55
+ .register('baseline', baselineTechnique)
56
+ .register('satori', satoriTechnique)
57
+ .register('elk', elkTechnique)
58
+ .register('sequence', sequenceTechnique);
59
+ /**
60
+ * The application-wide router, wired to the shared registry.
61
+ * Exposes the primary use-case functions as bound methods.
62
+ */
63
+ const router = new Router(REGISTRY);
64
+ /** All registered techniques — used by the lab harness. */
65
+ export const TECHNIQUES = REGISTRY.techniques();
66
+ /**
67
+ * Select the engine key that would render a spec.
68
+ * Useful for logging / debugging which engine was chosen.
69
+ */
70
+ export const selectEngineKey = router.selectEngineKey.bind(router);
71
+ /**
72
+ * Resolve the Technique that will render a spec.
73
+ */
74
+ export const selectEngine = router.selectEngine.bind(router);
75
+ /**
76
+ * Production render entry point.
77
+ * Validates routing and delegates to the chosen layout engine.
78
+ *
79
+ * @param spec the coordinate-free diagram spec
80
+ * @returns the rendered SVG + width/height/metadata
81
+ */
82
+ export const renderDiagram = router.renderDiagram.bind(router);
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,gFAAgF;AAChF,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAWlC,iFAAiF;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAkB,MAAM,yBAAyB,CAAC;AAEzD,gFAAgF;AAChF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,GAAG,EACH,iBAAiB,EACjB,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,gFAAgF;AAChF,OAAO,EAAE,SAAS,EAAE,MAAsB,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,iFAAiF;AACjF,OAAO,EAAE,eAAe,EAAE,MAAQ,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAW,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,iFAAiF;AACjF,8EAA8E;AAC9E,+DAA+D;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAQ,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAW,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAsB,IAAI,iBAAiB,EAAE;KAC/D,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;KACvC,QAAQ,CAAC,QAAQ,EAAI,eAAe,CAAC;KACrC,QAAQ,CAAC,KAAK,EAAO,YAAY,CAAC;KAClC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The Technique port — the single contract every layout engine must implement.
3
+ *
4
+ * A Technique is the "half B" of the pipeline: it takes a coordinate-free
5
+ * DiagramSpec and produces a rendered SVG. The application layer depends only
6
+ * on this interface — never on a concrete adapter (Satori, ELK, Sequence…).
7
+ * New engines are added by implementing this interface and registering them;
8
+ * no existing code changes.
9
+ */
10
+ import type { DiagramSpec } from '../domain/spec.js';
11
+ /** An axis-aligned box placed by the layout engine, for geometry eval. */
12
+ export interface PlacedBox {
13
+ id: string;
14
+ x: number;
15
+ y: number;
16
+ w: number;
17
+ h: number;
18
+ label: string;
19
+ fontSize: number;
20
+ /** Actual width of the widest rendered line (for wrapped labels). */
21
+ contentWidth?: number;
22
+ role: 'node' | 'group' | 'annotation';
23
+ }
24
+ /** A straight edge segment, for crossing detection. */
25
+ export interface PlacedEdge {
26
+ x1: number;
27
+ y1: number;
28
+ x2: number;
29
+ y2: number;
30
+ fromId: string;
31
+ toId: string;
32
+ }
33
+ /**
34
+ * Structural features a technique actually rendered.
35
+ * Used by the fidelity metric to detect "geometrically clean but wrong kind
36
+ * of picture" — a geometry score alone cannot tell a box-stack from a rich
37
+ * card-column.
38
+ */
39
+ export interface StructuralFeatures {
40
+ cards: boolean;
41
+ checkpoints: boolean;
42
+ twoColumn: boolean;
43
+ legend: boolean;
44
+ categoryColors: boolean;
45
+ }
46
+ /** The complete output of a layout engine for a single spec. */
47
+ export interface RenderResult {
48
+ svg: string;
49
+ width: number;
50
+ height: number;
51
+ /** Omit when overlap is structurally impossible (e.g. Satori flexbox). */
52
+ boxes?: PlacedBox[];
53
+ edges?: PlacedEdge[];
54
+ features?: StructuralFeatures;
55
+ }
56
+ /**
57
+ * The Strategy interface every rendering adapter implements.
58
+ * `render` may be async — Satori is asynchronous.
59
+ */
60
+ export interface Technique {
61
+ /** Stable key used to select this engine from the registry. */
62
+ readonly key: string;
63
+ /** Human label shown in the gallery header. */
64
+ readonly name: string;
65
+ /** One-line blurb describing the approach. */
66
+ readonly blurb: string;
67
+ render(spec: DiagramSpec): RenderResult | Promise<RenderResult>;
68
+ }
69
+ //# sourceMappingURL=Technique.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Technique.d.ts","sourceRoot":"","sources":["../../src/ports/Technique.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,YAAY,CAAC;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACjE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Technique.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Technique.js","sourceRoot":"","sources":["../../src/ports/Technique.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@sgummalla-works/sketchon",
3
+ "version": "0.1.0",
4
+ "description": "Sketchon — coordinate-free diagram rendering. A model authors the spec; a deterministic engine computes every pixel. Spec in, SVG out.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist/",
17
+ "assets/",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.build.json",
23
+ "prebuild": "rm -rf dist",
24
+ "typecheck": "tsc --noEmit",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/sgummalla79/sgummalla_works_js_packages"
35
+ },
36
+ "keywords": [
37
+ "diagram",
38
+ "rendering",
39
+ "svg",
40
+ "satori",
41
+ "elkjs",
42
+ "browser",
43
+ "react"
44
+ ],
45
+ "dependencies": {
46
+ "elkjs": "^0.11.0",
47
+ "satori": "^0.26.0"
48
+ },
49
+ "devDependencies": {
50
+ "vitest": "^4.1.7"
51
+ }
52
+ }