sketchmark 2.0.0 → 2.1.1

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 (56) hide show
  1. package/README.md +274 -188
  2. package/bin/editor-ui.cjs +2285 -0
  3. package/bin/preview-ui.cjs +74 -0
  4. package/bin/sketchmark.cjs +648 -2008
  5. package/dist/src/animatable.d.ts +21 -0
  6. package/dist/src/animatable.js +439 -0
  7. package/dist/src/builders/index.d.ts +1 -11
  8. package/dist/src/builders/index.js +1 -19
  9. package/dist/src/diagnostics.js +1 -64
  10. package/dist/src/edit.d.ts +27 -0
  11. package/dist/src/edit.js +162 -0
  12. package/dist/src/index.d.ts +4 -13
  13. package/dist/src/index.js +4 -13
  14. package/dist/src/keyframes.d.ts +48 -0
  15. package/dist/src/keyframes.js +182 -0
  16. package/dist/src/motion.d.ts +4 -0
  17. package/dist/src/motion.js +262 -0
  18. package/dist/src/normalize.js +120 -151
  19. package/dist/src/presets/characters.d.ts +15 -0
  20. package/dist/src/presets/characters.js +113 -0
  21. package/dist/src/presets/compose.d.ts +5 -0
  22. package/dist/src/presets/compose.js +80 -0
  23. package/dist/src/presets/effects.d.ts +40 -0
  24. package/dist/src/presets/effects.js +79 -0
  25. package/dist/src/presets/helpers.d.ts +33 -0
  26. package/dist/src/presets/helpers.js +165 -0
  27. package/dist/src/presets/index.d.ts +9 -0
  28. package/dist/src/presets/index.js +48 -0
  29. package/dist/src/presets/motions.d.ts +33 -0
  30. package/dist/src/presets/motions.js +75 -0
  31. package/dist/src/presets/scenes.d.ts +35 -0
  32. package/dist/src/presets/scenes.js +134 -0
  33. package/dist/src/presets/shapes.d.ts +71 -0
  34. package/dist/src/presets/shapes.js +96 -0
  35. package/dist/src/presets/transitions.d.ts +29 -0
  36. package/dist/src/presets/transitions.js +113 -0
  37. package/dist/src/presets/types.d.ts +34 -0
  38. package/dist/src/presets/types.js +2 -0
  39. package/dist/src/render/html.js +1 -4
  40. package/dist/src/render/svg.d.ts +2 -2
  41. package/dist/src/render/svg.js +86 -82
  42. package/dist/src/render/three-html.js +67 -113
  43. package/dist/src/scenes.js +1 -0
  44. package/dist/src/schema.js +218 -280
  45. package/dist/src/shapes/builtins.js +11 -47
  46. package/dist/src/shapes/common.js +12 -11
  47. package/dist/src/shapes/registry.d.ts +0 -1
  48. package/dist/src/shapes/registry.js +0 -4
  49. package/dist/src/shapes/types.d.ts +1 -3
  50. package/dist/src/types.d.ts +57 -288
  51. package/dist/src/utils.d.ts +2 -11
  52. package/dist/src/utils.js +13 -70
  53. package/dist/src/validate.js +321 -275
  54. package/dist/tests/run.js +576 -510
  55. package/package.json +46 -52
  56. package/schema/visual.schema.json +1086 -930
@@ -1,139 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateVisualSchema = generateVisualSchema;
4
- const shapes_1 = require("./shapes");
5
4
  function generateVisualSchema() {
6
- const shapeDefinitions = (0, shapes_1.registeredAuthoringShapeDefinitions)();
7
- const elementProperties = {
8
- id: { type: "string" },
9
- type: { enum: shapeDefinitions.map((definition) => definition.type) },
10
- opacity: { type: "number" },
11
- fill: { $ref: "#/$defs/paint" },
12
- stroke: { $ref: "#/$defs/paint" },
13
- strokeWidth: { type: "number" },
14
- dashArray: { type: "array", items: { type: "number" } },
15
- strokeCap: { enum: ["butt", "round", "square"] },
16
- strokeJoin: { enum: ["miter", "round", "bevel"] },
17
- miterLimit: { type: "number" },
18
- dashOffset: { type: "number" },
19
- drawStart: { type: "number" },
20
- drawEnd: { type: "number" },
21
- effects: { $ref: "#/$defs/effects" },
22
- blendMode: { type: "string" },
23
- rotation: { type: "number" },
24
- scale: { type: "number" },
25
- scaleX: { type: "number" },
26
- scaleY: { type: "number" },
27
- origin: { oneOf: [{ type: "string" }, { $ref: "#/$defs/point2" }] },
28
- clip: { $ref: "#/$defs/clipShape" },
29
- mask: { $ref: "#/$defs/clipShape" },
30
- animate: { type: "object", additionalProperties: { $ref: "#/$defs/animationValue" } },
31
- metadata: { type: "object", additionalProperties: true },
32
- align: { enum: ["left", "center", "right"] },
33
- valign: { enum: ["top", "middle", "bottom"] },
34
- fontSize: { type: "number" },
35
- fontFamily: { type: "string" },
36
- weight: { oneOf: [{ type: "number" }, { type: "string" }] },
37
- fontStyle: { type: "string" },
38
- lineHeight: { type: "number" },
39
- letterSpacing: { type: "number" },
40
- maxWidth: { type: "number" },
41
- wrap: { type: "boolean" },
42
- label: { type: "string" },
43
- labelX: { type: "number" },
44
- labelY: { type: "number" },
45
- progress: { oneOf: [{ type: "number" }, { $ref: "#/$defs/animationValue" }] },
46
- follow: { type: "string" },
47
- rotationX: { type: "number" },
48
- rotationY: { type: "number" },
49
- rotationZ: { type: "number" },
50
- scaleZ: { type: "number" }
51
- };
52
- for (const definition of shapeDefinitions) {
53
- for (const [key, value] of Object.entries(definition.schema?.properties ?? {})) {
54
- elementProperties[key] = mergeSchemaProperty(elementProperties[key], value);
55
- }
56
- }
57
5
  return {
58
6
  $schema: "https://json-schema.org/draft/2020-12/schema",
59
7
  $id: "https://sketchmark.dev/schema/visual.schema.json",
60
- title: "Sketchmark Primitive Visual Document",
8
+ title: "Sketchmark Render Kernel Document",
61
9
  type: "object",
62
10
  required: ["version", "canvas"],
63
- additionalProperties: true,
11
+ additionalProperties: false,
64
12
  properties: {
65
13
  version: { const: 1 },
66
14
  canvas: {
67
15
  type: "object",
68
16
  required: ["width", "height"],
69
- additionalProperties: true,
17
+ additionalProperties: false,
70
18
  properties: {
71
19
  width: { type: "number" },
72
20
  height: { type: "number" },
73
21
  background: { type: "string" },
74
- duration: { type: "number" },
75
- fps: { type: "number" },
76
- space: { enum: ["2d", "3d"] },
77
- renderer: { enum: ["svg", "three"] }
22
+ duration: { type: "number", minimum: 0 },
23
+ fps: { type: "number", exclusiveMinimum: 0 }
78
24
  }
79
25
  },
80
26
  elements: {
81
27
  type: "array",
82
28
  items: { $ref: "#/$defs/element" }
83
- },
84
- imports: {
85
- type: "object",
86
- additionalProperties: { type: "string" }
87
- },
88
- assets: {
89
- type: "object",
90
- additionalProperties: { type: "string" }
91
- },
92
- exports: {
93
- type: "object",
94
- additionalProperties: {
95
- type: "object",
96
- properties: {
97
- format: { enum: ["svg", "html", "png", "jpg", "mp4", "webm", "pdf", "pptx"] },
98
- sequence: { type: "string" },
99
- scene: { type: "string" }
100
- },
101
- additionalProperties: true
102
- }
103
- },
104
- scenes: {
105
- type: "object",
106
- additionalProperties: {
107
- type: "object",
108
- required: ["elements"],
109
- properties: {
110
- canvas: { type: "object" },
111
- elements: {
112
- type: "array",
113
- items: { $ref: "#/$defs/element" }
114
- },
115
- steps: {
116
- type: "array",
117
- items: { $ref: "#/$defs/deckStep" }
118
- }
119
- },
120
- additionalProperties: true
121
- }
122
- },
123
- sequences: {
124
- type: "object",
125
- additionalProperties: {
126
- type: "object",
127
- required: ["id", "clips"],
128
- properties: {
129
- id: { type: "string" },
130
- clips: {
131
- type: "array",
132
- items: { $ref: "#/$defs/clip" }
133
- }
134
- },
135
- additionalProperties: true
136
- }
137
29
  }
138
30
  },
139
31
  $defs: {
@@ -141,27 +33,34 @@ function generateVisualSchema() {
141
33
  type: "array",
142
34
  minItems: 2,
143
35
  maxItems: 2,
144
- items: { type: "number" }
145
- },
146
- point3: {
147
- type: "array",
148
- minItems: 3,
149
- maxItems: 3,
150
- items: { type: "number" }
36
+ prefixItems: [{ type: "number" }, { type: "number" }]
151
37
  },
152
- endpoint: {
153
- oneOf: [{ $ref: "#/$defs/point2" }, { type: "string" }]
38
+ gradientStop: {
39
+ oneOf: [
40
+ {
41
+ type: "array",
42
+ minItems: 2,
43
+ maxItems: 2,
44
+ prefixItems: [{ type: "number", minimum: 0, maximum: 1 }, { type: "string" }]
45
+ },
46
+ {
47
+ type: "object",
48
+ required: ["offset", "color"],
49
+ additionalProperties: false,
50
+ properties: {
51
+ offset: { type: "number", minimum: 0, maximum: 1 },
52
+ color: { type: "string" }
53
+ }
54
+ }
55
+ ]
154
56
  },
155
57
  paint: paintSchema(),
156
- imageFit: {
157
- enum: ["fill", "contain", "cover"]
158
- },
159
- gradientStops: gradientStopsSchema(),
160
58
  effects: effectsSchema(),
161
- clipShape: clipShapeSchema(),
59
+ imageFit: { enum: ["fill", "contain", "cover"] },
162
60
  imageSource: {
163
61
  type: "object",
164
62
  required: ["x", "y", "width", "height", "imageWidth", "imageHeight"],
63
+ additionalProperties: false,
165
64
  properties: {
166
65
  x: { type: "number" },
167
66
  y: { type: "number" },
@@ -169,100 +68,206 @@ function generateVisualSchema() {
169
68
  height: { type: "number" },
170
69
  imageWidth: { type: "number" },
171
70
  imageHeight: { type: "number" }
172
- },
173
- additionalProperties: true
71
+ }
174
72
  },
175
- animationValue: {
73
+ clipShape: {
176
74
  type: "object",
177
- additionalProperties: true,
75
+ required: ["type", "d"],
76
+ additionalProperties: false,
178
77
  properties: {
179
- from: { oneOf: [{ type: "number" }, { type: "string" }] },
180
- to: { oneOf: [{ type: "number" }, { type: "string" }] },
181
- duration: { type: "number" },
182
- delay: { type: "number" },
183
- ease: { type: "string" },
184
- keyframes: {
78
+ type: { const: "path" },
79
+ d: { type: "string" }
80
+ }
81
+ },
82
+ maskShape: {
83
+ type: "object",
84
+ required: ["type", "d"],
85
+ additionalProperties: false,
86
+ properties: {
87
+ type: { const: "path" },
88
+ d: { type: "string" },
89
+ opacity: { type: "number", minimum: 0, maximum: 1 }
90
+ }
91
+ },
92
+ timelineValue: {
93
+ oneOf: [
94
+ { type: "number" },
95
+ { type: "string" },
96
+ { type: "array", items: { type: "number" } },
97
+ { type: "array", items: { type: "string" } },
98
+ { type: "object", additionalProperties: true }
99
+ ]
100
+ },
101
+ timelineCurve: {
102
+ oneOf: [
103
+ {
104
+ type: "object",
105
+ required: ["type", "points"],
106
+ additionalProperties: false,
107
+ properties: {
108
+ type: { const: "graph" },
109
+ points: {
110
+ type: "array",
111
+ minItems: 2,
112
+ items: { $ref: "#/$defs/point2" }
113
+ }
114
+ }
115
+ },
116
+ {
117
+ type: "object",
118
+ required: ["type", "x1", "y1", "x2", "y2"],
119
+ additionalProperties: false,
120
+ properties: {
121
+ type: { const: "cubicBezier" },
122
+ x1: { type: "number", minimum: 0, maximum: 1 },
123
+ y1: { type: "number" },
124
+ x2: { type: "number", minimum: 0, maximum: 1 },
125
+ y2: { type: "number" }
126
+ }
127
+ },
128
+ {
129
+ type: "object",
130
+ required: ["type"],
131
+ additionalProperties: false,
132
+ properties: {
133
+ type: { const: "hold" }
134
+ }
135
+ }
136
+ ]
137
+ },
138
+ timelineKeyframe: {
139
+ oneOf: [
140
+ {
185
141
  type: "array",
186
- items: {
187
- type: "array",
188
- minItems: 2,
189
- maxItems: 2,
190
- prefixItems: [{ type: "number" }, { oneOf: [{ type: "number" }, { type: "string" }] }]
142
+ minItems: 2,
143
+ maxItems: 2,
144
+ prefixItems: [{ type: "number" }, { $ref: "#/$defs/timelineValue" }]
145
+ },
146
+ {
147
+ type: "object",
148
+ required: ["time", "value"],
149
+ additionalProperties: false,
150
+ properties: {
151
+ time: { type: "number" },
152
+ value: { $ref: "#/$defs/timelineValue" },
153
+ in: { $ref: "#/$defs/timelineCurve" },
154
+ out: { $ref: "#/$defs/timelineCurve" },
155
+ interpolation: { $ref: "#/$defs/timelineCurve" }
191
156
  }
192
157
  }
193
- }
158
+ ]
194
159
  },
195
- clip: {
160
+ timelineTrack: {
196
161
  type: "object",
197
- required: ["scene", "duration"],
162
+ required: ["keyframes"],
163
+ additionalProperties: false,
198
164
  properties: {
199
- scene: { type: "string" },
200
- duration: { type: "number" },
201
- transition: {
202
- oneOf: [
203
- { enum: ["cut", "fade"] },
204
- {
205
- type: "object",
206
- required: ["type"],
207
- properties: {
208
- type: { enum: ["cut", "fade"] },
209
- duration: { type: "number" }
210
- },
211
- additionalProperties: true
212
- }
213
- ]
165
+ curve: { $ref: "#/$defs/timelineCurve" },
166
+ ease: { type: "string" },
167
+ keyframes: {
168
+ type: "array",
169
+ minItems: 1,
170
+ items: { $ref: "#/$defs/timelineKeyframe" }
214
171
  }
215
- },
216
- additionalProperties: true
172
+ }
217
173
  },
218
- deckStep: {
174
+ timeline: {
219
175
  type: "object",
220
- required: ["id"],
176
+ additionalProperties: false,
221
177
  properties: {
222
- id: { type: "string" },
223
- show: { type: "array", items: { type: "string" } },
224
- hide: { type: "array", items: { type: "string" } },
225
- duration: { type: "number" }
226
- },
227
- additionalProperties: true
178
+ start: { type: "number", minimum: 0 },
179
+ end: { type: "number", minimum: 0 },
180
+ tracks: {
181
+ type: "object",
182
+ additionalProperties: { $ref: "#/$defs/timelineTrack" }
183
+ }
184
+ }
228
185
  },
229
186
  element: {
230
- type: "object",
231
- required: ["type"],
232
- additionalProperties: true,
233
- properties: elementProperties
187
+ oneOf: [
188
+ elementSchema("path", {
189
+ d: { type: "string" },
190
+ x: { type: "number" },
191
+ y: { type: "number" }
192
+ }, ["d"]),
193
+ elementSchema("text", {
194
+ x: { type: "number" },
195
+ y: { type: "number" },
196
+ text: { type: "string" },
197
+ lines: { type: "array", items: { type: "string" } },
198
+ align: { enum: ["left", "center", "right"] },
199
+ valign: { enum: ["top", "middle", "bottom"] },
200
+ fontSize: { type: "number" },
201
+ fontFamily: { type: "string" },
202
+ weight: { oneOf: [{ type: "number" }, { type: "string" }] },
203
+ fontStyle: { type: "string" },
204
+ lineHeight: { type: "number" },
205
+ letterSpacing: { type: "number" },
206
+ maxWidth: { type: "number" },
207
+ wrap: { type: "boolean" }
208
+ }, ["x", "y"]),
209
+ elementSchema("image", {
210
+ src: { type: "string" },
211
+ x: { type: "number" },
212
+ y: { type: "number" },
213
+ width: { type: "number" },
214
+ height: { type: "number" },
215
+ fit: { $ref: "#/$defs/imageFit" },
216
+ source: { $ref: "#/$defs/imageSource" }
217
+ }, ["src", "x", "y", "width", "height"]),
218
+ elementSchema("point", {
219
+ x: { type: "number" },
220
+ y: { type: "number" }
221
+ }, ["x", "y"]),
222
+ elementSchema("group", {
223
+ x: { type: "number" },
224
+ y: { type: "number" },
225
+ width: { type: "number" },
226
+ height: { type: "number" },
227
+ children: { type: "array", items: { $ref: "#/$defs/element" } }
228
+ }, ["x", "y", "children"])
229
+ ]
234
230
  }
235
231
  }
236
232
  };
237
233
  }
238
- function mergeSchemaProperty(existing, incoming) {
239
- if (existing === undefined)
240
- return incoming;
241
- if (schemaKey(existing) === schemaKey(incoming))
242
- return existing;
243
- const items = schemaAlternatives(existing);
244
- const incomingItems = schemaAlternatives(incoming);
245
- for (const item of incomingItems) {
246
- if (!items.some((existingItem) => schemaKey(existingItem) === schemaKey(item)))
247
- items.push(item);
248
- }
249
- return { oneOf: items };
250
- }
251
- function schemaAlternatives(value) {
252
- if (value && typeof value === "object" && Array.isArray(value.oneOf)) {
253
- return [...(value.oneOf)];
254
- }
255
- return [value];
256
- }
257
- function schemaKey(value) {
258
- return JSON.stringify(sortJson(value));
234
+ function elementSchema(type, properties, required) {
235
+ return {
236
+ type: "object",
237
+ required: ["type", ...required],
238
+ additionalProperties: false,
239
+ properties: {
240
+ ...commonElementProperties(),
241
+ type: { const: type },
242
+ ...properties
243
+ }
244
+ };
259
245
  }
260
- function sortJson(value) {
261
- if (Array.isArray(value))
262
- return value.map(sortJson);
263
- if (!value || typeof value !== "object")
264
- return value;
265
- return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, sortJson(item)]));
246
+ function commonElementProperties() {
247
+ return {
248
+ id: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_.-]*$" },
249
+ opacity: { type: "number" },
250
+ fill: { $ref: "#/$defs/paint" },
251
+ stroke: { $ref: "#/$defs/paint" },
252
+ strokeWidth: { type: "number" },
253
+ strokeCap: { enum: ["butt", "round", "square"] },
254
+ strokeJoin: { enum: ["miter", "round", "bevel"] },
255
+ miterLimit: { type: "number" },
256
+ dashArray: { type: "array", items: { type: "number" } },
257
+ dashOffset: { type: "number" },
258
+ drawStart: { type: "number" },
259
+ drawEnd: { type: "number" },
260
+ effects: { $ref: "#/$defs/effects" },
261
+ blendMode: { type: "string" },
262
+ rotation: { type: "number" },
263
+ scale: { type: "number" },
264
+ scaleX: { type: "number" },
265
+ scaleY: { type: "number" },
266
+ origin: { $ref: "#/$defs/point2" },
267
+ clip: { $ref: "#/$defs/clipShape" },
268
+ mask: { $ref: "#/$defs/maskShape" },
269
+ timeline: { $ref: "#/$defs/timeline" }
270
+ };
266
271
  }
267
272
  function paintSchema() {
268
273
  return {
@@ -271,29 +276,30 @@ function paintSchema() {
271
276
  {
272
277
  type: "object",
273
278
  required: ["type", "from", "to", "stops"],
279
+ additionalProperties: false,
274
280
  properties: {
275
281
  type: { const: "linearGradient" },
276
282
  from: { $ref: "#/$defs/point2" },
277
283
  to: { $ref: "#/$defs/point2" },
278
- stops: { $ref: "#/$defs/gradientStops" }
279
- },
280
- additionalProperties: true
284
+ stops: { type: "array", minItems: 2, items: { $ref: "#/$defs/gradientStop" } }
285
+ }
281
286
  },
282
287
  {
283
288
  type: "object",
284
289
  required: ["type", "center", "radius", "stops"],
290
+ additionalProperties: false,
285
291
  properties: {
286
292
  type: { const: "radialGradient" },
287
293
  center: { $ref: "#/$defs/point2" },
288
294
  radius: { type: "number" },
289
295
  focus: { $ref: "#/$defs/point2" },
290
- stops: { $ref: "#/$defs/gradientStops" }
291
- },
292
- additionalProperties: true
296
+ stops: { type: "array", minItems: 2, items: { $ref: "#/$defs/gradientStop" } }
297
+ }
293
298
  },
294
299
  {
295
300
  type: "object",
296
301
  required: ["type", "src", "width", "height"],
302
+ additionalProperties: false,
297
303
  properties: {
298
304
  type: { const: "pattern" },
299
305
  src: { type: "string" },
@@ -303,40 +309,15 @@ function paintSchema() {
303
309
  height: { type: "number" },
304
310
  fit: { $ref: "#/$defs/imageFit" },
305
311
  opacity: { type: "number" }
306
- },
307
- additionalProperties: true
312
+ }
308
313
  }
309
314
  ]
310
315
  };
311
316
  }
312
- function gradientStopsSchema() {
313
- return {
314
- type: "array",
315
- minItems: 2,
316
- items: {
317
- oneOf: [
318
- {
319
- type: "array",
320
- minItems: 2,
321
- maxItems: 2,
322
- prefixItems: [{ type: "number" }, { type: "string" }]
323
- },
324
- {
325
- type: "object",
326
- required: ["offset", "color"],
327
- properties: {
328
- offset: { type: "number" },
329
- color: { type: "string" }
330
- },
331
- additionalProperties: true
332
- }
333
- ]
334
- }
335
- };
336
- }
337
317
  function effectsSchema() {
338
318
  return {
339
319
  type: "object",
320
+ additionalProperties: false,
340
321
  properties: {
341
322
  blur: { type: "number" },
342
323
  brightness: { type: "number" },
@@ -346,58 +327,15 @@ function effectsSchema() {
346
327
  shadow: {
347
328
  type: "object",
348
329
  required: ["dx", "dy", "blur", "color"],
330
+ additionalProperties: false,
349
331
  properties: {
350
332
  dx: { type: "number" },
351
333
  dy: { type: "number" },
352
334
  blur: { type: "number" },
353
335
  color: { type: "string" },
354
336
  opacity: { type: "number" }
355
- },
356
- additionalProperties: true
357
- }
358
- },
359
- additionalProperties: true
360
- };
361
- }
362
- function clipShapeSchema() {
363
- return {
364
- oneOf: [
365
- {
366
- type: "object",
367
- required: ["type", "x", "y", "width", "height"],
368
- properties: {
369
- type: { const: "rect" },
370
- x: { type: "number" },
371
- y: { type: "number" },
372
- width: { type: "number" },
373
- height: { type: "number" },
374
- radius: { type: "number" },
375
- opacity: { type: "number" }
376
- },
377
- additionalProperties: true
378
- },
379
- {
380
- type: "object",
381
- required: ["type", "cx", "cy", "radius"],
382
- properties: {
383
- type: { const: "circle" },
384
- cx: { type: "number" },
385
- cy: { type: "number" },
386
- radius: { type: "number" },
387
- opacity: { type: "number" }
388
- },
389
- additionalProperties: true
390
- },
391
- {
392
- type: "object",
393
- required: ["type", "d"],
394
- properties: {
395
- type: { const: "path" },
396
- d: { type: "string" },
397
- opacity: { type: "number" }
398
- },
399
- additionalProperties: true
337
+ }
400
338
  }
401
- ]
339
+ }
402
340
  };
403
341
  }