sketchmark 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/package.json +1 -7
  2. package/ANIMATABLE_MATRIX.md +0 -177
  3. package/KERNEL_SPEC.md +0 -412
  4. package/PACKS.md +0 -81
  5. package/PRESETS.md +0 -182
  6. package/dist/src/builders/index.d.ts +0 -64
  7. package/dist/src/builders/index.js +0 -212
  8. package/dist/src/compounds.d.ts +0 -13
  9. package/dist/src/compounds.js +0 -118
  10. package/dist/src/deck.d.ts +0 -4
  11. package/dist/src/deck.js +0 -91
  12. package/dist/src/export/index.d.ts +0 -8
  13. package/dist/src/export/index.js +0 -15
  14. package/dist/src/kernel.d.ts +0 -8
  15. package/dist/src/kernel.js +0 -68
  16. package/dist/src/motion.d.ts +0 -4
  17. package/dist/src/motion.js +0 -262
  18. package/dist/src/patch.d.ts +0 -5
  19. package/dist/src/patch.js +0 -72
  20. package/dist/src/player/index.d.ts +0 -68
  21. package/dist/src/player/index.js +0 -600
  22. package/dist/src/project.d.ts +0 -11
  23. package/dist/src/project.js +0 -107
  24. package/dist/src/render/raw-three.d.ts +0 -7
  25. package/dist/src/render/raw-three.js +0 -17
  26. package/dist/src/render/three-html.d.ts +0 -2
  27. package/dist/src/render/three-html.js +0 -257
  28. package/dist/src/render/three-preview-svg.d.ts +0 -3
  29. package/dist/src/render/three-preview-svg.js +0 -102
  30. package/dist/src/scenes.d.ts +0 -4
  31. package/dist/src/scenes.js +0 -26
  32. package/dist/src/sequences.d.ts +0 -43
  33. package/dist/src/sequences.js +0 -109
  34. package/dist/src/shapes/builtins.d.ts +0 -2
  35. package/dist/src/shapes/builtins.js +0 -393
  36. package/dist/src/shapes/common.d.ts +0 -9
  37. package/dist/src/shapes/common.js +0 -76
  38. package/dist/src/shapes/geometry.d.ts +0 -22
  39. package/dist/src/shapes/geometry.js +0 -166
  40. package/dist/src/shapes/index.d.ts +0 -2
  41. package/dist/src/shapes/index.js +0 -18
  42. package/dist/src/shapes/registry.d.ts +0 -8
  43. package/dist/src/shapes/registry.js +0 -31
  44. package/dist/src/shapes/types.d.ts +0 -32
  45. package/dist/src/shapes/types.js +0 -2
  46. package/examples/1730642890464.jpg +0 -0
  47. package/examples/app-screen.svg +0 -1
  48. package/examples/app-screen.visual.json +0 -503
  49. package/examples/dashboard-table.svg +0 -1
  50. package/examples/dashboard-table.visual.json +0 -708
  51. package/examples/dev-docs.svg +0 -1
  52. package/examples/dev-docs.visual.json +0 -248
  53. package/examples/explainer.mp4 +0 -0
  54. package/examples/explainer.visual.json +0 -1713
  55. package/examples/group-origin-effects-lab-check.svg +0 -1
  56. package/examples/group-origin-effects-lab.visual.json +0 -1880
  57. package/examples/image-clip-radius.visual.json +0 -271
  58. package/examples/make-app-screen.cjs +0 -368
  59. package/examples/make-dashboard-table.cjs +0 -277
  60. package/examples/make-dev-docs.cjs +0 -233
  61. package/examples/make-explainer.cjs +0 -438
  62. package/examples/make-group-origin-effects-lab.cjs +0 -370
  63. package/examples/make-image-clip-radius.cjs +0 -169
  64. package/examples/make-modal-dialog.cjs +0 -355
  65. package/examples/make-origin-effects-lab.cjs +0 -311
  66. package/examples/make-preset-character-motion.cjs +0 -32
  67. package/examples/make-presets-demo.cjs +0 -30
  68. package/examples/make-pricing.cjs +0 -286
  69. package/examples/make-product-demo.cjs +0 -468
  70. package/examples/make-product-hero.cjs +0 -223
  71. package/examples/make-release-notes.cjs +0 -333
  72. package/examples/make-settings-panel.cjs +0 -435
  73. package/examples/make-split-preview.cjs +0 -248
  74. package/examples/make-storyboard.cjs +0 -215
  75. package/examples/make-transcript.cjs +0 -234
  76. package/examples/make-typography-test.cjs +0 -397
  77. package/examples/make-ui-demo-explainer.cjs +0 -1094
  78. package/examples/make-ui-flow.cjs +0 -762
  79. package/examples/make-walkthrough.cjs +0 -815
  80. package/examples/modal-dialog.svg +0 -1
  81. package/examples/modal-dialog.visual.json +0 -239
  82. package/examples/origin-effects-lab-check.svg +0 -1
  83. package/examples/origin-effects-lab.visual.json +0 -1412
  84. package/examples/preset-character-motion.visual.json +0 -949
  85. package/examples/presets-demo.visual.json +0 -787
  86. package/examples/pricing.svg +0 -1
  87. package/examples/pricing.visual.json +0 -652
  88. package/examples/product-demo.mp4 +0 -0
  89. package/examples/product-demo.visual.json +0 -866
  90. package/examples/product-hero.svg +0 -1
  91. package/examples/product-hero.visual.json +0 -242
  92. package/examples/release-notes.svg +0 -1
  93. package/examples/release-notes.visual.json +0 -467
  94. package/examples/settings-panel.svg +0 -1
  95. package/examples/settings-panel.visual.json +0 -501
  96. package/examples/split-preview.svg +0 -1
  97. package/examples/split-preview.visual.json +0 -124
  98. package/examples/storyboard.svg +0 -1
  99. package/examples/storyboard.visual.json +0 -312
  100. package/examples/transcript.svg +0 -1
  101. package/examples/transcript.visual.json +0 -407
  102. package/examples/typography-indent-check.svg +0 -1
  103. package/examples/typography-lineheight-0.svg +0 -1
  104. package/examples/typography-lineheight-2.svg +0 -1
  105. package/examples/typography-test-check.svg +0 -1
  106. package/examples/typography-test.svg +0 -1
  107. package/examples/typography-test.visual.json +0 -757
  108. package/examples/ui-demo-explainer-billing.svg +0 -1
  109. package/examples/ui-demo-explainer-check.svg +0 -1
  110. package/examples/ui-demo-explainer-save.svg +0 -1
  111. package/examples/ui-demo-explainer-toggle.svg +0 -1
  112. package/examples/ui-demo-explainer.mp4 +0 -0
  113. package/examples/ui-demo-explainer.visual.json +0 -2597
  114. package/examples/ui-flow.mp4 +0 -0
  115. package/examples/ui-flow.visual.json +0 -1211
  116. package/examples/walkthrough.mp4 +0 -0
  117. package/examples/walkthrough.visual.json +0 -1372
@@ -1,277 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- const width = 1100;
5
- const height = 560;
6
- const bg = "#f8fafc";
7
- const font = "Inter, system-ui, sans-serif";
8
-
9
- const colors = {
10
- pageTitle: "#0f172a",
11
- tableTitle: "#1e293b",
12
- headerBg: "#f1f5f9",
13
- headerText: "#475569",
14
- rowBg: "#ffffff",
15
- rowAltBg: "#fafbfc",
16
- rowBorder: "#e2e8f0",
17
- cellText: "#334155",
18
- cellMuted: "#64748b",
19
- tableBorder: "#e2e8f0",
20
- statusGreen: "#10b981",
21
- statusGreenBg: "#d1fae5",
22
- statusYellow: "#d97706",
23
- statusYellowBg: "#fef3c7",
24
- statusRed: "#dc2626",
25
- statusRedBg: "#fee2e2",
26
- statusGray: "#64748b",
27
- statusGrayBg: "#f1f5f9"
28
- };
29
-
30
- const padX = 48;
31
- let y = 40;
32
-
33
- const elements = [];
34
-
35
- // Page title
36
- elements.push({
37
- id: "page-title",
38
- type: "text",
39
- x: padX,
40
- y: y,
41
- text: "Operations Dashboard",
42
- align: "left",
43
- valign: "top",
44
- fontSize: 26,
45
- fontFamily: font,
46
- weight: 700,
47
- fill: colors.pageTitle
48
- });
49
- y += 44;
50
-
51
- // Table title
52
- elements.push({
53
- id: "table-title",
54
- type: "text",
55
- x: padX,
56
- y: y,
57
- text: "Service Health Overview",
58
- align: "left",
59
- valign: "top",
60
- fontSize: 16,
61
- fontFamily: font,
62
- weight: 600,
63
- fill: colors.tableTitle
64
- });
65
- y += 32;
66
-
67
- // Table structure
68
- const tableX = padX;
69
- const tableW = width - padX * 2;
70
- const rowH = 44;
71
- const headerH = 40;
72
-
73
- const columns = [
74
- { key: "service", label: "Service", width: 200, align: "left" },
75
- { key: "requests", label: "Requests", width: 120, align: "right" },
76
- { key: "latency", label: "Avg Latency", width: 120, align: "right" },
77
- { key: "errors", label: "Error Rate", width: 110, align: "right" },
78
- { key: "uptime", label: "Uptime", width: 100, align: "right" },
79
- { key: "status", label: "Status", width: 110, align: "center" }
80
- ];
81
-
82
- const rows = [
83
- { service: "API Gateway", requests: "1.2M", latency: "42ms", errors: "0.02%", uptime: "99.99%", status: "Healthy" },
84
- { service: "Auth Service", requests: "890K", latency: "28ms", errors: "0.01%", uptime: "99.98%", status: "Healthy" },
85
- { service: "User Database", requests: "2.4M", latency: "8ms", errors: "0.00%", uptime: "100%", status: "Healthy" },
86
- { service: "Cache Layer", requests: "5.1M", latency: "2ms", errors: "0.03%", uptime: "99.95%", status: "Degraded" },
87
- { service: "Search Index", requests: "340K", latency: "156ms", errors: "1.20%", uptime: "98.50%", status: "Warning" },
88
- { service: "Legacy Sync", requests: "45K", latency: "890ms", errors: "4.50%", uptime: "94.20%", status: "Critical" }
89
- ];
90
-
91
- const statusColors = {
92
- Healthy: { bg: colors.statusGreenBg, text: colors.statusGreen },
93
- Degraded: { bg: colors.statusYellowBg, text: colors.statusYellow },
94
- Warning: { bg: colors.statusYellowBg, text: colors.statusYellow },
95
- Critical: { bg: colors.statusRedBg, text: colors.statusRed },
96
- Offline: { bg: colors.statusGrayBg, text: colors.statusGray }
97
- };
98
-
99
- // Table outer border
100
- const tableH = headerH + rows.length * rowH;
101
- elements.push({
102
- id: "table-border",
103
- type: "path",
104
- d: roundedRect(tableX, y, tableW, tableH, 8),
105
- fill: colors.rowBg,
106
- stroke: colors.tableBorder,
107
- strokeWidth: 1
108
- });
109
-
110
- // Header row background
111
- elements.push({
112
- id: "header-bg",
113
- type: "path",
114
- d: `M ${tableX + 8} ${y} L ${tableX + tableW - 8} ${y} Q ${tableX + tableW} ${y} ${tableX + tableW} ${y + 8} L ${tableX + tableW} ${y + headerH} L ${tableX} ${y + headerH} L ${tableX} ${y + 8} Q ${tableX} ${y} ${tableX + 8} ${y} Z`,
115
- fill: colors.headerBg,
116
- stroke: "none"
117
- });
118
-
119
- // Header row bottom border
120
- elements.push({
121
- id: "header-border",
122
- type: "path",
123
- d: `M ${tableX} ${y + headerH} L ${tableX + tableW} ${y + headerH}`,
124
- stroke: colors.rowBorder,
125
- strokeWidth: 1,
126
- fill: "none"
127
- });
128
-
129
- // Column headers
130
- let colX = tableX;
131
- columns.forEach((col, i) => {
132
- const textX = col.align === "left" ? colX + 16 :
133
- col.align === "right" ? colX + col.width - 16 :
134
- colX + col.width / 2;
135
-
136
- elements.push({
137
- id: `header-${col.key}`,
138
- type: "text",
139
- x: textX,
140
- y: y + headerH / 2,
141
- text: col.label,
142
- align: col.align,
143
- valign: "middle",
144
- fontSize: 12,
145
- fontFamily: font,
146
- weight: 600,
147
- fill: colors.headerText
148
- });
149
-
150
- colX += col.width;
151
- });
152
-
153
- // Data rows
154
- rows.forEach((row, ri) => {
155
- const rowY = y + headerH + ri * rowH;
156
-
157
- // Alternating row background
158
- if (ri % 2 === 1) {
159
- elements.push({
160
- id: `row-bg-${ri}`,
161
- type: "path",
162
- d: `M ${tableX} ${rowY} L ${tableX + tableW} ${rowY} L ${tableX + tableW} ${rowY + rowH} L ${tableX} ${rowY + rowH} Z`,
163
- fill: colors.rowAltBg,
164
- stroke: "none"
165
- });
166
- }
167
-
168
- // Row border (except last)
169
- if (ri < rows.length - 1) {
170
- elements.push({
171
- id: `row-border-${ri}`,
172
- type: "path",
173
- d: `M ${tableX + 16} ${rowY + rowH} L ${tableX + tableW - 16} ${rowY + rowH}`,
174
- stroke: colors.rowBorder,
175
- strokeWidth: 1,
176
- fill: "none"
177
- });
178
- }
179
-
180
- // Cell values
181
- let cx = tableX;
182
- columns.forEach((col) => {
183
- const value = row[col.key];
184
- const textX = col.align === "left" ? cx + 16 :
185
- col.align === "right" ? cx + col.width - 16 :
186
- cx + col.width / 2;
187
-
188
- if (col.key === "status") {
189
- // Status chip
190
- const chipW = 72;
191
- const chipH = 24;
192
- const chipX = cx + (col.width - chipW) / 2;
193
- const chipY = rowY + (rowH - chipH) / 2;
194
- const chipR = 12;
195
- const sc = statusColors[value] || statusColors.Offline;
196
-
197
- elements.push({
198
- id: `cell-${ri}-${col.key}-bg`,
199
- type: "path",
200
- d: roundedRect(chipX, chipY, chipW, chipH, chipR),
201
- fill: sc.bg,
202
- stroke: "none"
203
- });
204
-
205
- elements.push({
206
- id: `cell-${ri}-${col.key}-text`,
207
- type: "text",
208
- x: chipX + chipW / 2,
209
- y: chipY + chipH / 2,
210
- text: value,
211
- align: "center",
212
- valign: "middle",
213
- fontSize: 11,
214
- fontFamily: font,
215
- weight: 600,
216
- fill: sc.text
217
- });
218
- } else if (col.key === "service") {
219
- // Service name (row label)
220
- elements.push({
221
- id: `cell-${ri}-${col.key}`,
222
- type: "text",
223
- x: textX,
224
- y: rowY + rowH / 2,
225
- text: value,
226
- align: col.align,
227
- valign: "middle",
228
- fontSize: 13,
229
- fontFamily: font,
230
- weight: 500,
231
- fill: colors.cellText
232
- });
233
- } else {
234
- // Numeric values
235
- elements.push({
236
- id: `cell-${ri}-${col.key}`,
237
- type: "text",
238
- x: textX,
239
- y: rowY + rowH / 2,
240
- text: value,
241
- align: col.align,
242
- valign: "middle",
243
- fontSize: 13,
244
- fontFamily: font,
245
- weight: 400,
246
- fill: colors.cellMuted
247
- });
248
- }
249
-
250
- cx += col.width;
251
- });
252
- });
253
-
254
- function roundedRect(x, y, w, h, r) {
255
- return [
256
- `M ${x + r} ${y}`,
257
- `L ${x + w - r} ${y}`,
258
- `Q ${x + w} ${y} ${x + w} ${y + r}`,
259
- `L ${x + w} ${y + h - r}`,
260
- `Q ${x + w} ${y + h} ${x + w - r} ${y + h}`,
261
- `L ${x + r} ${y + h}`,
262
- `Q ${x} ${y + h} ${x} ${y + h - r}`,
263
- `L ${x} ${y + r}`,
264
- `Q ${x} ${y} ${x + r} ${y}`,
265
- "Z"
266
- ].join(" ");
267
- }
268
-
269
- const doc = {
270
- version: 1,
271
- canvas: { width, height, background: bg },
272
- elements
273
- };
274
-
275
- const outPath = path.join(__dirname, "dashboard-table.visual.json");
276
- fs.writeFileSync(outPath, JSON.stringify(doc, null, 2));
277
- console.log("Written:", outPath);
@@ -1,233 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- const width = 1280;
5
- const height = 960;
6
- const bg = "#ffffff";
7
- const textColor = "#1a1a2e";
8
- const mutedColor = "#6b7280";
9
- const accentColor = "#2563eb";
10
- const codeBg = "#f1f5f9";
11
- const codeBorder = "#e2e8f0";
12
- const codeText = "#334155";
13
- const bulletColor = "#2563eb";
14
- const btnBg = "#2563eb";
15
- const btnText = "#ffffff";
16
- const font = "Inter, system-ui, sans-serif";
17
- const monoFont = "JetBrains Mono, Fira Code, monospace";
18
-
19
- const padX = 80;
20
- let y = 64;
21
-
22
- const elements = [];
23
-
24
- // Page title
25
- elements.push({
26
- id: "title",
27
- type: "text",
28
- x: padX,
29
- y: y,
30
- text: "Getting Started with the Render API",
31
- align: "left",
32
- valign: "top",
33
- fontSize: 36,
34
- fontFamily: font,
35
- weight: 700,
36
- fill: textColor
37
- });
38
- y += 52;
39
-
40
- // Subtitle
41
- elements.push({
42
- id: "subtitle",
43
- type: "text",
44
- x: padX,
45
- y: y,
46
- text: "A concise guide to integrating the render pipeline into your application.",
47
- align: "left",
48
- valign: "top",
49
- fontSize: 16,
50
- fontFamily: font,
51
- weight: 400,
52
- fill: mutedColor
53
- });
54
- y += 48;
55
-
56
- // Horizontal rule
57
- elements.push({
58
- id: "divider",
59
- type: "path",
60
- d: `M ${padX} ${y} L ${width - padX} ${y}`,
61
- stroke: "#e5e7eb",
62
- strokeWidth: 1,
63
- fill: "none"
64
- });
65
- y += 32;
66
-
67
- // Paragraph 1
68
- elements.push({
69
- id: "para1",
70
- type: "text",
71
- x: padX,
72
- y: y,
73
- text: "The Render API exposes a minimal surface for compiling visual documents into\noutput frames. It accepts a validated kernel document and a target time, then\nresolves all timeline interpolations and returns a flat list of positioned primitives\nready for rasterization or SVG serialization.",
74
- align: "left",
75
- valign: "top",
76
- fontSize: 15,
77
- fontFamily: font,
78
- weight: 400,
79
- lineHeight: 1.7,
80
- fill: textColor,
81
- maxWidth: width - padX * 2
82
- });
83
- y += 110;
84
-
85
- // Paragraph 2
86
- elements.push({
87
- id: "para2",
88
- type: "text",
89
- x: padX,
90
- y: y,
91
- text: "Before calling the render function, ensure your document passes schema\nvalidation. Invalid documents will throw a structured error with path information\npointing to the offending node. This keeps the pipeline predictable and safe.",
92
- align: "left",
93
- valign: "top",
94
- fontSize: 15,
95
- fontFamily: font,
96
- weight: 400,
97
- lineHeight: 1.7,
98
- fill: textColor,
99
- maxWidth: width - padX * 2
100
- });
101
- y += 100;
102
-
103
- // Code block background
104
- const codeBlockH = 172;
105
- elements.push({
106
- id: "code-bg",
107
- type: "path",
108
- d: `M ${padX} ${y} L ${width - padX} ${y} L ${width - padX} ${y + codeBlockH} L ${padX} ${y + codeBlockH} Z`,
109
- fill: codeBg,
110
- stroke: codeBorder,
111
- strokeWidth: 1
112
- });
113
-
114
- // Code block text (6 lines)
115
- elements.push({
116
- id: "code-text",
117
- type: "text",
118
- x: padX + 20,
119
- y: y + 18,
120
- text: `import { validateVisualDocument, resolveVisualFrame } from "sketchmark";\n\nconst doc = JSON.parse(fs.readFileSync("scene.visual.json", "utf8"));\nvalidateVisualDocument(doc);\n\nconst frame = resolveVisualFrame(doc, { time: 1.5 });\nconsole.log(frame.elements.length, "primitives resolved");`,
121
- align: "left",
122
- valign: "top",
123
- fontSize: 13,
124
- fontFamily: monoFont,
125
- weight: 400,
126
- lineHeight: 1.8,
127
- fill: codeText,
128
- maxWidth: width - padX * 2 - 40
129
- });
130
- y += codeBlockH + 36;
131
-
132
- // Section heading for bullet list
133
- elements.push({
134
- id: "list-heading",
135
- type: "text",
136
- x: padX,
137
- y: y,
138
- text: "Key Concepts",
139
- align: "left",
140
- valign: "top",
141
- fontSize: 20,
142
- fontFamily: font,
143
- weight: 600,
144
- fill: textColor
145
- });
146
- y += 36;
147
-
148
- // Bullet list items
149
- const bullets = [
150
- "Documents must declare version: 1 and a canvas with width and height.",
151
- "Elements are flat arrays of path, text, image, point, or group primitives.",
152
- "Timelines are element-local — each element owns its own tracks and keyframes.",
153
- "Interpolation resolves per-track using cubic bezier, graph, or hold curves.",
154
- "The output frame contains fully resolved properties with no remaining references."
155
- ];
156
-
157
- bullets.forEach((text, i) => {
158
- const bulletY = y + i * 30;
159
- elements.push({
160
- id: `bullet-dot-${i}`,
161
- type: "path",
162
- d: `M ${padX + 4} ${bulletY + 7} A 3 3 0 1 1 ${padX + 4} ${bulletY + 7.01} Z`,
163
- fill: bulletColor,
164
- stroke: "none"
165
- });
166
- elements.push({
167
- id: `bullet-text-${i}`,
168
- type: "text",
169
- x: padX + 18,
170
- y: bulletY,
171
- text: text,
172
- align: "left",
173
- valign: "top",
174
- fontSize: 14,
175
- fontFamily: font,
176
- weight: 400,
177
- fill: textColor,
178
- maxWidth: width - padX * 2 - 18
179
- });
180
- });
181
- y += bullets.length * 30 + 40;
182
-
183
- // Centered button
184
- const btnW = 200;
185
- const btnH = 44;
186
- const btnX = (width - btnW) / 2;
187
- const btnR = 8;
188
- elements.push({
189
- id: "btn-bg",
190
- type: "path",
191
- d: `M ${btnX + btnR} ${y} L ${btnX + btnW - btnR} ${y} Q ${btnX + btnW} ${y} ${btnX + btnW} ${y + btnR} L ${btnX + btnW} ${y + btnH - btnR} Q ${btnX + btnW} ${y + btnH} ${btnX + btnW - btnR} ${y + btnH} L ${btnX + btnR} ${y + btnH} Q ${btnX} ${y + btnH} ${btnX} ${y + btnH - btnR} L ${btnX} ${y + btnR} Q ${btnX} ${y} ${btnX + btnR} ${y} Z`,
192
- fill: btnBg,
193
- stroke: "none"
194
- });
195
- elements.push({
196
- id: "btn-label",
197
- type: "text",
198
- x: width / 2,
199
- y: y + btnH / 2,
200
- text: "View Full Reference",
201
- align: "center",
202
- valign: "middle",
203
- fontSize: 15,
204
- fontFamily: font,
205
- weight: 600,
206
- fill: btnText
207
- });
208
- y += btnH + 36;
209
-
210
- // Footer note
211
- elements.push({
212
- id: "footer",
213
- type: "text",
214
- x: padX,
215
- y: y,
216
- text: "Last updated May 2026 · Sketchmark v1.0 · MIT License",
217
- align: "left",
218
- valign: "top",
219
- fontSize: 12,
220
- fontFamily: font,
221
- weight: 400,
222
- fill: mutedColor
223
- });
224
-
225
- const doc = {
226
- version: 1,
227
- canvas: { width, height, background: bg },
228
- elements
229
- };
230
-
231
- const outPath = path.join(__dirname, "dev-docs.visual.json");
232
- fs.writeFileSync(outPath, JSON.stringify(doc, null, 2));
233
- console.log("Written:", outPath);