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.
- package/package.json +1 -7
- package/ANIMATABLE_MATRIX.md +0 -177
- package/KERNEL_SPEC.md +0 -412
- package/PACKS.md +0 -81
- package/PRESETS.md +0 -182
- package/dist/src/builders/index.d.ts +0 -64
- package/dist/src/builders/index.js +0 -212
- package/dist/src/compounds.d.ts +0 -13
- package/dist/src/compounds.js +0 -118
- package/dist/src/deck.d.ts +0 -4
- package/dist/src/deck.js +0 -91
- package/dist/src/export/index.d.ts +0 -8
- package/dist/src/export/index.js +0 -15
- package/dist/src/kernel.d.ts +0 -8
- package/dist/src/kernel.js +0 -68
- package/dist/src/motion.d.ts +0 -4
- package/dist/src/motion.js +0 -262
- package/dist/src/patch.d.ts +0 -5
- package/dist/src/patch.js +0 -72
- package/dist/src/player/index.d.ts +0 -68
- package/dist/src/player/index.js +0 -600
- package/dist/src/project.d.ts +0 -11
- package/dist/src/project.js +0 -107
- package/dist/src/render/raw-three.d.ts +0 -7
- package/dist/src/render/raw-three.js +0 -17
- package/dist/src/render/three-html.d.ts +0 -2
- package/dist/src/render/three-html.js +0 -257
- package/dist/src/render/three-preview-svg.d.ts +0 -3
- package/dist/src/render/three-preview-svg.js +0 -102
- package/dist/src/scenes.d.ts +0 -4
- package/dist/src/scenes.js +0 -26
- package/dist/src/sequences.d.ts +0 -43
- package/dist/src/sequences.js +0 -109
- package/dist/src/shapes/builtins.d.ts +0 -2
- package/dist/src/shapes/builtins.js +0 -393
- package/dist/src/shapes/common.d.ts +0 -9
- package/dist/src/shapes/common.js +0 -76
- package/dist/src/shapes/geometry.d.ts +0 -22
- package/dist/src/shapes/geometry.js +0 -166
- package/dist/src/shapes/index.d.ts +0 -2
- package/dist/src/shapes/index.js +0 -18
- package/dist/src/shapes/registry.d.ts +0 -8
- package/dist/src/shapes/registry.js +0 -31
- package/dist/src/shapes/types.d.ts +0 -32
- package/dist/src/shapes/types.js +0 -2
- package/examples/1730642890464.jpg +0 -0
- package/examples/app-screen.svg +0 -1
- package/examples/app-screen.visual.json +0 -503
- package/examples/dashboard-table.svg +0 -1
- package/examples/dashboard-table.visual.json +0 -708
- package/examples/dev-docs.svg +0 -1
- package/examples/dev-docs.visual.json +0 -248
- package/examples/explainer.mp4 +0 -0
- package/examples/explainer.visual.json +0 -1713
- package/examples/group-origin-effects-lab-check.svg +0 -1
- package/examples/group-origin-effects-lab.visual.json +0 -1880
- package/examples/image-clip-radius.visual.json +0 -271
- package/examples/make-app-screen.cjs +0 -368
- package/examples/make-dashboard-table.cjs +0 -277
- package/examples/make-dev-docs.cjs +0 -233
- package/examples/make-explainer.cjs +0 -438
- package/examples/make-group-origin-effects-lab.cjs +0 -370
- package/examples/make-image-clip-radius.cjs +0 -169
- package/examples/make-modal-dialog.cjs +0 -355
- package/examples/make-origin-effects-lab.cjs +0 -311
- package/examples/make-preset-character-motion.cjs +0 -32
- package/examples/make-presets-demo.cjs +0 -30
- package/examples/make-pricing.cjs +0 -286
- package/examples/make-product-demo.cjs +0 -468
- package/examples/make-product-hero.cjs +0 -223
- package/examples/make-release-notes.cjs +0 -333
- package/examples/make-settings-panel.cjs +0 -435
- package/examples/make-split-preview.cjs +0 -248
- package/examples/make-storyboard.cjs +0 -215
- package/examples/make-transcript.cjs +0 -234
- package/examples/make-typography-test.cjs +0 -397
- package/examples/make-ui-demo-explainer.cjs +0 -1094
- package/examples/make-ui-flow.cjs +0 -762
- package/examples/make-walkthrough.cjs +0 -815
- package/examples/modal-dialog.svg +0 -1
- package/examples/modal-dialog.visual.json +0 -239
- package/examples/origin-effects-lab-check.svg +0 -1
- package/examples/origin-effects-lab.visual.json +0 -1412
- package/examples/preset-character-motion.visual.json +0 -949
- package/examples/presets-demo.visual.json +0 -787
- package/examples/pricing.svg +0 -1
- package/examples/pricing.visual.json +0 -652
- package/examples/product-demo.mp4 +0 -0
- package/examples/product-demo.visual.json +0 -866
- package/examples/product-hero.svg +0 -1
- package/examples/product-hero.visual.json +0 -242
- package/examples/release-notes.svg +0 -1
- package/examples/release-notes.visual.json +0 -467
- package/examples/settings-panel.svg +0 -1
- package/examples/settings-panel.visual.json +0 -501
- package/examples/split-preview.svg +0 -1
- package/examples/split-preview.visual.json +0 -124
- package/examples/storyboard.svg +0 -1
- package/examples/storyboard.visual.json +0 -312
- package/examples/transcript.svg +0 -1
- package/examples/transcript.visual.json +0 -407
- package/examples/typography-indent-check.svg +0 -1
- package/examples/typography-lineheight-0.svg +0 -1
- package/examples/typography-lineheight-2.svg +0 -1
- package/examples/typography-test-check.svg +0 -1
- package/examples/typography-test.svg +0 -1
- package/examples/typography-test.visual.json +0 -757
- package/examples/ui-demo-explainer-billing.svg +0 -1
- package/examples/ui-demo-explainer-check.svg +0 -1
- package/examples/ui-demo-explainer-save.svg +0 -1
- package/examples/ui-demo-explainer-toggle.svg +0 -1
- package/examples/ui-demo-explainer.mp4 +0 -0
- package/examples/ui-demo-explainer.visual.json +0 -2597
- package/examples/ui-flow.mp4 +0 -0
- package/examples/ui-flow.visual.json +0 -1211
- package/examples/walkthrough.mp4 +0 -0
- package/examples/walkthrough.visual.json +0 -1372
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
|
|
4
|
-
const width = 1000;
|
|
5
|
-
const height = 920;
|
|
6
|
-
const duration = 8;
|
|
7
|
-
const fps = 30;
|
|
8
|
-
const bg = "#ffffff";
|
|
9
|
-
const font = "Inter, system-ui, sans-serif";
|
|
10
|
-
const monoFont = "JetBrains Mono, Fira Code, monospace";
|
|
11
|
-
const altFont = "Roboto, Arial, sans-serif";
|
|
12
|
-
|
|
13
|
-
const colors = {
|
|
14
|
-
headline: "#0f172a",
|
|
15
|
-
subtitle: "#475569",
|
|
16
|
-
body: "#334155",
|
|
17
|
-
muted: "#64748b",
|
|
18
|
-
number: "#2563eb",
|
|
19
|
-
codeBg: "#1e293b",
|
|
20
|
-
codeText: "#e2e8f0",
|
|
21
|
-
pillBg: "#f1f5f9",
|
|
22
|
-
pillBorder: "#cbd5e1",
|
|
23
|
-
pillText: "#475569",
|
|
24
|
-
note: "#94a3b8",
|
|
25
|
-
divider: "#e2e8f0"
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const curves = {
|
|
29
|
-
ease: { type: "cubicBezier", x1: 0.25, y1: 0.1, x2: 0.25, y2: 1 }
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const padX = 72;
|
|
33
|
-
const contentW = width - padX * 2;
|
|
34
|
-
let y = 56;
|
|
35
|
-
|
|
36
|
-
const elements = [];
|
|
37
|
-
|
|
38
|
-
function kf(time, value, out) {
|
|
39
|
-
return out ? { time, value, out } : { time, value };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function animated(tracks) {
|
|
43
|
-
return { timeline: { tracks } };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// === 1. Centered headline ===
|
|
47
|
-
elements.push({
|
|
48
|
-
id: "headline",
|
|
49
|
-
type: "text",
|
|
50
|
-
x: width / 2,
|
|
51
|
-
y: y,
|
|
52
|
-
text: "Typography Stress Test",
|
|
53
|
-
align: "center",
|
|
54
|
-
valign: "top",
|
|
55
|
-
fontSize: 40,
|
|
56
|
-
fontFamily: font,
|
|
57
|
-
weight: 700,
|
|
58
|
-
fill: colors.headline,
|
|
59
|
-
...animated({
|
|
60
|
-
fontSize: {
|
|
61
|
-
keyframes: [
|
|
62
|
-
kf(0, 40, curves.ease),
|
|
63
|
-
kf(1.6, 46, curves.ease),
|
|
64
|
-
kf(3.3, 36, curves.ease),
|
|
65
|
-
kf(4.8, 44, curves.ease),
|
|
66
|
-
kf(6.5, 40)
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
letterSpacing: {
|
|
70
|
-
keyframes: [
|
|
71
|
-
kf(0, 0, curves.ease),
|
|
72
|
-
kf(1.6, 1.5, curves.ease),
|
|
73
|
-
kf(3.3, 4, curves.ease),
|
|
74
|
-
kf(4.8, 0.8, curves.ease),
|
|
75
|
-
kf(6.5, 0)
|
|
76
|
-
]
|
|
77
|
-
},
|
|
78
|
-
weight: {
|
|
79
|
-
keyframes: [
|
|
80
|
-
kf(0, 700),
|
|
81
|
-
kf(2.2, 300),
|
|
82
|
-
kf(4.4, 700),
|
|
83
|
-
kf(6.5, 700)
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
});
|
|
88
|
-
y += 56;
|
|
89
|
-
|
|
90
|
-
// === 2. Centered subtitle ===
|
|
91
|
-
elements.push({
|
|
92
|
-
id: "subtitle",
|
|
93
|
-
type: "text",
|
|
94
|
-
x: width / 2,
|
|
95
|
-
y: y,
|
|
96
|
-
text: "Demonstrating multiple alignment modes, text styles, and layout patterns\nin a single cohesive document without visual overlap.",
|
|
97
|
-
align: "center",
|
|
98
|
-
valign: "top",
|
|
99
|
-
fontSize: 16,
|
|
100
|
-
fontFamily: font,
|
|
101
|
-
weight: 400,
|
|
102
|
-
lineHeight: 1.55,
|
|
103
|
-
fill: colors.subtitle,
|
|
104
|
-
maxWidth: contentW,
|
|
105
|
-
...animated({
|
|
106
|
-
lineHeight: {
|
|
107
|
-
keyframes: [
|
|
108
|
-
kf(0, 1.55, curves.ease),
|
|
109
|
-
kf(2, 1.9, curves.ease),
|
|
110
|
-
kf(4.2, 1.3, curves.ease),
|
|
111
|
-
kf(6.4, 1.55)
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
});
|
|
116
|
-
y += 64;
|
|
117
|
-
|
|
118
|
-
// Divider
|
|
119
|
-
elements.push({
|
|
120
|
-
id: "divider-1",
|
|
121
|
-
type: "path",
|
|
122
|
-
d: `M ${padX} ${y} L ${width - padX} ${y}`,
|
|
123
|
-
stroke: colors.divider,
|
|
124
|
-
strokeWidth: 1,
|
|
125
|
-
fill: "none"
|
|
126
|
-
});
|
|
127
|
-
y += 40;
|
|
128
|
-
|
|
129
|
-
// === 3. Left-aligned paragraph block ===
|
|
130
|
-
elements.push({
|
|
131
|
-
id: "para-heading",
|
|
132
|
-
type: "text",
|
|
133
|
-
x: padX,
|
|
134
|
-
y: y,
|
|
135
|
-
text: "Overview",
|
|
136
|
-
align: "left",
|
|
137
|
-
valign: "top",
|
|
138
|
-
fontSize: 20,
|
|
139
|
-
fontFamily: font,
|
|
140
|
-
weight: 700,
|
|
141
|
-
fill: colors.headline
|
|
142
|
-
});
|
|
143
|
-
y += 32;
|
|
144
|
-
|
|
145
|
-
elements.push({
|
|
146
|
-
id: "para-body",
|
|
147
|
-
type: "text",
|
|
148
|
-
x: padX,
|
|
149
|
-
y: y,
|
|
150
|
-
text: "This document tests the render kernel's ability to handle diverse typographic\nscenarios. Each section exercises a different combination of alignment, weight,\nsize, and line height. The goal is to verify that spacing remains predictable\nand that no elements collide regardless of content length or style variation.",
|
|
151
|
-
align: "left",
|
|
152
|
-
valign: "top",
|
|
153
|
-
fontSize: 14,
|
|
154
|
-
fontFamily: font,
|
|
155
|
-
weight: 400,
|
|
156
|
-
lineHeight: 1.7,
|
|
157
|
-
fill: colors.body,
|
|
158
|
-
maxWidth: contentW,
|
|
159
|
-
...animated({
|
|
160
|
-
letterSpacing: {
|
|
161
|
-
keyframes: [
|
|
162
|
-
kf(0, 0, curves.ease),
|
|
163
|
-
kf(2.6, 0.6, curves.ease),
|
|
164
|
-
kf(5.1, 0.15, curves.ease),
|
|
165
|
-
kf(7, 0)
|
|
166
|
-
]
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
});
|
|
170
|
-
y += 110;
|
|
171
|
-
|
|
172
|
-
// === 4. Left-aligned numbered list ===
|
|
173
|
-
elements.push({
|
|
174
|
-
id: "list-heading",
|
|
175
|
-
type: "text",
|
|
176
|
-
x: padX,
|
|
177
|
-
y: y,
|
|
178
|
-
text: "Validation Checklist",
|
|
179
|
-
align: "left",
|
|
180
|
-
valign: "top",
|
|
181
|
-
fontSize: 20,
|
|
182
|
-
fontFamily: font,
|
|
183
|
-
weight: 700,
|
|
184
|
-
fill: colors.headline
|
|
185
|
-
});
|
|
186
|
-
y += 32;
|
|
187
|
-
|
|
188
|
-
const listItems = [
|
|
189
|
-
"Confirm that centered text remains horizontally balanced at all font sizes.",
|
|
190
|
-
"Verify left-aligned blocks maintain consistent left edge across line breaks.",
|
|
191
|
-
"Check that right-aligned notes anchor correctly without drifting.",
|
|
192
|
-
"Ensure code blocks preserve whitespace and monospace character width.",
|
|
193
|
-
"Validate that pill components center their labels within fixed bounds."
|
|
194
|
-
];
|
|
195
|
-
|
|
196
|
-
listItems.forEach((text, i) => {
|
|
197
|
-
const itemY = y + i * 28;
|
|
198
|
-
|
|
199
|
-
// Number
|
|
200
|
-
elements.push({
|
|
201
|
-
id: `list-num-${i}`,
|
|
202
|
-
type: "text",
|
|
203
|
-
x: padX,
|
|
204
|
-
y: itemY,
|
|
205
|
-
text: `${i + 1}.`,
|
|
206
|
-
align: "left",
|
|
207
|
-
valign: "top",
|
|
208
|
-
fontSize: 14,
|
|
209
|
-
fontFamily: font,
|
|
210
|
-
weight: 600,
|
|
211
|
-
fill: colors.number
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Item text
|
|
215
|
-
elements.push({
|
|
216
|
-
id: `list-item-${i}`,
|
|
217
|
-
type: "text",
|
|
218
|
-
x: padX + 24,
|
|
219
|
-
y: itemY,
|
|
220
|
-
text: text,
|
|
221
|
-
align: "left",
|
|
222
|
-
valign: "top",
|
|
223
|
-
fontSize: 14,
|
|
224
|
-
fontFamily: font,
|
|
225
|
-
weight: 400,
|
|
226
|
-
fill: colors.body,
|
|
227
|
-
maxWidth: contentW - 24
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
y += listItems.length * 28 + 32;
|
|
231
|
-
|
|
232
|
-
// === 5. Multiline code block ===
|
|
233
|
-
const codeLines = `function validateLayout(elements) {
|
|
234
|
-
const bounds = elements.map(el => getBounds(el));
|
|
235
|
-
for (let i = 0; i < bounds.length; i++) {
|
|
236
|
-
for (let j = i + 1; j < bounds.length; j++) {
|
|
237
|
-
if (intersects(bounds[i], bounds[j])) {
|
|
238
|
-
return { valid: false, collision: [i, j] };
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return { valid: true };
|
|
243
|
-
}`;
|
|
244
|
-
|
|
245
|
-
const codeBlockH = 200;
|
|
246
|
-
const codeBlockR = 8;
|
|
247
|
-
const codePad = 20;
|
|
248
|
-
|
|
249
|
-
elements.push({
|
|
250
|
-
id: "code-bg",
|
|
251
|
-
type: "path",
|
|
252
|
-
d: roundedRect(padX, y, contentW, codeBlockH, codeBlockR),
|
|
253
|
-
fill: colors.codeBg,
|
|
254
|
-
stroke: "none"
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
elements.push({
|
|
258
|
-
id: "code-text",
|
|
259
|
-
type: "text",
|
|
260
|
-
x: padX + codePad,
|
|
261
|
-
y: y + codePad,
|
|
262
|
-
text: codeLines,
|
|
263
|
-
align: "left",
|
|
264
|
-
valign: "top",
|
|
265
|
-
fontSize: 12,
|
|
266
|
-
fontFamily: monoFont,
|
|
267
|
-
weight: 400,
|
|
268
|
-
lineHeight: 1.55,
|
|
269
|
-
fill: colors.codeText,
|
|
270
|
-
maxWidth: contentW - codePad * 2,
|
|
271
|
-
...animated({
|
|
272
|
-
fontFamily: {
|
|
273
|
-
keyframes: [
|
|
274
|
-
kf(0, monoFont),
|
|
275
|
-
kf(2.7, altFont),
|
|
276
|
-
kf(5.2, monoFont)
|
|
277
|
-
]
|
|
278
|
-
}
|
|
279
|
-
})
|
|
280
|
-
});
|
|
281
|
-
y += codeBlockH + 28;
|
|
282
|
-
|
|
283
|
-
// === 6. Right-aligned note ===
|
|
284
|
-
elements.push({
|
|
285
|
-
id: "note-text",
|
|
286
|
-
type: "text",
|
|
287
|
-
x: width - padX,
|
|
288
|
-
y: y,
|
|
289
|
-
text: "Note: All measurements are in logical pixels.\nActual rendering may vary by display density.",
|
|
290
|
-
align: "right",
|
|
291
|
-
valign: "top",
|
|
292
|
-
fontSize: 12,
|
|
293
|
-
fontFamily: font,
|
|
294
|
-
weight: 400,
|
|
295
|
-
lineHeight: 1.5,
|
|
296
|
-
fill: colors.note,
|
|
297
|
-
maxWidth: 320,
|
|
298
|
-
...animated({
|
|
299
|
-
fontSize: {
|
|
300
|
-
keyframes: [
|
|
301
|
-
kf(0, 12, curves.ease),
|
|
302
|
-
kf(2.5, 14, curves.ease),
|
|
303
|
-
kf(5.3, 12)
|
|
304
|
-
]
|
|
305
|
-
},
|
|
306
|
-
letterSpacing: {
|
|
307
|
-
keyframes: [
|
|
308
|
-
kf(0, 0, curves.ease),
|
|
309
|
-
kf(2.5, 1.2, curves.ease),
|
|
310
|
-
kf(5.3, 0.2, curves.ease),
|
|
311
|
-
kf(7.1, 0)
|
|
312
|
-
]
|
|
313
|
-
}
|
|
314
|
-
})
|
|
315
|
-
});
|
|
316
|
-
y += 52;
|
|
317
|
-
|
|
318
|
-
// === 7. Three small centered pills ===
|
|
319
|
-
const pills = ["Centered", "Balanced", "Verified"];
|
|
320
|
-
const pillH = 28;
|
|
321
|
-
const pillR = 14;
|
|
322
|
-
const pillPadX = 16;
|
|
323
|
-
const pillGap = 12;
|
|
324
|
-
|
|
325
|
-
let totalPillW = 0;
|
|
326
|
-
const pillWidths = pills.map(label => {
|
|
327
|
-
const w = label.length * 8 + pillPadX * 2;
|
|
328
|
-
totalPillW += w;
|
|
329
|
-
return w;
|
|
330
|
-
});
|
|
331
|
-
totalPillW += pillGap * (pills.length - 1);
|
|
332
|
-
|
|
333
|
-
let pillX = (width - totalPillW) / 2;
|
|
334
|
-
|
|
335
|
-
pills.forEach((label, i) => {
|
|
336
|
-
const pw = pillWidths[i];
|
|
337
|
-
|
|
338
|
-
elements.push({
|
|
339
|
-
id: `pill-bg-${i}`,
|
|
340
|
-
type: "path",
|
|
341
|
-
d: roundedRect(pillX, y, pw, pillH, pillR),
|
|
342
|
-
fill: colors.pillBg,
|
|
343
|
-
stroke: colors.pillBorder,
|
|
344
|
-
strokeWidth: 1
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
elements.push({
|
|
348
|
-
id: `pill-text-${i}`,
|
|
349
|
-
type: "text",
|
|
350
|
-
x: pillX + pw / 2,
|
|
351
|
-
y: y + pillH / 2,
|
|
352
|
-
text: label,
|
|
353
|
-
align: "center",
|
|
354
|
-
valign: "middle",
|
|
355
|
-
fontSize: 12,
|
|
356
|
-
fontFamily: font,
|
|
357
|
-
weight: 500,
|
|
358
|
-
fill: colors.pillText,
|
|
359
|
-
...animated({
|
|
360
|
-
weight: {
|
|
361
|
-
keyframes: [
|
|
362
|
-
kf(0, 500),
|
|
363
|
-
kf(1.8 + i * 0.18, 700),
|
|
364
|
-
kf(4.1 + i * 0.18, 300),
|
|
365
|
-
kf(6.2 + i * 0.18, 500)
|
|
366
|
-
]
|
|
367
|
-
}
|
|
368
|
-
})
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
pillX += pw + pillGap;
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
function roundedRect(x, y, w, h, r) {
|
|
375
|
-
return [
|
|
376
|
-
`M ${x + r} ${y}`,
|
|
377
|
-
`L ${x + w - r} ${y}`,
|
|
378
|
-
`Q ${x + w} ${y} ${x + w} ${y + r}`,
|
|
379
|
-
`L ${x + w} ${y + h - r}`,
|
|
380
|
-
`Q ${x + w} ${y + h} ${x + w - r} ${y + h}`,
|
|
381
|
-
`L ${x + r} ${y + h}`,
|
|
382
|
-
`Q ${x} ${y + h} ${x} ${y + h - r}`,
|
|
383
|
-
`L ${x} ${y + r}`,
|
|
384
|
-
`Q ${x} ${y} ${x + r} ${y}`,
|
|
385
|
-
"Z"
|
|
386
|
-
].join(" ");
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const doc = {
|
|
390
|
-
version: 1,
|
|
391
|
-
canvas: { width, height, background: bg, duration, fps },
|
|
392
|
-
elements
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
const outPath = path.join(__dirname, "typography-test.visual.json");
|
|
396
|
-
fs.writeFileSync(outPath, JSON.stringify(doc, null, 2));
|
|
397
|
-
console.log("Written:", outPath);
|