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,815 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- const width = 1280;
5
- const height = 720;
6
- const duration = 24;
7
- const fps = 30;
8
- const bg = "#f8fafc";
9
- const font = "Inter, system-ui, sans-serif";
10
-
11
- const colors = {
12
- hero: "#0f172a",
13
- heroSub: "#64748b",
14
- panelBg: "#ffffff",
15
- panelBorder: "#e2e8f0",
16
- panelTitle: "#1e293b",
17
- panelBody: "#475569",
18
- panelMuted: "#94a3b8",
19
- inputBg: "#f8fafc",
20
- inputBorder: "#cbd5e1",
21
- inputText: "#64748b",
22
- btnPrimaryBg: "#2563eb",
23
- btnPrimaryText: "#ffffff",
24
- btnSecondaryBg: "#ffffff",
25
- btnSecondaryText: "#475569",
26
- btnSecondaryBorder: "#e2e8f0",
27
- accent: "#2563eb",
28
- success: "#10b981",
29
- successBg: "#d1fae5",
30
- cursor: "#0f172a",
31
- cursorRing: "#3b82f6"
32
- };
33
-
34
- const curves = {
35
- ease: { type: "cubicBezier", x1: 0.4, y1: 0, x2: 0.2, y2: 1 },
36
- easeOut: { type: "cubicBezier", x1: 0, y1: 0, x2: 0.2, y2: 1 },
37
- snap: { type: "cubicBezier", x1: 0.2, y1: 1, x2: 0.2, y2: 1 }
38
- };
39
-
40
- const elements = [];
41
-
42
- // Cursor elements stored separately, added at the end so they render on top
43
- // Button positions (calculated from layout):
44
- // Create button: dashX + dashW - 140 + 56 = 996, dashY + 24 + 20 = 164
45
- // Input field: ~640, ~335 (center of input)
46
- // Save button: modalX + modalW - 150 + 61 = 791, modalY + modalH - 68 + 20 = 482
47
- const createBtnX = 996;
48
- const createBtnY = 164;
49
- const inputFieldX = 640;
50
- const inputFieldY = 335;
51
- const saveBtnX = 791;
52
- const saveBtnY = 482;
53
-
54
- const cursorElement = {
55
- id: "cursor",
56
- type: "group",
57
- x: -50,
58
- y: -50,
59
- children: [
60
- {
61
- id: "cursor-arrow",
62
- type: "path",
63
- d: "M 0 0 L 0 20 L 5 16 L 8 24 L 12 22 L 9 14 L 15 14 Z",
64
- fill: colors.cursor,
65
- stroke: "#ffffff",
66
- strokeWidth: 1.5
67
- }
68
- ],
69
- timeline: {
70
- tracks: {
71
- x: {
72
- keyframes: [
73
- { time: 0, value: -50 },
74
- // Move to Create button
75
- { time: 5.5, value: -50, out: curves.ease },
76
- { time: 6.5, value: createBtnX },
77
- { time: 8, value: createBtnX },
78
- // Move to input field
79
- { time: 10, value: createBtnX, out: curves.ease },
80
- { time: 11, value: inputFieldX },
81
- // Move to Save button
82
- { time: 16, value: inputFieldX, out: curves.ease },
83
- { time: 17, value: saveBtnX },
84
- // Exit
85
- { time: 20, value: saveBtnX, out: curves.ease },
86
- { time: 21, value: 1400 }
87
- ]
88
- },
89
- y: {
90
- keyframes: [
91
- { time: 0, value: -50 },
92
- { time: 5.5, value: -50, out: curves.ease },
93
- { time: 6.5, value: createBtnY },
94
- { time: 8, value: createBtnY },
95
- { time: 10, value: createBtnY, out: curves.ease },
96
- { time: 11, value: inputFieldY },
97
- { time: 16, value: inputFieldY, out: curves.ease },
98
- { time: 17, value: saveBtnY },
99
- { time: 20, value: saveBtnY, out: curves.ease },
100
- { time: 21, value: 800 }
101
- ]
102
- }
103
- }
104
- }
105
- };
106
-
107
- const clickRingElement = {
108
- id: "click-ring",
109
- type: "path",
110
- d: "M 0 0 m -16 0 a 16 16 0 1 1 32 0 a 16 16 0 1 1 -32 0",
111
- x: createBtnX,
112
- y: createBtnY,
113
- fill: "none",
114
- stroke: colors.cursorRing,
115
- strokeWidth: 2,
116
- opacity: 0,
117
- origin: [0, 0],
118
- timeline: {
119
- tracks: {
120
- opacity: {
121
- keyframes: [
122
- // Click 1: Create button
123
- { time: 7, value: 0 },
124
- { time: 7.1, value: 0.6 },
125
- { time: 7.5, value: 0 },
126
- // Click 2: Save button
127
- { time: 17.5, value: 0 },
128
- { time: 17.6, value: 0.6 },
129
- { time: 18, value: 0 }
130
- ]
131
- },
132
- scale: {
133
- keyframes: [
134
- { time: 7, value: 0.5, out: curves.easeOut },
135
- { time: 7.5, value: 1.5 },
136
- { time: 17.5, value: 0.5, out: curves.easeOut },
137
- { time: 18, value: 1.5 }
138
- ]
139
- },
140
- x: {
141
- keyframes: [
142
- { time: 7, value: createBtnX },
143
- { time: 17.5, value: saveBtnX }
144
- ]
145
- },
146
- y: {
147
- keyframes: [
148
- { time: 7, value: createBtnY },
149
- { time: 17.5, value: saveBtnY }
150
- ]
151
- }
152
- }
153
- }
154
- };
155
-
156
- // === SCENE 1: Hero (0-5s) ===
157
- elements.push({
158
- id: "hero-title",
159
- type: "text",
160
- x: width / 2,
161
- y: 280,
162
- text: "Build beautiful interfaces",
163
- align: "center",
164
- valign: "middle",
165
- fontSize: 56,
166
- fontFamily: font,
167
- weight: 800,
168
- fill: colors.hero,
169
- opacity: 0,
170
- timeline: {
171
- tracks: {
172
- opacity: {
173
- keyframes: [
174
- { time: 0.2, value: 0, out: curves.ease },
175
- { time: 0.8, value: 1 },
176
- { time: 4, value: 1, out: curves.ease },
177
- { time: 4.6, value: 0 }
178
- ]
179
- },
180
- y: {
181
- keyframes: [
182
- { time: 0.2, value: 300, out: curves.ease },
183
- { time: 0.8, value: 280 }
184
- ]
185
- },
186
- scale: {
187
- keyframes: [
188
- { time: 0.2, value: 0.95, out: curves.ease },
189
- { time: 0.8, value: 1 }
190
- ]
191
- }
192
- }
193
- }
194
- });
195
-
196
- elements.push({
197
- id: "hero-sub",
198
- type: "text",
199
- x: width / 2,
200
- y: 360,
201
- text: "Design, prototype, and ship — all in one place.",
202
- align: "center",
203
- valign: "middle",
204
- fontSize: 22,
205
- fontFamily: font,
206
- weight: 400,
207
- fill: colors.heroSub,
208
- opacity: 0,
209
- timeline: {
210
- tracks: {
211
- opacity: {
212
- keyframes: [
213
- { time: 0.6, value: 0, out: curves.ease },
214
- { time: 1.2, value: 1 },
215
- { time: 4, value: 1, out: curves.ease },
216
- { time: 4.6, value: 0 }
217
- ]
218
- }
219
- }
220
- }
221
- });
222
-
223
- // === SCENE 2: Dashboard panel (5-10s) ===
224
- const dashX = 200;
225
- const dashY = 120;
226
- const dashW = 880;
227
- const dashH = 480;
228
-
229
- elements.push({
230
- id: "dash-panel",
231
- type: "group",
232
- x: dashX,
233
- y: dashY,
234
- opacity: 0,
235
- children: [
236
- {
237
- id: "dash-bg",
238
- type: "path",
239
- d: roundedRect(0, 0, dashW, dashH, 12),
240
- fill: colors.panelBg,
241
- stroke: colors.panelBorder,
242
- strokeWidth: 1
243
- },
244
- // Panel header
245
- {
246
- id: "dash-title",
247
- type: "text",
248
- x: 28,
249
- y: 28,
250
- text: "Your Projects",
251
- align: "left",
252
- valign: "top",
253
- fontSize: 20,
254
- fontFamily: font,
255
- weight: 600,
256
- fill: colors.panelTitle
257
- },
258
- {
259
- id: "dash-subtitle",
260
- type: "text",
261
- x: 28,
262
- y: 56,
263
- text: "3 projects · Last updated 2 hours ago",
264
- align: "left",
265
- valign: "top",
266
- fontSize: 13,
267
- fontFamily: font,
268
- weight: 400,
269
- fill: colors.panelMuted
270
- },
271
- // Divider
272
- {
273
- id: "dash-divider",
274
- type: "path",
275
- d: `M 0 90 L ${dashW} 90`,
276
- stroke: colors.panelBorder,
277
- strokeWidth: 1,
278
- fill: "none"
279
- },
280
- // Project rows
281
- ...projectRow(0, "Marketing Website", "12 screens · Published", 110),
282
- ...projectRow(1, "Mobile App v2", "8 screens · Draft", 170),
283
- ...projectRow(2, "Dashboard Redesign", "24 screens · In review", 230)
284
- ],
285
- timeline: {
286
- tracks: {
287
- opacity: {
288
- keyframes: [
289
- { time: 5, value: 0, out: curves.ease },
290
- { time: 5.6, value: 1 },
291
- { time: 9, value: 1, out: curves.ease },
292
- { time: 9.6, value: 0 }
293
- ]
294
- },
295
- scale: {
296
- keyframes: [
297
- { time: 5, value: 0.96, out: curves.ease },
298
- { time: 5.6, value: 1 }
299
- ]
300
- }
301
- }
302
- }
303
- });
304
-
305
- // Create button (separate for zoom effect on click)
306
- elements.push({
307
- id: "create-btn",
308
- type: "group",
309
- x: dashX + dashW - 140,
310
- y: dashY + 24,
311
- opacity: 0,
312
- children: [
313
- {
314
- id: "create-btn-bg",
315
- type: "path",
316
- d: roundedRect(0, 0, 112, 40, 8),
317
- fill: colors.btnPrimaryBg,
318
- stroke: "none"
319
- },
320
- {
321
- id: "create-btn-text",
322
- type: "text",
323
- x: 56,
324
- y: 20,
325
- text: "Create New",
326
- align: "center",
327
- valign: "middle",
328
- fontSize: 14,
329
- fontFamily: font,
330
- weight: 600,
331
- fill: colors.btnPrimaryText
332
- }
333
- ],
334
- timeline: {
335
- tracks: {
336
- opacity: {
337
- keyframes: [
338
- { time: 5.3, value: 0, out: curves.ease },
339
- { time: 5.8, value: 1 },
340
- { time: 9, value: 1, out: curves.ease },
341
- { time: 9.6, value: 0 }
342
- ]
343
- },
344
- scale: {
345
- keyframes: [
346
- { time: 7, value: 1, out: curves.snap },
347
- { time: 7.15, value: 0.95 },
348
- { time: 7.3, value: 1 }
349
- ]
350
- }
351
- }
352
- },
353
- origin: [56, 20]
354
- });
355
-
356
- // === SCENE 3: Create form modal (10-17s) ===
357
- const modalW = 480;
358
- const modalH = 340;
359
- const modalX = (width - modalW) / 2;
360
- const modalY = (height - modalH) / 2;
361
-
362
- // Modal backdrop
363
- elements.push({
364
- id: "modal-backdrop",
365
- type: "path",
366
- d: `M 0 0 L ${width} 0 L ${width} ${height} L 0 ${height} Z`,
367
- fill: colors.hero,
368
- opacity: 0,
369
- timeline: {
370
- tracks: {
371
- opacity: {
372
- keyframes: [
373
- { time: 10, value: 0, out: curves.ease },
374
- { time: 10.4, value: 0.4 },
375
- { time: 19, value: 0.4, out: curves.ease },
376
- { time: 19.5, value: 0 }
377
- ]
378
- }
379
- }
380
- }
381
- });
382
-
383
- elements.push({
384
- id: "modal",
385
- type: "group",
386
- x: modalX,
387
- y: modalY,
388
- opacity: 0,
389
- children: [
390
- {
391
- id: "modal-bg",
392
- type: "path",
393
- d: roundedRect(0, 0, modalW, modalH, 12),
394
- fill: colors.panelBg,
395
- stroke: "none"
396
- },
397
- {
398
- id: "modal-title",
399
- type: "text",
400
- x: 28,
401
- y: 28,
402
- text: "Create new project",
403
- align: "left",
404
- valign: "top",
405
- fontSize: 18,
406
- fontFamily: font,
407
- weight: 600,
408
- fill: colors.panelTitle
409
- },
410
- {
411
- id: "modal-desc",
412
- type: "text",
413
- x: 28,
414
- y: 56,
415
- text: "Give your project a name and choose a template to get started.",
416
- align: "left",
417
- valign: "top",
418
- fontSize: 13,
419
- fontFamily: font,
420
- weight: 400,
421
- fill: colors.panelBody,
422
- maxWidth: modalW - 56
423
- },
424
- // Project name field
425
- {
426
- id: "field-label",
427
- type: "text",
428
- x: 28,
429
- y: 100,
430
- text: "Project name",
431
- align: "left",
432
- valign: "top",
433
- fontSize: 13,
434
- fontFamily: font,
435
- weight: 500,
436
- fill: colors.panelTitle
437
- },
438
- {
439
- id: "field-input-bg",
440
- type: "path",
441
- d: roundedRect(28, 124, modalW - 56, 42, 6),
442
- fill: colors.inputBg,
443
- stroke: colors.inputBorder,
444
- strokeWidth: 1
445
- },
446
- {
447
- id: "field-placeholder",
448
- type: "text",
449
- x: 40,
450
- y: 145,
451
- text: "Enter project name...",
452
- align: "left",
453
- valign: "middle",
454
- fontSize: 14,
455
- fontFamily: font,
456
- weight: 400,
457
- fill: colors.inputText
458
- },
459
- // Template selector
460
- {
461
- id: "template-label",
462
- type: "text",
463
- x: 28,
464
- y: 186,
465
- text: "Template",
466
- align: "left",
467
- valign: "top",
468
- fontSize: 13,
469
- fontFamily: font,
470
- weight: 500,
471
- fill: colors.panelTitle
472
- },
473
- ...templateOption(0, "Blank", 28, 210, true),
474
- ...templateOption(1, "Dashboard", 138, 210, false),
475
- ...templateOption(2, "Landing", 268, 210, false)
476
- ],
477
- timeline: {
478
- tracks: {
479
- opacity: {
480
- keyframes: [
481
- { time: 10, value: 0, out: curves.ease },
482
- { time: 10.5, value: 1 },
483
- { time: 19, value: 1, out: curves.ease },
484
- { time: 19.5, value: 0 }
485
- ]
486
- },
487
- scale: {
488
- keyframes: [
489
- { time: 10, value: 0.9, out: curves.ease },
490
- { time: 10.5, value: 1 },
491
- { time: 19, value: 1, out: curves.ease },
492
- { time: 19.5, value: 0.95 }
493
- ]
494
- },
495
- y: {
496
- keyframes: [
497
- { time: 10, value: modalY + 30, out: curves.ease },
498
- { time: 10.5, value: modalY }
499
- ]
500
- }
501
- }
502
- },
503
- origin: [modalW / 2, modalH / 2]
504
- });
505
-
506
- // Typing animation - text appears
507
- elements.push({
508
- id: "typed-text",
509
- type: "text",
510
- x: modalX + 40,
511
- y: modalY + 145,
512
- text: "Product Launch 2024",
513
- align: "left",
514
- valign: "middle",
515
- fontSize: 14,
516
- fontFamily: font,
517
- weight: 400,
518
- fill: colors.panelTitle,
519
- opacity: 0,
520
- timeline: {
521
- tracks: {
522
- opacity: {
523
- keyframes: [
524
- { time: 12, value: 0 },
525
- { time: 12.5, value: 1 },
526
- { time: 19, value: 1, out: curves.ease },
527
- { time: 19.5, value: 0 }
528
- ]
529
- }
530
- }
531
- }
532
- });
533
-
534
- // Modal buttons
535
- elements.push({
536
- id: "cancel-btn",
537
- type: "group",
538
- x: modalX + 28,
539
- y: modalY + modalH - 68,
540
- opacity: 0,
541
- children: [
542
- {
543
- id: "cancel-btn-bg",
544
- type: "path",
545
- d: roundedRect(0, 0, 90, 40, 8),
546
- fill: colors.btnSecondaryBg,
547
- stroke: colors.btnSecondaryBorder,
548
- strokeWidth: 1
549
- },
550
- {
551
- id: "cancel-btn-text",
552
- type: "text",
553
- x: 45,
554
- y: 20,
555
- text: "Cancel",
556
- align: "center",
557
- valign: "middle",
558
- fontSize: 14,
559
- fontFamily: font,
560
- weight: 500,
561
- fill: colors.btnSecondaryText
562
- }
563
- ],
564
- timeline: {
565
- tracks: {
566
- opacity: {
567
- keyframes: [
568
- { time: 10.6, value: 0, out: curves.ease },
569
- { time: 11, value: 1 },
570
- { time: 19, value: 1, out: curves.ease },
571
- { time: 19.5, value: 0 }
572
- ]
573
- }
574
- }
575
- }
576
- });
577
-
578
- elements.push({
579
- id: "save-btn",
580
- type: "group",
581
- x: modalX + modalW - 150,
582
- y: modalY + modalH - 68,
583
- opacity: 0,
584
- children: [
585
- {
586
- id: "save-btn-bg",
587
- type: "path",
588
- d: roundedRect(0, 0, 122, 40, 8),
589
- fill: colors.btnPrimaryBg,
590
- stroke: "none"
591
- },
592
- {
593
- id: "save-btn-text",
594
- type: "text",
595
- x: 61,
596
- y: 20,
597
- text: "Create Project",
598
- align: "center",
599
- valign: "middle",
600
- fontSize: 14,
601
- fontFamily: font,
602
- weight: 600,
603
- fill: colors.btnPrimaryText
604
- }
605
- ],
606
- origin: [61, 20],
607
- timeline: {
608
- tracks: {
609
- opacity: {
610
- keyframes: [
611
- { time: 10.6, value: 0, out: curves.ease },
612
- { time: 11, value: 1 },
613
- { time: 19, value: 1, out: curves.ease },
614
- { time: 19.5, value: 0 }
615
- ]
616
- },
617
- scale: {
618
- keyframes: [
619
- { time: 17.5, value: 1, out: curves.snap },
620
- { time: 17.65, value: 0.95 },
621
- { time: 17.8, value: 1 }
622
- ]
623
- }
624
- }
625
- }
626
- });
627
-
628
- // === SCENE 4: Success state (19-24s) ===
629
- elements.push({
630
- id: "success-panel",
631
- type: "group",
632
- x: (width - 400) / 2,
633
- y: 240,
634
- opacity: 0,
635
- children: [
636
- {
637
- id: "success-bg",
638
- type: "path",
639
- d: roundedRect(0, 0, 400, 200, 12),
640
- fill: colors.panelBg,
641
- stroke: colors.panelBorder,
642
- strokeWidth: 1
643
- },
644
- // Checkmark circle
645
- {
646
- id: "success-circle",
647
- type: "path",
648
- d: "M 200 50 m -30 0 a 30 30 0 1 1 60 0 a 30 30 0 1 1 -60 0",
649
- fill: colors.successBg,
650
- stroke: "none"
651
- },
652
- {
653
- id: "success-check",
654
- type: "path",
655
- d: "M 186 50 L 196 60 L 214 42",
656
- fill: "none",
657
- stroke: colors.success,
658
- strokeWidth: 3,
659
- strokeCap: "round",
660
- strokeJoin: "round"
661
- },
662
- {
663
- id: "success-title",
664
- type: "text",
665
- x: 200,
666
- y: 105,
667
- text: "Project created!",
668
- align: "center",
669
- valign: "top",
670
- fontSize: 20,
671
- fontFamily: font,
672
- weight: 600,
673
- fill: colors.panelTitle
674
- },
675
- {
676
- id: "success-desc",
677
- type: "text",
678
- x: 200,
679
- y: 135,
680
- text: "Your new project is ready. Start designing\nyour first screen now.",
681
- align: "center",
682
- valign: "top",
683
- fontSize: 14,
684
- fontFamily: font,
685
- weight: 400,
686
- lineHeight: 1.5,
687
- fill: colors.panelBody,
688
- maxWidth: 340
689
- }
690
- ],
691
- timeline: {
692
- tracks: {
693
- opacity: {
694
- keyframes: [
695
- { time: 19.5, value: 0, out: curves.ease },
696
- { time: 20.2, value: 1 },
697
- { time: 23, value: 1, out: curves.ease },
698
- { time: 23.6, value: 0 }
699
- ]
700
- },
701
- scale: {
702
- keyframes: [
703
- { time: 19.5, value: 0.9, out: curves.ease },
704
- { time: 20.2, value: 1 }
705
- ]
706
- },
707
- y: {
708
- keyframes: [
709
- { time: 19.5, value: 260, out: curves.ease },
710
- { time: 20.2, value: 240 }
711
- ]
712
- }
713
- }
714
- },
715
- origin: [200, 100]
716
- });
717
-
718
- // --- Helpers ---
719
-
720
- function projectRow(i, name, meta, yPos) {
721
- return [
722
- {
723
- id: `proj-${i}-name`,
724
- type: "text",
725
- x: 28,
726
- y: yPos,
727
- text: name,
728
- align: "left",
729
- valign: "top",
730
- fontSize: 15,
731
- fontFamily: font,
732
- weight: 500,
733
- fill: colors.panelTitle
734
- },
735
- {
736
- id: `proj-${i}-meta`,
737
- type: "text",
738
- x: 28,
739
- y: yPos + 22,
740
- text: meta,
741
- align: "left",
742
- valign: "top",
743
- fontSize: 12,
744
- fontFamily: font,
745
- weight: 400,
746
- fill: colors.panelMuted
747
- }
748
- ];
749
- }
750
-
751
- function templateOption(i, label, x, y, selected) {
752
- const w = 100;
753
- const h = 60;
754
- return [
755
- {
756
- id: `tpl-${i}-bg`,
757
- type: "path",
758
- d: roundedRect(x, y, w, h, 6),
759
- fill: selected ? colors.accent : colors.inputBg,
760
- stroke: selected ? colors.accent : colors.inputBorder,
761
- strokeWidth: selected ? 2 : 1,
762
- opacity: selected ? 0.1 : 1
763
- },
764
- {
765
- id: `tpl-${i}-border`,
766
- type: "path",
767
- d: roundedRect(x, y, w, h, 6),
768
- fill: "none",
769
- stroke: selected ? colors.accent : colors.inputBorder,
770
- strokeWidth: selected ? 2 : 1
771
- },
772
- {
773
- id: `tpl-${i}-label`,
774
- type: "text",
775
- x: x + w / 2,
776
- y: y + h / 2,
777
- text: label,
778
- align: "center",
779
- valign: "middle",
780
- fontSize: 13,
781
- fontFamily: font,
782
- weight: selected ? 600 : 400,
783
- fill: selected ? colors.accent : colors.panelBody
784
- }
785
- ];
786
- }
787
-
788
- function roundedRect(x, y, w, h, r) {
789
- return [
790
- `M ${x + r} ${y}`,
791
- `L ${x + w - r} ${y}`,
792
- `Q ${x + w} ${y} ${x + w} ${y + r}`,
793
- `L ${x + w} ${y + h - r}`,
794
- `Q ${x + w} ${y + h} ${x + w - r} ${y + h}`,
795
- `L ${x + r} ${y + h}`,
796
- `Q ${x} ${y + h} ${x} ${y + h - r}`,
797
- `L ${x} ${y + r}`,
798
- `Q ${x} ${y} ${x + r} ${y}`,
799
- "Z"
800
- ].join(" ");
801
- }
802
-
803
- // Add cursor elements last so they render on top of everything
804
- elements.push(clickRingElement);
805
- elements.push(cursorElement);
806
-
807
- const doc = {
808
- version: 1,
809
- canvas: { width, height, background: bg, duration, fps },
810
- elements
811
- };
812
-
813
- const outPath = path.join(__dirname, "walkthrough.visual.json");
814
- fs.writeFileSync(outPath, JSON.stringify(doc, null, 2));
815
- console.log("Written:", outPath);