@pixerate/editor 0.73.0 → 0.74.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 (42) hide show
  1. package/THIRD_PARTY_NOTICES.md +1 -0
  2. package/dist/animation-editor/index.cjs +708 -298
  3. package/dist/animation-editor/index.cjs.map +1 -1
  4. package/dist/animation-editor/index.d.cts +36 -2
  5. package/dist/animation-editor/index.d.ts +36 -2
  6. package/dist/animation-editor/index.js +693 -283
  7. package/dist/animation-editor/index.js.map +1 -1
  8. package/dist/chart/index.cjs +11 -9
  9. package/dist/chart/index.cjs.map +1 -1
  10. package/dist/chart/index.js +5 -3
  11. package/dist/chart/index.js.map +1 -1
  12. package/dist/{chunk-3S72F46R.js → chunk-2GFUA4X5.js} +2 -322
  13. package/dist/chunk-2GFUA4X5.js.map +1 -0
  14. package/dist/chunk-33AHNSEB.js +323 -0
  15. package/dist/chunk-33AHNSEB.js.map +1 -0
  16. package/dist/{chunk-NN3JGUSX.cjs → chunk-5PTR7HTL.cjs} +3 -323
  17. package/dist/chunk-5PTR7HTL.cjs.map +1 -0
  18. package/dist/{chunk-4YFMSPBU.js → chunk-EIXXBKUB.js} +6 -4
  19. package/dist/{chunk-4YFMSPBU.js.map → chunk-EIXXBKUB.js.map} +1 -1
  20. package/dist/chunk-EMQWJA3G.cjs +323 -0
  21. package/dist/chunk-EMQWJA3G.cjs.map +1 -0
  22. package/dist/{chunk-BQQZ6MOI.js → chunk-FGW5OWJ4.js} +6 -4
  23. package/dist/{chunk-BQQZ6MOI.js.map → chunk-FGW5OWJ4.js.map} +1 -1
  24. package/dist/{chunk-YZZMX6V7.cjs → chunk-FV5AXTSF.cjs} +11 -9
  25. package/dist/chunk-FV5AXTSF.cjs.map +1 -0
  26. package/dist/{chunk-7ZSU4MQZ.cjs → chunk-PL3MPFPA.cjs} +10 -8
  27. package/dist/chunk-PL3MPFPA.cjs.map +1 -0
  28. package/dist/export/index.cjs +4 -3
  29. package/dist/export/index.cjs.map +1 -1
  30. package/dist/export/index.js +3 -2
  31. package/dist/extensions/index.cjs +4 -3
  32. package/dist/extensions/index.cjs.map +1 -1
  33. package/dist/extensions/index.js +3 -2
  34. package/dist/index.cjs +19 -18
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.js +12 -11
  37. package/dist/index.js.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/chunk-3S72F46R.js.map +0 -1
  40. package/dist/chunk-7ZSU4MQZ.cjs.map +0 -1
  41. package/dist/chunk-NN3JGUSX.cjs.map +0 -1
  42. package/dist/chunk-YZZMX6V7.cjs.map +0 -1
@@ -17,6 +17,8 @@
17
17
 
18
18
 
19
19
 
20
+
21
+
20
22
 
21
23
  var _chunkYJLCBA7Vcjs = require('../chunk-YJLCBA7V.cjs');
22
24
 
@@ -28,6 +30,9 @@ var _chunkYJLCBA7Vcjs = require('../chunk-YJLCBA7V.cjs');
28
30
  var _chunkO2UH7LZEcjs = require('../chunk-O2UH7LZE.cjs');
29
31
 
30
32
 
33
+ var _chunkEMQWJA3Gcjs = require('../chunk-EMQWJA3G.cjs');
34
+
35
+
31
36
  var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
32
37
 
33
38
 
@@ -112,21 +117,21 @@ var MOTION_DEFAULT_HOLD = 600;
112
117
  var MOTION_CAMERA_MS = 1e3;
113
118
  var MOTION_DRAW_MS_PER_UNIT = 1.5;
114
119
  var MOTION_DRAW_RANGE = [500, 2500];
115
- function motionFlairPrimitive(command2) {
116
- switch (command2.type) {
120
+ function motionFlairPrimitive(command3) {
121
+ switch (command3.type) {
117
122
  case "enter":
118
- return `entrance.${_nullishCoalesce(command2.style, () => ( "fade"))}`;
123
+ return `entrance.${_nullishCoalesce(command3.style, () => ( "fade"))}`;
119
124
  case "exit":
120
- return `exit.${_nullishCoalesce(command2.style, () => ( "fade"))}`;
125
+ return `exit.${_nullishCoalesce(command3.style, () => ( "fade"))}`;
121
126
  case "pulse":
122
127
  case "shake":
123
128
  case "teeter":
124
129
  case "wave":
125
130
  case "wiggle":
126
131
  case "color-pulse":
127
- return `emphasis.${command2.type}`;
132
+ return `emphasis.${command3.type}`;
128
133
  case "rotate":
129
- return command2.by !== void 0 ? "emphasis.spin" : void 0;
134
+ return command3.by !== void 0 ? "emphasis.spin" : void 0;
130
135
  case "follow":
131
136
  return "path.follow";
132
137
  default:
@@ -254,108 +259,108 @@ var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
254
259
  function unknownKeys(value, known, where, problems) {
255
260
  for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${namedWithSuggestion(key, known)}.`);
256
261
  }
257
- function commandShapeProblems(command2, where) {
262
+ function commandShapeProblems(command3, where) {
258
263
  const problems = [];
259
- if (!isObject(command2)) return [`${where} must be an object.`];
260
- const type = command2.type;
264
+ if (!isObject(command3)) return [`${where} must be an object.`];
265
+ const type = command3.type;
261
266
  if (typeof type !== "string" || !MOTION_COMMAND_TYPES.includes(type)) {
262
267
  return [`${where}: unknown type ${typeof type === "string" ? namedWithSuggestion(type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
263
268
  }
264
- unknownKeys(command2, COMMAND_KEYS[type], `${where} (${type})`, problems);
269
+ unknownKeys(command3, COMMAND_KEYS[type], `${where} (${type})`, problems);
265
270
  const p = (msg) => problems.push(`${where} (${type}): ${msg}`);
266
271
  const nonNegative = (key) => {
267
- if (command2[key] !== void 0 && !(isNum(command2[key]) && command2[key] >= 0)) p(`"${key}" must be a number of milliseconds \u2265 0.`);
272
+ if (command3[key] !== void 0 && !(isNum(command3[key]) && command3[key] >= 0)) p(`"${key}" must be a number of milliseconds \u2265 0.`);
268
273
  };
269
274
  const fraction = (key) => {
270
- if (command2[key] !== void 0 && !(isNum(command2[key]) && command2[key] >= 0 && command2[key] <= 1)) p(`"${key}" must be a fraction from 0 to 1.`);
275
+ if (command3[key] !== void 0 && !(isNum(command3[key]) && command3[key] >= 0 && command3[key] <= 1)) p(`"${key}" must be a fraction from 0 to 1.`);
271
276
  };
272
277
  const optionalNumber = (key) => {
273
- if (command2[key] !== void 0 && !isNum(command2[key])) p(`"${key}" must be a number.`);
278
+ if (command3[key] !== void 0 && !isNum(command3[key])) p(`"${key}" must be a number.`);
274
279
  };
275
- if (command2.with !== void 0 && command2.with !== "after" && command2.with !== "previous") p(`"with" must be "after" or "previous".`);
276
- if (DRAW_ORDER_KEYS.some((k) => command2[k] !== void 0)) {
277
- if (type === "enter" && command2.style !== "draw" || type === "exit" && command2.style !== "undraw") p(`"order", "pace", "align", "sortBy" and "origin" go with drawing: style "${type === "enter" ? "draw" : "undraw"}".`);
278
- if (command2.order !== void 0 && command2.order !== "together" && command2.order !== "sequence") p(`"order" must be "together" or "sequence" (one stroke after another).`);
279
- if (command2.pace !== void 0 && command2.pace !== "time" && command2.pace !== "speed") p(`"pace" must be "time" (each stroke takes the whole time) or "speed" (all at one speed).`);
280
- if (command2.align !== void 0 && command2.align !== "start" && command2.align !== "end") p(`"align" must be "start" or "end".`);
281
- if (command2.sortBy !== void 0 && command2.sortBy !== "document" && command2.sortBy !== "distance") p(`"sortBy" must be "document" or "distance".`);
282
- if (command2.origin !== void 0 && !isPoint(command2.origin)) p(`"origin" must be { "x": number, "y": number } (document units).`);
280
+ if (command3.with !== void 0 && command3.with !== "after" && command3.with !== "previous") p(`"with" must be "after" or "previous".`);
281
+ if (DRAW_ORDER_KEYS.some((k) => command3[k] !== void 0)) {
282
+ if (type === "enter" && command3.style !== "draw" || type === "exit" && command3.style !== "undraw") p(`"order", "pace", "align", "sortBy" and "origin" go with drawing: style "${type === "enter" ? "draw" : "undraw"}".`);
283
+ if (command3.order !== void 0 && command3.order !== "together" && command3.order !== "sequence") p(`"order" must be "together" or "sequence" (one stroke after another).`);
284
+ if (command3.pace !== void 0 && command3.pace !== "time" && command3.pace !== "speed") p(`"pace" must be "time" (each stroke takes the whole time) or "speed" (all at one speed).`);
285
+ if (command3.align !== void 0 && command3.align !== "start" && command3.align !== "end") p(`"align" must be "start" or "end".`);
286
+ if (command3.sortBy !== void 0 && command3.sortBy !== "document" && command3.sortBy !== "distance") p(`"sortBy" must be "document" or "distance".`);
287
+ if (command3.origin !== void 0 && !isPoint(command3.origin)) p(`"origin" must be { "x": number, "y": number } (document units).`);
283
288
  }
284
- if (command2.note !== void 0 && typeof command2.note !== "string") p(`"note" must be a string.`);
289
+ if (command3.note !== void 0 && typeof command3.note !== "string") p(`"note" must be a string.`);
285
290
  if (type === "wait") {
286
- if (!isNum(command2.duration) || command2.duration < 0) p(`"duration" must be a number of milliseconds \u2265 0.`);
291
+ if (!isNum(command3.duration) || command3.duration < 0) p(`"duration" must be a number of milliseconds \u2265 0.`);
287
292
  return problems;
288
293
  }
289
- if (!Array.isArray(command2.targets) || command2.targets.length === 0 || !command2.targets.every((t) => typeof t === "string" && t.length > 0)) p(`"targets" must be a non-empty list of node ids.`);
294
+ if (!Array.isArray(command3.targets) || command3.targets.length === 0 || !command3.targets.every((t) => typeof t === "string" && t.length > 0)) p(`"targets" must be a non-empty list of node ids.`);
290
295
  nonNegative("duration");
291
296
  nonNegative("delay");
292
297
  nonNegative("stagger");
293
- if (command2.ease !== void 0 && !_chunk2FHLHZALcjs.isAnimationEasing.call(void 0, command2.ease)) p(`"ease" is not an easing; use a preset such as "ease-in-out" or "spring-bouncy", or { "type": "cubic-bezier", \u2026 } or { "type": "spring", \u2026 }.`);
294
- if (command2.repeat !== void 0) {
298
+ if (command3.ease !== void 0 && !_chunk2FHLHZALcjs.isAnimationEasing.call(void 0, command3.ease)) p(`"ease" is not an easing; use a preset such as "ease-in-out" or "spring-bouncy", or { "type": "cubic-bezier", \u2026 } or { "type": "spring", \u2026 }.`);
299
+ if (command3.repeat !== void 0) {
295
300
  if (type === "enter" || type === "exit") p(`"repeat" is not for ${type} (it brings things in or out once); repeat an emphasis or a move instead.`);
296
- else if (!(Number.isInteger(command2.repeat) && command2.repeat >= 1 && command2.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
301
+ else if (!(Number.isInteger(command3.repeat) && command3.repeat >= 1 && command3.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
297
302
  }
298
- if (command2.blend !== void 0 && !MOTION_BLENDS.includes(command2.blend)) p(`"blend" must be "replace" (the change takes over) or "add" (a layer on top).`);
299
- if (command2.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command2.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
300
- if (command2.steps !== void 0 && !(isNum(command2.steps) && command2.steps > 0 && command2.steps <= 120)) p(`"steps" must be frames per second from above 0 to 120 (12 holds each pose for two frames at 24 fps).`);
303
+ if (command3.blend !== void 0 && !MOTION_BLENDS.includes(command3.blend)) p(`"blend" must be "replace" (the change takes over) or "add" (a layer on top).`);
304
+ if (command3.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command3.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
305
+ if (command3.steps !== void 0 && !(isNum(command3.steps) && command3.steps > 0 && command3.steps <= 120)) p(`"steps" must be frames per second from above 0 to 120 (12 holds each pose for two frames at 24 fps).`);
301
306
  switch (type) {
302
307
  case "enter":
303
308
  case "exit": {
304
309
  const styles = type === "enter" ? MOTION_ENTER_STYLES : MOTION_EXIT_STYLES;
305
- if (command2.style !== void 0 && !(typeof command2.style === "string" && styles.includes(command2.style)))
306
- p(`"style" must be one of ${styles.join(", ")}${typeof command2.style === "string" ? ` (got ${namedWithSuggestion(command2.style, styles)})` : ""}.`);
307
- if (command2.direction !== void 0 && !MOTION_DIRECTIONS.includes(command2.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
310
+ if (command3.style !== void 0 && !(typeof command3.style === "string" && styles.includes(command3.style)))
311
+ p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${namedWithSuggestion(command3.style, styles)})` : ""}.`);
312
+ if (command3.direction !== void 0 && !MOTION_DIRECTIONS.includes(command3.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
308
313
  optionalNumber("distance");
309
- if (command2.scale !== void 0 && !(isNum(command2.scale) && command2.scale >= 0)) p(`"scale" must be a number \u2265 0 (the starting scale for pop and zoom).`);
310
- if (command2.shape !== void 0 && !MOTION_IRIS_SHAPES.includes(command2.shape)) p(`"shape" must be one of ${MOTION_IRIS_SHAPES.join(", ")} (the opening of an iris).`);
311
- if (command2.orientation !== void 0 && !MOTION_SPLIT_ORIENTATIONS.includes(command2.orientation)) p(`"orientation" must be one of ${MOTION_SPLIT_ORIENTATIONS.join(", ")} (the line a split opens from).`);
314
+ if (command3.scale !== void 0 && !(isNum(command3.scale) && command3.scale >= 0)) p(`"scale" must be a number \u2265 0 (the starting scale for pop and zoom).`);
315
+ if (command3.shape !== void 0 && !MOTION_IRIS_SHAPES.includes(command3.shape)) p(`"shape" must be one of ${MOTION_IRIS_SHAPES.join(", ")} (the opening of an iris).`);
316
+ if (command3.orientation !== void 0 && !MOTION_SPLIT_ORIENTATIONS.includes(command3.orientation)) p(`"orientation" must be one of ${MOTION_SPLIT_ORIENTATIONS.join(", ")} (the line a split opens from).`);
312
317
  break;
313
318
  }
314
319
  case "draw":
315
320
  fraction("from");
316
321
  fraction("to");
317
322
  fraction("comet");
318
- if (command2.comet !== void 0 && (command2.from !== void 0 || command2.to !== void 0)) p(`"comet" runs the whole path; leave out "from" and "to".`);
323
+ if (command3.comet !== void 0 && (command3.from !== void 0 || command3.to !== void 0)) p(`"comet" runs the whole path; leave out "from" and "to".`);
319
324
  break;
320
325
  case "move":
321
- if (command2.by === void 0 && command2.to === void 0) p(`give "by" (an offset) or "to" (a point).`);
322
- if (command2.by !== void 0 && command2.to !== void 0) p(`give "by" or "to", not both.`);
323
- if (command2.by !== void 0 && !isPoint(command2.by)) p(`"by" must be { "x": number, "y": number }.`);
324
- if (command2.to !== void 0 && !isPoint(command2.to)) p(`"to" must be { "x": number, "y": number }.`);
325
- if (command2.via !== void 0 && !(Array.isArray(command2.via) && command2.via.length > 0 && command2.via.length <= 64 && command2.via.every(isPoint))) p(`"via" must be a list of 1 to 64 points { "x": number, "y": number } (document units).`);
326
- if (command2.pacing !== void 0 && command2.pacing !== "even" && command2.pacing !== "equal") p(`"pacing" must be "even" (steady speed) or "equal" (each leg the same time).`);
327
- if (command2.pacing !== void 0 && command2.via === void 0) p(`"pacing" goes with "via".`);
326
+ if (command3.by === void 0 && command3.to === void 0) p(`give "by" (an offset) or "to" (a point).`);
327
+ if (command3.by !== void 0 && command3.to !== void 0) p(`give "by" or "to", not both.`);
328
+ if (command3.by !== void 0 && !isPoint(command3.by)) p(`"by" must be { "x": number, "y": number }.`);
329
+ if (command3.to !== void 0 && !isPoint(command3.to)) p(`"to" must be { "x": number, "y": number }.`);
330
+ if (command3.via !== void 0 && !(Array.isArray(command3.via) && command3.via.length > 0 && command3.via.length <= 64 && command3.via.every(isPoint))) p(`"via" must be a list of 1 to 64 points { "x": number, "y": number } (document units).`);
331
+ if (command3.pacing !== void 0 && command3.pacing !== "even" && command3.pacing !== "equal") p(`"pacing" must be "even" (steady speed) or "equal" (each leg the same time).`);
332
+ if (command3.pacing !== void 0 && command3.via === void 0) p(`"pacing" goes with "via".`);
328
333
  break;
329
334
  case "rotate":
330
- if (command2.by === void 0 && command2.to === void 0) p(`give "by" or "to" (degrees).`);
331
- if (command2.by !== void 0 && command2.to !== void 0) p(`give "by" or "to", not both.`);
335
+ if (command3.by === void 0 && command3.to === void 0) p(`give "by" or "to" (degrees).`);
336
+ if (command3.by !== void 0 && command3.to !== void 0) p(`give "by" or "to", not both.`);
332
337
  optionalNumber("by");
333
338
  optionalNumber("to");
334
339
  break;
335
340
  case "scale":
336
- if (!(isNum(command2.to) || isPoint(command2.to))) p(`"to" must be a number or { "x": number, "y": number }.`);
337
- if (command2.geometric !== void 0 && typeof command2.geometric !== "boolean") p(`"geometric" must be true or false.`);
341
+ if (!(isNum(command3.to) || isPoint(command3.to))) p(`"to" must be a number or { "x": number, "y": number }.`);
342
+ if (command3.geometric !== void 0 && typeof command3.geometric !== "boolean") p(`"geometric" must be true or false.`);
338
343
  break;
339
344
  case "fade":
340
- if (!(isNum(command2.to) && command2.to >= 0 && command2.to <= 1)) p(`"to" must be an opacity from 0 to 1.`);
345
+ if (!(isNum(command3.to) && command3.to >= 0 && command3.to <= 1)) p(`"to" must be an opacity from 0 to 1.`);
341
346
  break;
342
347
  case "style":
343
- if (command2.fill === void 0 && command2.stroke === void 0 && command2.strokeWidth === void 0) p(`give at least one of "fill", "stroke" or "strokeWidth".`);
344
- if (command2.fill !== void 0 && typeof command2.fill !== "string") p(`"fill" must be a CSS colour.`);
345
- if (command2.stroke !== void 0 && typeof command2.stroke !== "string") p(`"stroke" must be a CSS colour.`);
346
- if (command2.strokeWidth !== void 0 && !(isNum(command2.strokeWidth) && command2.strokeWidth >= 0)) p(`"strokeWidth" must be a number \u2265 0.`);
348
+ if (command3.fill === void 0 && command3.stroke === void 0 && command3.strokeWidth === void 0) p(`give at least one of "fill", "stroke" or "strokeWidth".`);
349
+ if (command3.fill !== void 0 && typeof command3.fill !== "string") p(`"fill" must be a CSS colour.`);
350
+ if (command3.stroke !== void 0 && typeof command3.stroke !== "string") p(`"stroke" must be a CSS colour.`);
351
+ if (command3.strokeWidth !== void 0 && !(isNum(command3.strokeWidth) && command3.strokeWidth >= 0)) p(`"strokeWidth" must be a number \u2265 0.`);
347
352
  break;
348
353
  case "play":
349
- if (typeof command2.clip !== "string" || !command2.clip) p(`"clip" must be the name of one of the scene's clips.`);
350
- if (command2.speed !== void 0 && !(isNum(command2.speed) && command2.speed >= 0.05 && command2.speed <= 20)) p(`"speed" must be a number from 0.05 to 20 (2 plays the clip twice as fast).`);
354
+ if (typeof command3.clip !== "string" || !command3.clip) p(`"clip" must be the name of one of the scene's clips.`);
355
+ if (command3.speed !== void 0 && !(isNum(command3.speed) && command3.speed >= 0.05 && command3.speed <= 20)) p(`"speed" must be a number from 0.05 to 20 (2 plays the clip twice as fast).`);
351
356
  break;
352
357
  case "morph":
353
358
  case "match":
354
- if (typeof command2.into !== "string" || !command2.into) p(`"into" must be the id of a ${type === "match" ? "group to become" : "node whose shape to take"}.`);
359
+ if (typeof command3.into !== "string" || !command3.into) p(`"into" must be the id of a ${type === "match" ? "group to become" : "node whose shape to take"}.`);
355
360
  break;
356
361
  case "follow":
357
- if (typeof command2.path !== "string" || !command2.path) p(`"path" must be the id of a path node.`);
358
- if (command2.rotate !== void 0 && typeof command2.rotate !== "boolean") p(`"rotate" must be true or false.`);
362
+ if (typeof command3.path !== "string" || !command3.path) p(`"path" must be the id of a path node.`);
363
+ if (command3.rotate !== void 0 && typeof command3.rotate !== "boolean") p(`"rotate" must be true or false.`);
359
364
  fraction("from");
360
365
  fraction("to");
361
366
  break;
@@ -366,22 +371,22 @@ function commandShapeProblems(command2, where) {
366
371
  case "color-pulse":
367
372
  optionalNumber("amount");
368
373
  optionalNumber("angle");
369
- if (command2.count !== void 0 && !(Number.isInteger(command2.count) && command2.count >= 1)) p(`"count" must be a whole number \u2265 1.`);
370
- if (command2.axis !== void 0 && command2.axis !== "horizontal" && command2.axis !== "vertical") p(`"axis" must be "horizontal" or "vertical".`);
371
- if (command2.color !== void 0 && typeof command2.color !== "string") p(`"color" must be a CSS colour.`);
372
- if (command2.paint !== void 0 && command2.paint !== "fill" && command2.paint !== "stroke") p(`"paint" must be "fill" or "stroke".`);
374
+ if (command3.count !== void 0 && !(Number.isInteger(command3.count) && command3.count >= 1)) p(`"count" must be a whole number \u2265 1.`);
375
+ if (command3.axis !== void 0 && command3.axis !== "horizontal" && command3.axis !== "vertical") p(`"axis" must be "horizontal" or "vertical".`);
376
+ if (command3.color !== void 0 && typeof command3.color !== "string") p(`"color" must be a CSS colour.`);
377
+ if (command3.paint !== void 0 && command3.paint !== "fill" && command3.paint !== "stroke") p(`"paint" must be "fill" or "stroke".`);
373
378
  break;
374
379
  case "wiggle":
375
380
  optionalNumber("amount");
376
381
  optionalNumber("rotate");
377
- if (command2.frequency !== void 0 && !(isNum(command2.frequency) && command2.frequency > 0)) p(`"frequency" must be a number of Hz > 0.`);
378
- if (command2.octaves !== void 0 && !(Number.isInteger(command2.octaves) && command2.octaves >= 1 && command2.octaves <= 8)) p(`"octaves" must be a whole number from 1 to 8.`);
379
- if (command2.seed !== void 0 && !(Number.isInteger(command2.seed) && command2.seed >= 0)) p(`"seed" must be a whole number \u2265 0.`);
382
+ if (command3.frequency !== void 0 && !(isNum(command3.frequency) && command3.frequency > 0)) p(`"frequency" must be a number of Hz > 0.`);
383
+ if (command3.octaves !== void 0 && !(Number.isInteger(command3.octaves) && command3.octaves >= 1 && command3.octaves <= 8)) p(`"octaves" must be a whole number from 1 to 8.`);
384
+ if (command3.seed !== void 0 && !(Number.isInteger(command3.seed) && command3.seed >= 0)) p(`"seed" must be a whole number \u2265 0.`);
380
385
  break;
381
386
  case "effect":
382
- if (typeof command2.effect !== "string" || !command2.effect) p(`"effect" must be the id of one of the node's effects.`);
383
- if (typeof command2.param !== "string" || !command2.param) p(`"param" must name a numeric parameter of the effect.`);
384
- if (!isNum(command2.to)) p(`"to" must be a number.`);
387
+ if (typeof command3.effect !== "string" || !command3.effect) p(`"effect" must be the id of one of the node's effects.`);
388
+ if (typeof command3.param !== "string" || !command3.param) p(`"param" must name a numeric parameter of the effect.`);
389
+ if (!isNum(command3.to)) p(`"to" must be a number.`);
385
390
  break;
386
391
  }
387
392
  return problems;
@@ -398,9 +403,9 @@ function clipsShapeProblems(clips) {
398
403
  }
399
404
  unknownKeys(clip, ["description", "run"], where, problems);
400
405
  if (clip.description !== void 0 && typeof clip.description !== "string") problems.push(`${where}: "description" must be a string.`);
401
- clip.run.forEach((command2, i) => {
402
- if (isObject(command2) && command2.type === "play") problems.push(`${where}, command ${i + 1}: a clip cannot play another clip; copy its commands in instead.`);
403
- else problems.push(...commandShapeProblems(command2, `${where}, command ${i + 1}`));
406
+ clip.run.forEach((command3, i) => {
407
+ if (isObject(command3) && command3.type === "play") problems.push(`${where}, command ${i + 1}: a clip cannot play another clip; copy its commands in instead.`);
408
+ else problems.push(...commandShapeProblems(command3, `${where}, command ${i + 1}`));
404
409
  });
405
410
  }
406
411
  return problems;
@@ -456,7 +461,7 @@ function shotShapeProblems(shot, where) {
456
461
  }
457
462
  }
458
463
  if (!Array.isArray(shot.run)) problems.push(`${name}: "run" must be a list of commands (it may be empty).`);
459
- else shot.run.forEach((command2, i) => problems.push(...commandShapeProblems(command2, `${name}, command ${i + 1}`)));
464
+ else shot.run.forEach((command3, i) => problems.push(...commandShapeProblems(command3, `${name}, command ${i + 1}`)));
460
465
  return problems;
461
466
  }
462
467
  function motionSceneShapeProblems(input) {
@@ -523,7 +528,7 @@ function motionSceneToJson(scene, space = 2) {
523
528
  return JSON.stringify(scene, null, space);
524
529
  }
525
530
  var isMotionShot = (shot) => shotShapeProblems(shot, "Shot").length === 0;
526
- var isMotionCommand = (command2) => commandShapeProblems(command2, "Command").length === 0;
531
+ var isMotionCommand = (command3) => commandShapeProblems(command3, "Command").length === 0;
527
532
 
528
533
  // src/animation-editor/match.ts
529
534
  var SEPARATOR = /[-_/.:]/;
@@ -886,13 +891,13 @@ function motionDriverSources(timeline, node, properties, seen = /* @__PURE__ */
886
891
  }
887
892
  return out;
888
893
  }
889
- function motionCommandRepeat(command2) {
890
- if (command2.type === "wait" || command2.type === "enter" || command2.type === "exit") return 1;
891
- const n = _nullishCoalesce(command2.repeat, () => ( 1));
894
+ function motionCommandRepeat(command3) {
895
+ if (command3.type === "wait" || command3.type === "enter" || command3.type === "exit") return 1;
896
+ const n = _nullishCoalesce(command3.repeat, () => ( 1));
892
897
  return Number.isInteger(n) && n >= 1 ? n : 1;
893
898
  }
894
- function motionCommandDuration(command2, scene, target) {
895
- return motionCycleDuration(command2, scene, target) * motionCommandRepeat(command2);
899
+ function motionCommandDuration(command3, scene, target) {
900
+ return motionCycleDuration(command3, scene, target) * motionCommandRepeat(command3);
896
901
  }
897
902
  function motionClipLayout(scene, clip, target, speed = 1) {
898
903
  const run = _optionalChain([scene, 'access', _28 => _28.clips, 'optionalAccess', _29 => _29[clip], 'optionalAccess', _30 => _30.run]);
@@ -909,36 +914,36 @@ function motionClipLayout(scene, clip, target, speed = 1) {
909
914
  return;
910
915
  }
911
916
  if (raw.type === "play") return;
912
- const command2 = { ...raw, targets: raw.targets.map((t) => t === MOTION_CLIP_TARGET ? target : t) };
913
- const begin = base + (_nullishCoalesce(command2.delay, () => ( 0))) * f;
917
+ const command3 = { ...raw, targets: raw.targets.map((t) => t === MOTION_CLIP_TARGET ? target : t) };
918
+ const begin = base + (_nullishCoalesce(command3.delay, () => ( 0))) * f;
914
919
  let end = begin;
915
- command2.targets.forEach((t, k) => {
916
- const cycle = motionCycleDuration(command2, scene, t) * f;
917
- const s = begin + k * (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
918
- items.push({ command: command2, target: t, start: s, cycle });
919
- end = Math.max(end, s + cycle * motionCommandRepeat(command2));
920
+ command3.targets.forEach((t, k) => {
921
+ const cycle = motionCycleDuration(command3, scene, t) * f;
922
+ const s = begin + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
923
+ items.push({ command: command3, target: t, start: s, cycle });
924
+ end = Math.max(end, s + cycle * motionCommandRepeat(command3));
920
925
  });
921
926
  prevStart = begin;
922
927
  runEnd = Math.max(runEnd, end);
923
928
  });
924
929
  return { items, length: runEnd };
925
930
  }
926
- function motionCycleDuration(command2, scene, target) {
927
- if (command2.type === "wait") return command2.duration;
928
- if (command2.type === "play") return motionClipLayout(scene, command2.clip, _nullishCoalesce(target, () => ( MOTION_CLIP_TARGET)), command2.speed).length;
929
- if (command2.duration !== void 0) return command2.duration;
930
- if (command2.ease !== void 0) {
931
- const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command2.ease);
931
+ function motionCycleDuration(command3, scene, target) {
932
+ if (command3.type === "wait") return command3.duration;
933
+ if (command3.type === "play") return motionClipLayout(scene, command3.clip, _nullishCoalesce(target, () => ( MOTION_CLIP_TARGET)), command3.speed).length;
934
+ if (command3.duration !== void 0) return command3.duration;
935
+ if (command3.ease !== void 0) {
936
+ const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command3.ease);
932
937
  if (ease !== "hold" && ease.type === "spring") return _chunk2FHLHZALcjs.springSettleMs.call(void 0, ease);
933
938
  }
934
- if (command2.type === "draw" || command2.type === "enter" && command2.style === "draw" || command2.type === "exit" && command2.style === "undraw") {
939
+ if (command3.type === "draw" || command3.type === "enter" && command3.style === "draw" || command3.type === "exit" && command3.style === "undraw") {
935
940
  const entry = target ? indexMotionNodes(scene.artwork.nodes).get(target) : void 0;
936
941
  const length = entry ? motionPathLength(entry.node) : 0;
937
942
  const ms = length * MOTION_DRAW_MS_PER_UNIT;
938
943
  return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
939
944
  }
940
- if (command2.type === "move" && _optionalChain([command2, 'access', _31 => _31.via, 'optionalAccess', _32 => _32.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command2.via.length;
941
- return MOTION_DEFAULT_DURATIONS[command2.type];
945
+ if (command3.type === "move" && _optionalChain([command3, 'access', _31 => _31.via, 'optionalAccess', _32 => _32.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
946
+ return MOTION_DEFAULT_DURATIONS[command3.type];
942
947
  }
943
948
  var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
944
949
  var MOTION_EASE_IN_OUT = { type: "cubic-bezier", x1: 0.65, y1: 0, x2: 0.35, y2: 1 };
@@ -974,14 +979,14 @@ function compileMotionScene(scene) {
974
979
  const commandsStart = cursor;
975
980
  let runEnd = cursor;
976
981
  let prevStart = cursor;
977
- shot.run.forEach((command2, i) => {
978
- const base = command2.with === "previous" && i > 0 ? prevStart : runEnd;
979
- const begin = base + (command2.type === "wait" ? 0 : (_nullishCoalesce(command2.delay, () => ( 0))) * f);
980
- const targets = command2.type === "wait" ? [] : command2.targets;
981
- const durations = command2.type === "wait" ? [command2.duration * f] : targets.map((id) => motionCommandDuration(command2, scene, id) * f);
982
- const stagger = command2.type === "wait" ? 0 : (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
982
+ shot.run.forEach((command3, i) => {
983
+ const base = command3.with === "previous" && i > 0 ? prevStart : runEnd;
984
+ const begin = base + (command3.type === "wait" ? 0 : (_nullishCoalesce(command3.delay, () => ( 0))) * f);
985
+ const targets = command3.type === "wait" ? [] : command3.targets;
986
+ const durations = command3.type === "wait" ? [command3.duration * f] : targets.map((id) => motionCommandDuration(command3, scene, id) * f);
987
+ const stagger = command3.type === "wait" ? 0 : (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
983
988
  const end2 = durations.reduce((m, d, k) => Math.max(m, begin + k * stagger + d), begin);
984
- commands.push({ shot: shot.id, shotIndex: index, command: i, type: command2.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
989
+ commands.push({ shot: shot.id, shotIndex: index, command: i, type: command3.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
985
990
  prevStart = begin;
986
991
  runEnd = Math.max(runEnd, end2);
987
992
  });
@@ -1013,14 +1018,14 @@ function compileMotionScene(scene) {
1013
1018
  }
1014
1019
  for (const timing of commands) {
1015
1020
  const shot = scene.shots[timing.shotIndex];
1016
- const command2 = shot.run[timing.command];
1017
- if (command2.type === "wait") continue;
1018
- if (command2.type === "play") {
1021
+ const command3 = shot.run[timing.command];
1022
+ if (command3.type === "wait") continue;
1023
+ if (command3.type === "play") {
1019
1024
  const f = motionShotTimeScale(shot);
1020
- command2.targets.forEach((target, k) => {
1025
+ command3.targets.forEach((target, k) => {
1021
1026
  if (!nodes.has(target)) return;
1022
- const at = timing.start + k * (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
1023
- for (const item of motionClipLayout(scene, command2.clip, target, (_nullishCoalesce(command2.speed, () => ( 1))) / f).items) {
1027
+ const at = timing.start + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
1028
+ for (const item of motionClipLayout(scene, command3.clip, target, (_nullishCoalesce(command3.speed, () => ( 1))) / f).items) {
1024
1029
  const entry = nodes.get(item.target);
1025
1030
  if (!entry) continue;
1026
1031
  jobs.push({ start: at + item.start, order: order++, run: () => compileRepeated(item.command, item.target, entry, at + item.start, item.cycle, timing) });
@@ -1028,24 +1033,24 @@ function compileMotionScene(scene) {
1028
1033
  });
1029
1034
  continue;
1030
1035
  }
1031
- command2.targets.forEach((target, k) => {
1036
+ command3.targets.forEach((target, k) => {
1032
1037
  const entry = nodes.get(target);
1033
1038
  if (!entry) return;
1034
1039
  const f = motionShotTimeScale(shot);
1035
- const start = timing.start + k * (_nullishCoalesce(command2.stagger, () => ( 0))) * f;
1036
- const cycle = motionCycleDuration(command2, scene, target) * f;
1037
- jobs.push({ start, order: order++, run: () => compileRepeated(command2, target, entry, start, cycle, timing) });
1040
+ const start = timing.start + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
1041
+ const cycle = motionCycleDuration(command3, scene, target) * f;
1042
+ jobs.push({ start, order: order++, run: () => compileRepeated(command3, target, entry, start, cycle, timing) });
1038
1043
  });
1039
1044
  }
1040
1045
  jobs.sort((a, b) => a.start - b.start || a.order - b.order).forEach((job) => job.run());
1041
- function compileRepeated(command2, node, entry, start, cycle, timing) {
1046
+ function compileRepeated(command3, node, entry, start, cycle, timing) {
1042
1047
  const first = segments.length;
1043
- compileCommand(command2, node, entry, start, cycle, timing);
1048
+ compileCommand(command3, node, entry, start, cycle, timing);
1044
1049
  const made = segments.slice(first);
1045
- const steps = _nullishCoalesce(command2.steps, () => ( scene.steps));
1050
+ const steps = _nullishCoalesce(command3.steps, () => ( scene.steps));
1046
1051
  if (steps && steps > 0) for (const s of made) s.steps = steps;
1047
- const n = motionCommandRepeat(command2);
1048
- const mode = _nullishCoalesce(command2.repeatMode, () => ( "loop"));
1052
+ const n = motionCommandRepeat(command3);
1053
+ const mode = _nullishCoalesce(command3.repeatMode, () => ( "loop"));
1049
1054
  const shift = (v, by, k) => {
1050
1055
  if (typeof v === "number" && typeof by === "number") return v + by * k;
1051
1056
  if (Array.isArray(v) && Array.isArray(by) && v.length === by.length) return v.map((x, i) => x + by[i] * k);
@@ -1064,16 +1069,16 @@ function compileMotionScene(scene) {
1064
1069
  }
1065
1070
  }
1066
1071
  }
1067
- function compileCommand(command2, node, entry, start, duration2, timing) {
1072
+ function compileCommand(command3, node, entry, start, duration2, timing) {
1068
1073
  const end = start + duration2;
1069
1074
  const where = { shot: timing.shot, command: timing.command };
1070
1075
  const seg = (property, to, ease2, s = start, e = end, extra = {}) => push({ node, property, start: s, end: e, from: _nullishCoalesce(extra.from, () => ( valueAt(node, property, s))), to, ease: ease2, ...where, ...extra });
1071
1076
  const rest = (p) => motionRestValue(entry, p, artwork);
1072
- const num = (p, time = start) => {
1077
+ const num2 = (p, time = start) => {
1073
1078
  const v = valueAt(node, p, time);
1074
1079
  return typeof v === "number" ? v : 0;
1075
1080
  };
1076
- const ease = command2.ease;
1081
+ const ease = command3.ease;
1077
1082
  const drawWindows = (s, e, o) => {
1078
1083
  const order2 = _nullishCoalesce(o.order, () => ( "together"));
1079
1084
  const pace = _nullishCoalesce(o.pace, () => ( "time"));
@@ -1111,11 +1116,11 @@ function compileMotionScene(scene) {
1111
1116
  return o.align === "end" ? { id: p.id, start: e - d, end: e } : { id: p.id, start: s, end: s + d };
1112
1117
  });
1113
1118
  };
1114
- switch (command2.type) {
1119
+ switch (command3.type) {
1115
1120
  case "enter": {
1116
- const style = _nullishCoalesce(command2.style, () => ( "fade"));
1121
+ const style = _nullishCoalesce(command3.style, () => ( "fade"));
1117
1122
  const opacity = rest("opacity");
1118
- const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction: command2.direction }) : style === "iris" ? motionRevealClip(entry, { style, shape: command2.shape }) : style === "split" ? motionRevealClip(entry, { style, orientation: command2.orientation }) : null;
1123
+ const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction: command3.direction }) : style === "iris" ? motionRevealClip(entry, { style, shape: command3.shape }) : style === "split" ? motionRevealClip(entry, { style, orientation: command3.orientation }) : null;
1119
1124
  for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _35 => _35.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
1120
1125
  if (reveal) {
1121
1126
  seg("opacity", opacity, "linear", start, start);
@@ -1123,30 +1128,30 @@ function compileMotionScene(scene) {
1123
1128
  break;
1124
1129
  }
1125
1130
  if (style === "draw") {
1126
- const windows = drawWindows(start, start + duration2 * 0.75, command2);
1131
+ const windows = drawWindows(start, start + duration2 * 0.75, command3);
1127
1132
  if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1, ease: _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), ...where });
1128
1133
  else seg("drawEnd", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, start + duration2 * 0.75, { from: 0 });
1129
1134
  seg("fillOpacity", 1, MOTION_EASE_OUT, start + duration2 * 0.6, end, { from: 0 });
1130
1135
  break;
1131
1136
  }
1132
1137
  if (style === "pop" || style === "zoom") {
1133
- const from = _nullishCoalesce(command2.scale, () => ( (style === "pop" ? 0.5 : 1.6)));
1138
+ const from = _nullishCoalesce(command3.scale, () => ( (style === "pop" ? 0.5 : 1.6)));
1134
1139
  seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * (style === "pop" ? 0.4 : 0.5), { from: 0 });
1135
1140
  seg("scaleX", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
1136
1141
  seg("scaleY", 1, _nullishCoalesce(ease, () => ( (style === "pop" ? "ease-out-back" : MOTION_EASE_OUT))), start, end, { from });
1137
1142
  } else if (style === "rise") {
1138
- const y = num("y");
1143
+ const y = num2("y");
1139
1144
  seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.5, { from: 0 });
1140
- seg("y", y, _nullishCoalesce(ease, () => ( "ease-out-back")), start, end, { from: y + (_nullishCoalesce(command2.distance, () => ( 20))) });
1145
+ seg("y", y, _nullishCoalesce(ease, () => ( "ease-out-back")), start, end, { from: y + (_nullishCoalesce(command3.distance, () => ( 20))) });
1141
1146
  } else if (style === "grow") {
1142
1147
  seg("opacity", opacity, MOTION_EASE_OUT, start, start + duration2 * 0.3, { from: 0 });
1143
1148
  seg("scaleX", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: 0 });
1144
1149
  seg("scaleY", 1, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: 0 });
1145
1150
  } else if (style === "slide") {
1146
- const dir = DIRECTION[_nullishCoalesce(command2.direction, () => ( "up"))];
1147
- const distance = _nullishCoalesce(command2.distance, () => ( 40));
1148
- const x = num("x");
1149
- const y = num("y");
1151
+ const dir = DIRECTION[_nullishCoalesce(command3.direction, () => ( "up"))];
1152
+ const distance = _nullishCoalesce(command3.distance, () => ( 40));
1153
+ const x = num2("x");
1154
+ const y = num2("y");
1150
1155
  seg("opacity", opacity, MOTION_EASE_OUT, start, end, { from: 0 });
1151
1156
  seg("x", x, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: x - dir.x * distance });
1152
1157
  seg("y", y, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: y - dir.y * distance });
@@ -1154,12 +1159,12 @@ function compileMotionScene(scene) {
1154
1159
  break;
1155
1160
  }
1156
1161
  case "exit": {
1157
- const style = _nullishCoalesce(command2.style, () => ( "fade"));
1158
- const wipe = style === "wipe" ? motionRevealClip(entry, { style, direction: command2.direction, hide: true }) : null;
1162
+ const style = _nullishCoalesce(command3.style, () => ( "fade"));
1163
+ const wipe = style === "wipe" ? motionRevealClip(entry, { style, direction: command3.direction, hide: true }) : null;
1159
1164
  if (wipe) seg(wipe.property, wipe.to, _nullishCoalesce(ease, () => ( "ease-in")), start, end, { from: wipe.from });
1160
1165
  else if (style === "undraw") {
1161
1166
  seg("fillOpacity", 0, "ease-in", start, start + duration2 * 0.4);
1162
- const windows = drawWindows(start, end, command2);
1167
+ const windows = drawWindows(start, end, command3);
1163
1168
  if (windows) for (const w of windows) push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: valueAt(w.id, "drawEnd", w.start), to: 0, ease: _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), ...where });
1164
1169
  else seg("drawEnd", 0, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1165
1170
  } else if (style === "shrink") {
@@ -1167,18 +1172,18 @@ function compileMotionScene(scene) {
1167
1172
  seg("scaleY", 0, _nullishCoalesce(ease, () => ( "ease-in")));
1168
1173
  seg("opacity", 0, "ease-in", start + duration2 * 0.6, end);
1169
1174
  } else if (style === "slide") {
1170
- const dir = DIRECTION[_nullishCoalesce(command2.direction, () => ( "down"))];
1171
- const distance = _nullishCoalesce(command2.distance, () => ( 40));
1172
- seg("x", num("x") + dir.x * distance, _nullishCoalesce(ease, () => ( "ease-in")));
1173
- seg("y", num("y") + dir.y * distance, _nullishCoalesce(ease, () => ( "ease-in")));
1175
+ const dir = DIRECTION[_nullishCoalesce(command3.direction, () => ( "down"))];
1176
+ const distance = _nullishCoalesce(command3.distance, () => ( 40));
1177
+ seg("x", num2("x") + dir.x * distance, _nullishCoalesce(ease, () => ( "ease-in")));
1178
+ seg("y", num2("y") + dir.y * distance, _nullishCoalesce(ease, () => ( "ease-in")));
1174
1179
  seg("opacity", 0, _nullishCoalesce(ease, () => ( "ease-in")));
1175
1180
  } else seg("opacity", 0, _nullishCoalesce(ease, () => ( "ease-in")));
1176
1181
  break;
1177
1182
  }
1178
1183
  case "draw": {
1179
1184
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
1180
- const comet = command2.comet !== void 0 ? Math.min(1, Math.max(0, command2.comet)) : void 0;
1181
- const windows = _nullishCoalesce(drawWindows(start, end, command2), () => ( [{ id: node, start, end }]));
1185
+ const comet = command3.comet !== void 0 ? Math.min(1, Math.max(0, command3.comet)) : void 0;
1186
+ const windows = _nullishCoalesce(drawWindows(start, end, command3), () => ( [{ id: node, start, end }]));
1182
1187
  for (const w of windows) {
1183
1188
  if (comet !== void 0) {
1184
1189
  push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: 0, to: 1 + comet, ease: e, ...where });
@@ -1186,27 +1191,27 @@ function compileMotionScene(scene) {
1186
1191
  continue;
1187
1192
  }
1188
1193
  const drawn = tracks.has(motionTrackKey(w.id, "drawEnd"));
1189
- push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: _nullishCoalesce(command2.from, () => ( (drawn ? valueAt(w.id, "drawEnd", w.start) : 0))), to: _nullishCoalesce(command2.to, () => ( 1)), ease: e, ...where });
1194
+ push({ node: w.id, property: "drawEnd", start: w.start, end: w.end, from: _nullishCoalesce(command3.from, () => ( (drawn ? valueAt(w.id, "drawEnd", w.start) : 0))), to: _nullishCoalesce(command3.to, () => ( 1)), ease: e, ...where });
1190
1195
  }
1191
1196
  break;
1192
1197
  }
1193
1198
  case "move": {
1194
1199
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
1195
- let dx = _nullishCoalesce(_optionalChain([command2, 'access', _36 => _36.by, 'optionalAccess', _37 => _37.x]), () => ( 0));
1196
- let dy = _nullishCoalesce(_optionalChain([command2, 'access', _38 => _38.by, 'optionalAccess', _39 => _39.y]), () => ( 0));
1197
- if (command2.to) {
1200
+ let dx = _nullishCoalesce(_optionalChain([command3, 'access', _36 => _36.by, 'optionalAccess', _37 => _37.x]), () => ( 0));
1201
+ let dy = _nullishCoalesce(_optionalChain([command3, 'access', _38 => _38.by, 'optionalAccess', _39 => _39.y]), () => ( 0));
1202
+ if (command3.to) {
1198
1203
  const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1199
- const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
1200
- dx = target.x - (entry.center.x + num("x"));
1201
- dy = target.y - (entry.center.y + num("y"));
1204
+ const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command3.to);
1205
+ dx = target.x - (entry.center.x + num2("x"));
1206
+ dy = target.y - (entry.center.y + num2("y"));
1202
1207
  }
1203
- if (_optionalChain([command2, 'access', _40 => _40.via, 'optionalAccess', _41 => _41.length])) {
1208
+ if (_optionalChain([command3, 'access', _40 => _40.via, 'optionalAccess', _41 => _41.length])) {
1204
1209
  const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1205
- const x0 = num("x");
1206
- const y0 = num("y");
1207
- const add = command2.blend === "add";
1208
- const offsets = [{ x: 0, y: 0 }, ...command2.via.map((p) => _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, p)).map((p) => ({ x: p.x - entry.center.x - x0, y: p.y - entry.center.y - y0 })), { x: dx, y: dy }];
1209
- const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command2.pacing, () => ( "even")));
1210
+ const x0 = num2("x");
1211
+ const y0 = num2("y");
1212
+ const add = command3.blend === "add";
1213
+ const offsets = [{ x: 0, y: 0 }, ...command3.via.map((p) => _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, p)).map((p) => ({ x: p.x - entry.center.x - x0, y: p.y - entry.center.y - y0 })), { x: dx, y: dy }];
1214
+ const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
1210
1215
  for (const axis of ["x", "y"]) {
1211
1216
  const base = add ? 0 : axis === "x" ? x0 : y0;
1212
1217
  for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
@@ -1214,42 +1219,42 @@ function compileMotionScene(scene) {
1214
1219
  }
1215
1220
  break;
1216
1221
  }
1217
- if (command2.blend === "add") {
1222
+ if (command3.blend === "add") {
1218
1223
  seg("x", dx, e, start, end, { from: 0, blend: "add" });
1219
1224
  seg("y", dy, e, start, end, { from: 0, blend: "add" });
1220
1225
  } else {
1221
- seg("x", num("x") + dx, e);
1222
- seg("y", num("y") + dy, e);
1226
+ seg("x", num2("x") + dx, e);
1227
+ seg("y", num2("y") + dy, e);
1223
1228
  }
1224
1229
  break;
1225
1230
  }
1226
1231
  case "rotate": {
1227
1232
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
1228
- if (command2.blend === "add") seg("rotation", command2.to !== void 0 ? command2.to - num("rotation") : _nullishCoalesce(command2.by, () => ( 0)), e, start, end, { from: 0, blend: "add" });
1229
- else seg("rotation", _nullishCoalesce(command2.to, () => ( num("rotation") + (_nullishCoalesce(command2.by, () => ( 0))))), e);
1233
+ if (command3.blend === "add") seg("rotation", command3.to !== void 0 ? command3.to - num2("rotation") : _nullishCoalesce(command3.by, () => ( 0)), e, start, end, { from: 0, blend: "add" });
1234
+ else seg("rotation", _nullishCoalesce(command3.to, () => ( num2("rotation") + (_nullishCoalesce(command3.by, () => ( 0))))), e);
1230
1235
  break;
1231
1236
  }
1232
1237
  case "scale": {
1233
- const to = typeof command2.to === "number" ? { x: command2.to, y: command2.to } : command2.to;
1234
- const extra = { ...command2.geometric ? { geometric: true } : {}, ...command2.blend === "add" ? { from: 1, blend: "add" } : {} };
1238
+ const to = typeof command3.to === "number" ? { x: command3.to, y: command3.to } : command3.to;
1239
+ const extra = { ...command3.geometric ? { geometric: true } : {}, ...command3.blend === "add" ? { from: 1, blend: "add" } : {} };
1235
1240
  seg("scaleX", to.x, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
1236
1241
  seg("scaleY", to.y, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, extra);
1237
1242
  break;
1238
1243
  }
1239
1244
  case "fade":
1240
- seg("opacity", command2.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1245
+ seg("opacity", command3.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1241
1246
  break;
1242
1247
  case "style":
1243
- if (command2.fill !== void 0) seg("fill", command2.fill, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1244
- if (command2.stroke !== void 0) seg("stroke", command2.stroke, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1245
- if (command2.strokeWidth !== void 0) seg("strokeWidth", command2.strokeWidth, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1248
+ if (command3.fill !== void 0) seg("fill", command3.fill, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1249
+ if (command3.stroke !== void 0) seg("stroke", command3.stroke, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1250
+ if (command3.strokeWidth !== void 0) seg("strokeWidth", command3.strokeWidth, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1246
1251
  break;
1247
1252
  case "morph":
1248
- seg("shape", command2.into, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1253
+ seg("shape", command3.into, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1249
1254
  break;
1250
1255
  case "match": {
1251
- const into = nodes.get(command2.into);
1252
- if (!into || command2.into === node) break;
1256
+ const into = nodes.get(command3.into);
1257
+ if (!into || command3.into === node) break;
1253
1258
  const match = matchMotionNodes(entry.node, into.node);
1254
1259
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
1255
1260
  for (const [a, b] of match.pairs) push({ node: a, property: "shape", start, end, from: valueAt(a, "shape", start), to: b, ease: e, ...where });
@@ -1257,7 +1262,7 @@ function compileMotionScene(scene) {
1257
1262
  break;
1258
1263
  }
1259
1264
  case "follow":
1260
- seg("follow", _nullishCoalesce(command2.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, { from: _nullishCoalesce(command2.from, () => ( 0)), path: command2.path, rotate: _nullishCoalesce(command2.rotate, () => ( false)) });
1265
+ seg("follow", _nullishCoalesce(command3.to, () => ( 1)), _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)), start, end, { from: _nullishCoalesce(command3.from, () => ( 0)), path: command3.path, rotate: _nullishCoalesce(command3.rotate, () => ( false)) });
1261
1266
  break;
1262
1267
  // Emphasis: a change toward a peak that a behaviour swings round (as Flair's primitives do).
1263
1268
  case "pulse":
@@ -1265,33 +1270,33 @@ function compileMotionScene(scene) {
1265
1270
  case "teeter":
1266
1271
  case "wave":
1267
1272
  case "wiggle": {
1268
- const add = (_nullishCoalesce(command2.blend, () => ( "add"))) === "add";
1273
+ const add = (_nullishCoalesce(command3.blend, () => ( "add"))) === "add";
1269
1274
  const swing = (p, by, extra) => {
1270
1275
  const scale = p === "scaleX" || p === "scaleY";
1271
1276
  if (add) seg(p, by, _nullishCoalesce(ease, () => ( "linear")), start, end, { from: scale ? 1 : 0, blend: "add", ...extra });
1272
- else seg(p, scale ? num(p) * by : num(p) + by, _nullishCoalesce(ease, () => ( "linear")), start, end, extra);
1277
+ else seg(p, scale ? num2(p) * by : num2(p) + by, _nullishCoalesce(ease, () => ( "linear")), start, end, extra);
1273
1278
  };
1274
- if (command2.type === "pulse") {
1275
- const behavior = { type: "pulse", count: _nullishCoalesce(command2.count, () => ( 1)) };
1276
- swing("scaleX", 1 + (_nullishCoalesce(command2.amount, () => ( 0.15))), { behavior });
1277
- swing("scaleY", 1 + (_nullishCoalesce(command2.amount, () => ( 0.15))), { behavior });
1278
- } else if (command2.type === "shake") swing(command2.axis === "vertical" ? "y" : "x", _nullishCoalesce(command2.amount, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
1279
- else if (command2.type === "teeter") swing("rotation", _nullishCoalesce(command2.angle, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 3)), decay: 1 } });
1280
- else if (command2.type === "wave") swing("y", -(_nullishCoalesce(command2.amount, () => ( 6))), { behavior: { type: "oscillate", count: _nullishCoalesce(command2.count, () => ( 2)) } });
1279
+ if (command3.type === "pulse") {
1280
+ const behavior = { type: "pulse", count: _nullishCoalesce(command3.count, () => ( 1)) };
1281
+ swing("scaleX", 1 + (_nullishCoalesce(command3.amount, () => ( 0.15))), { behavior });
1282
+ swing("scaleY", 1 + (_nullishCoalesce(command3.amount, () => ( 0.15))), { behavior });
1283
+ } else if (command3.type === "shake") swing(command3.axis === "vertical" ? "y" : "x", _nullishCoalesce(command3.amount, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 3)), decay: 1 } });
1284
+ else if (command3.type === "teeter") swing("rotation", _nullishCoalesce(command3.angle, () => ( 8)), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 3)), decay: 1 } });
1285
+ else if (command3.type === "wave") swing("y", -(_nullishCoalesce(command3.amount, () => ( 6))), { behavior: { type: "oscillate", count: _nullishCoalesce(command3.count, () => ( 2)) } });
1281
1286
  else {
1282
- const behavior = { type: "wriggle", frequency: _nullishCoalesce(command2.frequency, () => ( 3)), octaves: _nullishCoalesce(command2.octaves, () => ( 2)), seed: command2.seed || _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, node) };
1283
- const amount = _nullishCoalesce(command2.amount, () => ( 6));
1287
+ const behavior = { type: "wriggle", frequency: _nullishCoalesce(command3.frequency, () => ( 3)), octaves: _nullishCoalesce(command3.octaves, () => ( 2)), seed: command3.seed || _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, node) };
1288
+ const amount = _nullishCoalesce(command3.amount, () => ( 6));
1284
1289
  swing("x", amount, { behavior, index: 0 });
1285
1290
  swing("y", amount, { behavior, index: 1 });
1286
- if (command2.rotate) swing("rotation", command2.rotate, { behavior, index: 2 });
1291
+ if (command3.rotate) swing("rotation", command3.rotate, { behavior, index: 2 });
1287
1292
  }
1288
1293
  break;
1289
1294
  }
1290
1295
  case "color-pulse":
1291
- seg(_nullishCoalesce(command2.paint, () => ( "fill")), _nullishCoalesce(command2.color, () => ( "#f59e0b")), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "pulse", count: _nullishCoalesce(command2.count, () => ( 1)) } });
1296
+ seg(_nullishCoalesce(command3.paint, () => ( "fill")), _nullishCoalesce(command3.color, () => ( "#f59e0b")), _nullishCoalesce(ease, () => ( "linear")), start, end, { behavior: { type: "pulse", count: _nullishCoalesce(command3.count, () => ( 1)) } });
1292
1297
  break;
1293
1298
  case "effect":
1294
- seg(`effect:${command2.effect}:${command2.param}`, command2.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1299
+ seg(`effect:${command3.effect}:${command3.param}`, command3.to, _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT)));
1295
1300
  break;
1296
1301
  }
1297
1302
  }
@@ -1682,24 +1687,24 @@ function usesColor(scene, color) {
1682
1687
  return found;
1683
1688
  }
1684
1689
  function visibleAt(timeline, id, time, node) {
1685
- const num = (p, rest) => {
1690
+ const num2 = (p, rest) => {
1686
1691
  const v = trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
1687
1692
  return typeof v === "number" ? v : rest;
1688
1693
  };
1689
1694
  if (node.visible === false) return false;
1690
- if (num("opacity", _nullishCoalesce(node.opacity, () => ( 1))) <= 0.01) return false;
1691
- if (Math.abs(num("scaleX", 1) * num("scaleY", 1)) <= 1e-4) return false;
1695
+ if (num2("opacity", _nullishCoalesce(node.opacity, () => ( 1))) <= 0.01) return false;
1696
+ if (Math.abs(num2("scaleX", 1) * num2("scaleY", 1)) <= 1e-4) return false;
1692
1697
  const clip = (p) => trackValue(timeline.tracks.get(motionTrackKey(id, p)), time);
1693
1698
  const rect = clip("clipRect");
1694
1699
  if (Array.isArray(rect) && (rect[2] <= 1e-4 || rect[3] <= 1e-4)) return false;
1695
1700
  const circle = clip("clipCircle");
1696
1701
  if (Array.isArray(circle) && circle[2] <= 1e-4) return false;
1697
1702
  const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
1698
- const drawn = num("drawEnd", 1) > 0.01 && (node.type === "path" || _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).length === 0 || _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).some((p) => {
1703
+ const drawn = num2("drawEnd", 1) > 0.01 && (node.type === "path" || _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).length === 0 || _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).some((p) => {
1699
1704
  const v = trackValue(timeline.tracks.get(motionTrackKey(p.id, "drawEnd")), time);
1700
1705
  return typeof v !== "number" || v > 0.01;
1701
1706
  }));
1702
- return drawn || hasFill && num("fillOpacity", 1) > 0.01;
1707
+ return drawn || hasFill && num2("fillOpacity", 1) > 0.01;
1703
1708
  }
1704
1709
  function checkMotionScene(scene) {
1705
1710
  const issues = [];
@@ -1727,48 +1732,48 @@ function checkMotionScene(scene) {
1727
1732
  issues.push(motionIssue("camera-aspect", `The camera is ${c.width} \xD7 ${c.height}, a different shape from the ${scene.artwork.width} \xD7 ${scene.artwork.height} artwork, so it shows bands at the sides; frame a node instead to match.`, { shot: shot.id }));
1728
1733
  }
1729
1734
  if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(motionIssue("empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
1730
- shot.run.forEach((command2, i) => {
1735
+ shot.run.forEach((command3, i) => {
1731
1736
  const where = { shot: shot.id, command: i };
1732
- if (command2.type === "wait") return;
1733
- const targets = command2.targets.filter((id) => known(id, "unknown-target", "node", where));
1737
+ if (command3.type === "wait") return;
1738
+ const targets = command3.targets.filter((id) => known(id, "unknown-target", "node", where));
1734
1739
  const timing = timeline.commands.find((c) => c.shot === shot.id && c.command === i);
1735
1740
  if (timing && timing.duration > 0 && timing.duration < MOTION_MIN_CHANGE_MS)
1736
- issues.push(motionIssue("too-fast", `This ${command2.type} lasts ${timing.duration} ms, too quick to follow; make it at least ${MOTION_MIN_CHANGE_MS} ms.`, { ...where, measured: timing.duration, needed: MOTION_MIN_CHANGE_MS, unit: "ms", ids: targets }));
1737
- if (command2.duration !== void 0 && command2.ease !== void 0) {
1738
- const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command2.ease);
1741
+ issues.push(motionIssue("too-fast", `This ${command3.type} lasts ${timing.duration} ms, too quick to follow; make it at least ${MOTION_MIN_CHANGE_MS} ms.`, { ...where, measured: timing.duration, needed: MOTION_MIN_CHANGE_MS, unit: "ms", ids: targets }));
1742
+ if (command3.duration !== void 0 && command3.ease !== void 0) {
1743
+ const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command3.ease);
1739
1744
  if (ease !== "hold" && ease.type === "spring") {
1740
1745
  const settle = _chunk2FHLHZALcjs.springSettleMs.call(void 0, ease);
1741
- if (command2.duration < settle * 0.9)
1742
- issues.push(motionIssue("spring-cut-short", `This ${command2.type}'s spring takes ${settle} ms to settle but lasts ${command2.duration} ms, so it jumps to its end; leave "duration" out (the spring sets it) or make it at least ${settle} ms.`, { ...where, measured: command2.duration, needed: settle, unit: "ms", ids: targets }));
1746
+ if (command3.duration < settle * 0.9)
1747
+ issues.push(motionIssue("spring-cut-short", `This ${command3.type}'s spring takes ${settle} ms to settle but lasts ${command3.duration} ms, so it jumps to its end; leave "duration" out (the spring sets it) or make it at least ${settle} ms.`, { ...where, measured: command3.duration, needed: settle, unit: "ms", ids: targets }));
1743
1748
  }
1744
1749
  }
1745
- if (command2.type === "follow" && known(command2.path, "unknown-path", "path", where) && nodes.get(command2.path).node.type !== "path")
1746
- issues.push(motionIssue("not-a-path", `"${command2.path}" is a group; follow a single path node.`, { ...where, ids: [command2.path] }));
1747
- if (command2.type === "morph") known(command2.into, "unknown-shape", "shape", where);
1748
- if (command2.type === "play" && !_optionalChain([scene, 'access', _79 => _79.clips, 'optionalAccess', _80 => _80[command2.clip]]))
1749
- issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command2.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
1750
- if (command2.type === "match" && known(command2.into, "unknown-shape", "group", where)) {
1751
- const into = nodes.get(command2.into);
1750
+ if (command3.type === "follow" && known(command3.path, "unknown-path", "path", where) && nodes.get(command3.path).node.type !== "path")
1751
+ issues.push(motionIssue("not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
1752
+ if (command3.type === "morph") known(command3.into, "unknown-shape", "shape", where);
1753
+ if (command3.type === "play" && !_optionalChain([scene, 'access', _79 => _79.clips, 'optionalAccess', _80 => _80[command3.clip]]))
1754
+ issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
1755
+ if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
1756
+ const into = nodes.get(command3.into);
1752
1757
  for (const id of targets) {
1753
1758
  const entry = nodes.get(id);
1754
- if (id === command2.into || into.ancestors.includes(id) || entry.ancestors.includes(command2.into)) {
1755
- issues.push(motionIssue("match-self", `"${id}" cannot match "${command2.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command2.into] }));
1759
+ if (id === command3.into || into.ancestors.includes(id) || entry.ancestors.includes(command3.into)) {
1760
+ issues.push(motionIssue("match-self", `"${id}" cannot match "${command3.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command3.into] }));
1756
1761
  continue;
1757
1762
  }
1758
1763
  const m = matchMotionNodes(entry.node, into.node);
1759
1764
  if (m.unpairedInto.length)
1760
- issues.push(motionIssue("match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command2.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
1765
+ issues.push(motionIssue("match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command3.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
1761
1766
  }
1762
1767
  }
1763
- const style = command2.type === "enter" || command2.type === "exit" ? command2.style : void 0;
1768
+ const style = command3.type === "enter" || command3.type === "exit" ? command3.style : void 0;
1764
1769
  if (style === "wipe" || style === "iris" || style === "split") {
1765
1770
  for (const id of targets)
1766
1771
  if (!motionRevealPadding(nodes.get(id)))
1767
- issues.push(motionIssue("reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command2.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
1772
+ issues.push(motionIssue("reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command3.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
1768
1773
  }
1769
- if (command2.type === "style") {
1774
+ if (command3.type === "style") {
1770
1775
  for (const key of ["fill", "stroke"]) {
1771
- const color = command2[key];
1776
+ const color = command3[key];
1772
1777
  if (color === void 0) continue;
1773
1778
  if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) {
1774
1779
  issues.push(motionIssue("invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
@@ -1782,9 +1787,9 @@ function checkMotionScene(scene) {
1782
1787
  }
1783
1788
  }
1784
1789
  }
1785
- if (command2.type === "color-pulse") {
1786
- const key = _nullishCoalesce(command2.paint, () => ( "fill"));
1787
- const color = _nullishCoalesce(command2.color, () => ( "#f59e0b"));
1790
+ if (command3.type === "color-pulse") {
1791
+ const key = _nullishCoalesce(command3.paint, () => ( "fill"));
1792
+ const color = _nullishCoalesce(command3.color, () => ( "#f59e0b"));
1788
1793
  if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(motionIssue("invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1789
1794
  else
1790
1795
  for (const id of targets) {
@@ -1794,15 +1799,15 @@ function checkMotionScene(scene) {
1794
1799
  issues.push(motionIssue("paint-not-color", `"${id}" has a gradient or no ${key}, so a colour pulse cannot tint it; give it a solid ${key} or pulse the ${key === "fill" ? "stroke" : "fill"}.`, { ...where, ids: [id] }));
1795
1800
  }
1796
1801
  }
1797
- if (command2.type === "effect") {
1802
+ if (command3.type === "effect") {
1798
1803
  for (const id of targets) {
1799
1804
  const node = nodes.get(id).node;
1800
- const params = NUMERIC_PARAMS(node, command2.effect);
1805
+ const params = NUMERIC_PARAMS(node, command3.effect);
1801
1806
  const effects = (_nullishCoalesce(node.effects, () => ( []))).map((e) => e.id);
1802
1807
  if (!params)
1803
- issues.push(motionIssue("unknown-effect", `"${id}" has no effect ${namedWithSuggestion(command2.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
1804
- else if (!params.includes(command2.param))
1805
- issues.push(motionIssue("unknown-effect-param", `Effect "${command2.effect}" has no numeric parameter ${namedWithSuggestion(command2.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
1808
+ issues.push(motionIssue("unknown-effect", `"${id}" has no effect ${namedWithSuggestion(command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
1809
+ else if (!params.includes(command3.param))
1810
+ issues.push(motionIssue("unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${namedWithSuggestion(command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
1806
1811
  }
1807
1812
  }
1808
1813
  if (timing) {
@@ -1810,11 +1815,11 @@ function checkMotionScene(scene) {
1810
1815
  const node = nodes.get(id).node;
1811
1816
  const before = Math.max(0, timing.start - 0.5);
1812
1817
  const visible = timing.start > 0 ? visibleAt(timeline, id, before, node) : node.visible !== false;
1813
- if (command2.type === "enter" && visible && timing.start > 0)
1818
+ if (command3.type === "enter" && visible && timing.start > 0)
1814
1819
  issues.push(motionIssue("enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
1815
- const probe = command2.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
1816
- if (command2.type !== "enter" && command2.type !== "draw" && !visibleAt(timeline, id, probe, node))
1817
- issues.push(motionIssue("exit-hidden", `"${id}" is hidden when this ${command2.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
1820
+ const probe = command3.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
1821
+ if (command3.type !== "enter" && command3.type !== "draw" && !visibleAt(timeline, id, probe, node))
1822
+ issues.push(motionIssue("exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
1818
1823
  }
1819
1824
  }
1820
1825
  });
@@ -1842,9 +1847,9 @@ function checkMotionScene(scene) {
1842
1847
  if (loop.length) issues.push(motionIssue("driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
1843
1848
  }
1844
1849
  for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
1845
- for (const command2 of clip.run)
1846
- if (command2.type !== "wait") {
1847
- for (const id of command2.targets)
1850
+ for (const command3 of clip.run)
1851
+ if (command3.type !== "wait") {
1852
+ for (const id of command3.targets)
1848
1853
  if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(motionIssue("unknown-target", `Clip "${name}" names ${namedWithSuggestion(id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
1849
1854
  }
1850
1855
  if (scene.trigger) {
@@ -1887,18 +1892,18 @@ function checkMotionScene(scene) {
1887
1892
  }
1888
1893
  const reported = /* @__PURE__ */ new Set();
1889
1894
  for (const timing of timeline.commands) {
1890
- const command2 = scene.shots[timing.shotIndex].run[timing.command];
1891
- if (command2.type === "wait" || command2.type === "exit") continue;
1895
+ const command3 = scene.shots[timing.shotIndex].run[timing.command];
1896
+ if (command3.type === "wait" || command3.type === "exit") continue;
1892
1897
  const frame = motionFrameAt(scene, timing.end);
1893
1898
  const cam = frame.camera;
1894
1899
  const docIndex = indexMotionNodes(frame.document.nodes);
1895
- for (const id of command2.targets) {
1900
+ for (const id of command3.targets) {
1896
1901
  const b = _optionalChain([docIndex, 'access', _84 => _84.get, 'call', _85 => _85(id), 'optionalAccess', _86 => _86.bounds]);
1897
1902
  if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
1898
1903
  const outside = b.x + b.width < cam.x || b.y + b.height < cam.y || b.x > cam.x + cam.width || b.y > cam.y + cam.height;
1899
1904
  if (outside) {
1900
1905
  reported.add(id);
1901
- issues.push(motionIssue("out-of-frame", `"${id}" is outside the camera when this ${command2.type} ends, so it is not seen; move it into frame or move the camera.`, { shot: timing.shot, command: timing.command, ids: [id] }));
1906
+ issues.push(motionIssue("out-of-frame", `"${id}" is outside the camera when this ${command3.type} ends, so it is not seen; move it into frame or move the camera.`, { shot: timing.shot, command: timing.command, ids: [id] }));
1902
1907
  }
1903
1908
  }
1904
1909
  }
@@ -2052,8 +2057,8 @@ function applyOne(scene, edit) {
2052
2057
  case "add_commands": {
2053
2058
  const i = shotIndex(scene, edit.shot);
2054
2059
  if (!edit.commands.length) fail("Give at least one command.");
2055
- edit.commands.forEach((command2, k) => {
2056
- const problems = commandShapeProblems(command2, `Command ${k + 1}`);
2060
+ edit.commands.forEach((command3, k) => {
2061
+ const problems = commandShapeProblems(command3, `Command ${k + 1}`);
2057
2062
  if (problems.length) fail(problems.join(" "));
2058
2063
  });
2059
2064
  const run = scene.shots[i].run;
@@ -2065,14 +2070,14 @@ function applyOne(scene, edit) {
2065
2070
  const run = scene.shots[i].run;
2066
2071
  if (!Number.isInteger(edit.command) || edit.command < 0 || edit.command >= run.length)
2067
2072
  fail(`Shot "${edit.shot}" has ${run.length} command${run.length === 1 ? "" : "s"}; "command" must be an index from 0 to ${run.length - 1} (got ${edit.command}).`);
2068
- const command2 = { ...run[edit.command], ..._nullishCoalesce(edit.set, () => ( {})) };
2073
+ const command3 = { ...run[edit.command], ..._nullishCoalesce(edit.set, () => ( {})) };
2069
2074
  for (const key of _nullishCoalesce(edit.remove, () => ( []))) {
2070
2075
  if (key === "type") fail('"type" cannot be removed; replace the command instead.');
2071
- delete command2[key];
2076
+ delete command3[key];
2072
2077
  }
2073
- const problems = commandShapeProblems(command2, `Command ${edit.command}`);
2078
+ const problems = commandShapeProblems(command3, `Command ${edit.command}`);
2074
2079
  if (problems.length) fail(problems.join(" "));
2075
- return replaceShot(scene, i, { ...scene.shots[i], run: run.map((c, k) => k === edit.command ? command2 : c) });
2080
+ return replaceShot(scene, i, { ...scene.shots[i], run: run.map((c, k) => k === edit.command ? command3 : c) });
2076
2081
  }
2077
2082
  case "delete_commands": {
2078
2083
  const i = shotIndex(scene, edit.shot);
@@ -2103,9 +2108,9 @@ function applyOne(scene, edit) {
2103
2108
  else delete next.presets;
2104
2109
  }
2105
2110
  const names = new Set(edit.controls.map((c) => c.name));
2106
- for (const preset of _nullishCoalesce(next.presets, () => ( [])))
2107
- for (const key of Object.keys(preset.values))
2108
- if (!names.has(key)) fail(`Preset "${preset.name}" sets ${namedWithSuggestion(key, names)}, which is not a control.`);
2111
+ for (const preset2 of _nullishCoalesce(next.presets, () => ( [])))
2112
+ for (const key of Object.keys(preset2.values))
2113
+ if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${namedWithSuggestion(key, names)}, which is not a control.`);
2109
2114
  return next;
2110
2115
  }
2111
2116
  case "replace_scene":
@@ -2272,7 +2277,7 @@ function toFlairSvgMotion(scene, options = {}) {
2272
2277
  const springs = flairAtLeast(flair, "0.39");
2273
2278
  const strobes = flairAtLeast(flair, "0.39");
2274
2279
  const writeEase = (ease) => typeof ease === "string" || "spring" in ease ? ease : ease.map(round2);
2275
- const easeOf = (segment) => {
2280
+ const easeOf2 = (segment) => {
2276
2281
  const resolved = _chunk2FHLHZALcjs.resolveEasing.call(void 0, segment.ease);
2277
2282
  if (resolved !== "hold" && resolved.type === "spring") {
2278
2283
  if (!springs || segment.reverse) return void 0;
@@ -2451,7 +2456,7 @@ function toFlairSvgMotion(scene, options = {}) {
2451
2456
  const first = active[0];
2452
2457
  const key = (x) => JSON.stringify([x.ease, x.behavior, _nullishCoalesce(x.reverse, () => ( false)), _nullishCoalesce(x.steps, () => ( 0))]);
2453
2458
  const together = active.every((x) => x.start === a && x.end === b && channel.exact(x) && key(x) === key(first));
2454
- const curve = together ? easeOf(first) : void 0;
2459
+ const curve = together ? easeOf2(first) : void 0;
2455
2460
  const ease = curve && (!overshoots(curve) || channel.overshoot) ? curve : void 0;
2456
2461
  if (ease) {
2457
2462
  const from = channel.value(a);
@@ -2478,7 +2483,7 @@ function toFlairSvgMotion(scene, options = {}) {
2478
2483
  for (const seg of follow.segments) {
2479
2484
  const along = { id: follow.wrapper, along: follow.routes.get(seg.path), ...seg.rotate ? { orient: true } : {} };
2480
2485
  const progress = (t) => round2(Math.min(1, Math.max(0, Number(segmentValue(seg, t)))));
2481
- const curve = seg.end > seg.start ? plays(seg) ? easeOf(seg) : void 0 : "linear";
2486
+ const curve = seg.end > seg.start ? plays(seg) ? easeOf2(seg) : void 0 : "linear";
2482
2487
  if (curve && !(overshoots(curve) && seg.rotate)) {
2483
2488
  const ends = seg.reverse ? [Number(seg.to), Number(seg.from)] : [Number(seg.from), Number(seg.to)];
2484
2489
  animate.push({ ...along, ...seg.start > 0 ? { delay: round2(seg.start) } : {}, ms: round2(seg.end - seg.start), ease: writeEase(curve), ...seg.steps ? { strobe: seg.steps } : {}, at: [round2(ends[0]), round2(ends[1])] });
@@ -2722,9 +2727,9 @@ function fromFlairSvgMotion(input, options = {}) {
2722
2727
  if (!anim.id) continue;
2723
2728
  const at = Math.max(0, (_nullishCoalesce(anim.delay, () => ( 0))) - cameraMs);
2724
2729
  if (cameraMs && (_nullishCoalesce(anim.delay, () => ( 0))) < cameraMs) notes.push(`Step ${step}: a change to "${anim.id}" during the camera move now starts after it.`);
2725
- for (const command2 of commandsFor(anim, nodes, entered, notes)) {
2730
+ for (const command3 of commandsFor(anim, nodes, entered, notes)) {
2726
2731
  const first = run.length === 0;
2727
- run.push({ ...command2, ...first ? {} : { with: "previous" }, ...at - last > 0 || first ? { delay: first ? at : at - last } : {} });
2732
+ run.push({ ...command3, ...first ? {} : { with: "previous" }, ...at - last > 0 || first ? { delay: first ? at : at - last } : {} });
2728
2733
  if (first && at === 0) delete run[run.length - 1].delay;
2729
2734
  last = at;
2730
2735
  }
@@ -2974,11 +2979,11 @@ function toLottie(scene, options = {}) {
2974
2979
  }
2975
2980
  const stroke = paintOf(path.stroke, "stroke", path.id);
2976
2981
  if (stroke || strokeFrom) {
2977
- const colour = strokeFrom ? track(strokeFrom, "stroke") : [];
2982
+ const colour2 = strokeFrom ? track(strokeFrom, "stroke") : [];
2978
2983
  items.push({
2979
2984
  ty: "st",
2980
2985
  nm: "Stroke",
2981
- c: colour.length ? animate(colour, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour, t)), () => ( stroke)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(stroke, () => ( [0, 0, 0, 1]))).map(round2) },
2986
+ c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( stroke)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(stroke, () => ( [0, 0, 0, 1]))).map(round2) },
2982
2987
  o: { a: 0, k: 100 },
2983
2988
  w: widthFrom ? animate(track(widthFrom, "strokeWidth"), (t) => [Math.max(0, Number(_nullishCoalesce(_nullishCoalesce(trackValue(track(widthFrom, "strokeWidth"), t), () => ( path.strokeWidth)), () => ( 1))))]) : { a: 0, k: round2(_nullishCoalesce(path.strokeWidth, () => ( 1))) },
2984
2989
  lc: path.strokeLinecap === "round" ? 2 : path.strokeLinecap === "square" ? 3 : 1,
@@ -2990,12 +2995,12 @@ function toLottie(scene, options = {}) {
2990
2995
  }
2991
2996
  const fill = paintOf(path.fill, "fill", path.id);
2992
2997
  if (fill || fillFrom) {
2993
- const colour = fillFrom ? track(fillFrom, "fill") : [];
2998
+ const colour2 = fillFrom ? track(fillFrom, "fill") : [];
2994
2999
  const fade = fadeFrom ? track(fadeFrom, "fillOpacity") : [];
2995
3000
  items.push({
2996
3001
  ty: "fl",
2997
3002
  nm: "Fill",
2998
- c: colour.length ? animate(colour, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour, t)), () => ( fill)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(fill, () => ( [0, 0, 0, 1]))).map(round2) },
3003
+ c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( fill)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(fill, () => ( [0, 0, 0, 1]))).map(round2) },
2999
3004
  o: fade.length ? animate(fade, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(fade, t), () => ( 1))))) * 100]) : { a: 0, k: 100 },
3000
3005
  r: path.fillRule === "evenodd" ? 2 : 1
3001
3006
  });
@@ -3069,6 +3074,383 @@ function toLottie(scene, options = {}) {
3069
3074
  return { lottie, sampled, notes: [...new Set(notes)] };
3070
3075
  }
3071
3076
 
3077
+ // src/animation-editor/pptx.ts
3078
+ var EMU = 9525;
3079
+ var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName === name) : [];
3080
+ var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
3081
+ var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
3082
+ var num = (el, attr, fallback = 0) => {
3083
+ const v = _optionalChain([el, 'optionalAccess', _122 => _122.getAttribute, 'call', _123 => _123(attr)]);
3084
+ const n = v === null || v === void 0 ? NaN : Number(v);
3085
+ return Number.isFinite(n) ? n : fallback;
3086
+ };
3087
+ var dirname = (p) => p.slice(0, p.lastIndexOf("/") + 1);
3088
+ function resolve(base, target) {
3089
+ const out = [];
3090
+ for (const seg of (target.startsWith("/") ? target.slice(1) : base + target).split("/")) {
3091
+ if (seg === "..") out.pop();
3092
+ else if (seg && seg !== ".") out.push(seg);
3093
+ }
3094
+ return out.join("/");
3095
+ }
3096
+ async function xml(ctx, path) {
3097
+ if (!ctx.zip.has(path)) return null;
3098
+ const text = new TextDecoder().decode(await ctx.zip.read(path));
3099
+ const doc = new ctx.Parser().parseFromString(text, "application/xml");
3100
+ return doc.getElementsByTagName("parsererror").length ? null : doc;
3101
+ }
3102
+ async function rels(ctx, part) {
3103
+ const doc = await xml(ctx, `${dirname(part)}_rels/${part.slice(part.lastIndexOf("/") + 1)}.rels`);
3104
+ const out = /* @__PURE__ */ new Map();
3105
+ for (const r of deep(doc, "Relationship")) if (r.getAttribute("TargetMode") !== "External") out.set(_nullishCoalesce(r.getAttribute("Id"), () => ( "")), resolve(dirname(part), _nullishCoalesce(r.getAttribute("Target"), () => ( ""))));
3106
+ return out;
3107
+ }
3108
+ function colour(ctx, holder) {
3109
+ if (!holder) return null;
3110
+ const c = holder.firstElementChild;
3111
+ if (!c) return null;
3112
+ let hex = null;
3113
+ if (c.localName === "srgbClr") hex = `#${(_nullishCoalesce(c.getAttribute("val"), () => ( "000000"))).toLowerCase()}`;
3114
+ else if (c.localName === "sysClr") hex = `#${(_nullishCoalesce(c.getAttribute("lastClr"), () => ( "000000"))).toLowerCase()}`;
3115
+ else if (c.localName === "schemeClr") {
3116
+ const name = _nullishCoalesce(c.getAttribute("val"), () => ( ""));
3117
+ const alias = { tx1: "dk1", bg1: "lt1", tx2: "dk2", bg2: "lt2" };
3118
+ hex = _nullishCoalesce(ctx.theme.get(_nullishCoalesce(alias[name], () => ( name))), () => ( null));
3119
+ } else if (c.localName === "prstClr") hex = _nullishCoalesce({ black: "#000000", white: "#ffffff", red: "#ff0000", green: "#008000", blue: "#0000ff" }[_nullishCoalesce(c.getAttribute("val"), () => ( ""))], () => ( null));
3120
+ if (!hex || !/^#[0-9a-f]{6}$/.test(hex)) return null;
3121
+ const lum = kid(c, "lumMod");
3122
+ if (lum) {
3123
+ const k = num(lum, "val", 1e5) / 1e5;
3124
+ const off = num(kid(c, "lumOff"), "val", 0) / 1e5;
3125
+ hex = `#${[1, 3, 5].map((i) => Math.round(Math.min(255, Math.max(0, parseInt(hex.slice(i, i + 2), 16) * k + 255 * off))).toString(16).padStart(2, "0")).join("")}`;
3126
+ }
3127
+ return hex;
3128
+ }
3129
+ function preset(prst, w, h) {
3130
+ const poly = (pts) => [{ closed: true, anchors: pts.map(([x, y]) => ({ x, y })) }];
3131
+ switch (prst) {
3132
+ case "rect":
3133
+ return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3134
+ case "roundRect":
3135
+ return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
3136
+ case "ellipse":
3137
+ return [_chunkYJLCBA7Vcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3138
+ case "triangle":
3139
+ return poly([[w / 2, 0], [w, h], [0, h]]);
3140
+ case "rtTriangle":
3141
+ return poly([[0, 0], [w, h], [0, h]]);
3142
+ case "diamond":
3143
+ return poly([[w / 2, 0], [w, h / 2], [w / 2, h], [0, h / 2]]);
3144
+ case "parallelogram":
3145
+ return poly([[w * 0.25, 0], [w, 0], [w * 0.75, h], [0, h]]);
3146
+ case "hexagon":
3147
+ return poly([[w * 0.25, 0], [w * 0.75, 0], [w, h / 2], [w * 0.75, h], [w * 0.25, h], [0, h / 2]]);
3148
+ case "line":
3149
+ case "straightConnector1":
3150
+ return [{ closed: false, anchors: [{ x: 0, y: 0 }, { x: w, y: h }] }];
3151
+ default:
3152
+ return null;
3153
+ }
3154
+ }
3155
+ function custom(geom, w, h) {
3156
+ const out = [];
3157
+ for (const path of deep(geom, "path")) {
3158
+ const sx = w / (num(path, "w") || w || 1);
3159
+ const sy = h / (num(path, "h") || h || 1);
3160
+ const pt = (el) => ({ x: num(el, "x") * sx, y: num(el, "y") * sy });
3161
+ let cur = null;
3162
+ for (const cmd of Array.from(path.children)) {
3163
+ const pts = kids(cmd, "pt").map(pt);
3164
+ if (cmd.localName === "moveTo" && pts[0]) {
3165
+ if (cur) out.push(cur);
3166
+ cur = { closed: false, anchors: [{ x: pts[0].x, y: pts[0].y }] };
3167
+ } else if (!cur) continue;
3168
+ else if (cmd.localName === "lnTo" && pts[0]) cur.anchors.push({ x: pts[0].x, y: pts[0].y });
3169
+ else if (cmd.localName === "cubicBezTo" && pts.length === 3) {
3170
+ cur.anchors[cur.anchors.length - 1].out = pts[0];
3171
+ cur.anchors.push({ x: pts[2].x, y: pts[2].y, in: pts[1] });
3172
+ } else if (cmd.localName === "quadBezTo" && pts.length === 2) {
3173
+ const p0 = cur.anchors[cur.anchors.length - 1];
3174
+ cur.anchors[cur.anchors.length - 1].out = { x: p0.x + 2 / 3 * (pts[0].x - p0.x), y: p0.y + 2 / 3 * (pts[0].y - p0.y) };
3175
+ cur.anchors.push({ x: pts[1].x, y: pts[1].y, in: { x: pts[1].x + 2 / 3 * (pts[0].x - pts[1].x), y: pts[1].y + 2 / 3 * (pts[0].y - pts[1].y) } });
3176
+ } else if (cmd.localName === "close") {
3177
+ cur.closed = true;
3178
+ out.push(cur);
3179
+ cur = null;
3180
+ }
3181
+ }
3182
+ if (cur) out.push(cur);
3183
+ }
3184
+ return out;
3185
+ }
3186
+ function placement(xfrm, map) {
3187
+ const off = kid(xfrm, "off");
3188
+ const ext = kid(xfrm, "ext");
3189
+ const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
3190
+ const rot = num(xfrm, "rot") / 6e4 * (Math.PI / 180);
3191
+ const fx = _optionalChain([xfrm, 'optionalAccess', _124 => _124.getAttribute, 'call', _125 => _125("flipH")]) === "1" ? -1 : 1;
3192
+ const fy = _optionalChain([xfrm, 'optionalAccess', _126 => _126.getAttribute, 'call', _127 => _127("flipV")]) === "1" ? -1 : 1;
3193
+ const cx = x + w / 2;
3194
+ const cy = y + h / 2;
3195
+ const cos = Math.cos(rot);
3196
+ const sin = Math.sin(rot);
3197
+ const a = cos * fx;
3198
+ const b = sin * fx;
3199
+ const c = -sin * fy;
3200
+ const d = cos * fy;
3201
+ const e = cx - a * (w / 2) - c * (h / 2);
3202
+ const f = cy - b * (w / 2) - d * (h / 2);
3203
+ return { x, y, w, h, transform: [a, b, c, d, e, f].map((v) => v + 0) };
3204
+ }
3205
+ var idFor = (ctx, spid, name) => {
3206
+ const base = `${name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "shape"}-${spid}`;
3207
+ let id = base;
3208
+ for (let k = 2; ctx.used.has(id); k++) id = `${base}-${k}`;
3209
+ ctx.used.add(id);
3210
+ ctx.nodes.set(spid, id);
3211
+ return id;
3212
+ };
3213
+ function shapes(ctx, tree, map) {
3214
+ const out = [];
3215
+ for (const el of Array.from(tree.children)) {
3216
+ const nv = el.firstElementChild;
3217
+ const cNvPr = kid(nv, "cNvPr");
3218
+ const spid = num(cNvPr, "id", -1);
3219
+ const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _128 => _128.getAttribute, 'call', _129 => _129("name")]), () => ( ""));
3220
+ if (el.localName === "grpSp") {
3221
+ const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
3222
+ const off = kid(xfrm, "off");
3223
+ const ext = kid(xfrm, "ext");
3224
+ const chOff = kid(xfrm, "chOff");
3225
+ const chExt = kid(xfrm, "chExt");
3226
+ const sx = num(ext, "cx") / (num(chExt, "cx") || num(ext, "cx") || 1);
3227
+ const sy = num(ext, "cy") / (num(chExt, "cy") || num(ext, "cy") || 1);
3228
+ const inner = (x, y, w2, h2) => map(num(off, "x") + (x - num(chOff, "x")) * sx, num(off, "y") + (y - num(chOff, "y")) * sy, w2 * sx, h2 * sy);
3229
+ const id = idFor(ctx, spid, name || "group");
3230
+ out.push({ id, type: "group", ...name ? { name } : {}, children: shapes(ctx, el, inner) });
3231
+ continue;
3232
+ }
3233
+ if (el.localName === "pic" || el.localName === "graphicFrame") {
3234
+ ctx.notes.push(`"${name || `shape ${spid}`}" is a ${el.localName === "pic" ? "picture" : "chart, table or diagram"}, which the artwork cannot hold; it was left out.`);
3235
+ continue;
3236
+ }
3237
+ if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
3238
+ const spPr = kid(el, "spPr");
3239
+ const { w, h, transform } = placement(kid(spPr, "xfrm"), map);
3240
+ const prst = _optionalChain([kid, 'call', _130 => _130(spPr, "prstGeom"), 'optionalAccess', _131 => _131.getAttribute, 'call', _132 => _132("prst")]);
3241
+ const cust = kid(spPr, "custGeom");
3242
+ let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
3243
+ if (!subpaths) {
3244
+ if (prst) ctx.notes.push(`"${name}" is a ${prst}, drawn as its bounding rectangle.`);
3245
+ subpaths = [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3246
+ }
3247
+ const style = kid(el, "style");
3248
+ const fill = kid(spPr, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(spPr, "solidFill")), () => ( (el.localName === "cxnSp" ? null : colour(ctx, kid(style, "fillRef")))));
3249
+ const ln = kid(spPr, "ln");
3250
+ const stroke = kid(ln, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(ln, "solidFill")), () => ( colour(ctx, kid(style, "lnRef"))));
3251
+ if (kid(spPr, "gradFill")) ctx.notes.push(`"${name}" has a gradient fill, imported as its first colour or none.`);
3252
+ const text = deep(kid(el, "txBody"), "t").map((t) => _nullishCoalesce(t.textContent, () => ( ""))).join("").trim();
3253
+ if (text) ctx.notes.push(`"${name}" has text ("${text.slice(0, 40)}${text.length > 40 ? "\u2026" : ""}"), which the artwork cannot hold; only its shape was imported.`);
3254
+ const node = {
3255
+ id: idFor(ctx, spid, name),
3256
+ type: "path",
3257
+ ...name ? { name } : {},
3258
+ transform,
3259
+ fill: _nullishCoalesce(fill, () => ( (kid(spPr, "gradFill") ? colour(ctx, kid(deep(spPr, "gs")[0], "srgbClr") ? deep(spPr, "gs")[0] : null) : null))),
3260
+ stroke,
3261
+ strokeWidth: Math.max(0.5, (num(ln, "w", 12700) || 12700) / EMU),
3262
+ subpaths
3263
+ };
3264
+ out.push(node);
3265
+ }
3266
+ return out;
3267
+ }
3268
+ var DIRECTION_FROM = { 1: "down", 2: "left", 4: "up", 8: "right" };
3269
+ var DIRECTION_TO = { 1: "up", 2: "right", 4: "down", 8: "left" };
3270
+ function easeOf(ctn) {
3271
+ const accel = num(ctn, "accel") / 1e5;
3272
+ const decel = num(ctn, "decel") / 1e5;
3273
+ if (!accel && !decel) return void 0;
3274
+ return { type: "cubic-bezier", x1: Math.min(1, accel), y1: 0, x2: Math.max(0, 1 - decel), y2: 1 };
3275
+ }
3276
+ function command(ctx, ctn, scene, artwork, target, hidden) {
3277
+ const cls = ctn.getAttribute("presetClass");
3278
+ const id = num(ctn, "presetID");
3279
+ const sub = num(ctn, "presetSubtype");
3280
+ const durs = [ctn, ...deep(ctn, "cTn")].map((c) => num(c, "dur", NaN)).filter(Number.isFinite);
3281
+ const duration = durs.length ? Math.max(...durs) : void 0;
3282
+ const ease = easeOf(ctn);
3283
+ const base = { targets: [target], ...duration !== void 0 ? { duration } : {}, ...ease ? { ease } : {} };
3284
+ const repeat = num(ctn, "repeatCount", 1e3) / 1e3;
3285
+ const auto = ctn.getAttribute("autoRev") === "1";
3286
+ const timing = auto || repeat > 1 ? { repeat: Math.max(1, Math.round(repeat)) * (auto ? 2 : 1), ...auto ? { repeatMode: "mirror" } : {} } : {};
3287
+ const label = `${cls} effect ${id} on "${target}"`;
3288
+ if (cls === "entr") {
3289
+ const by = {
3290
+ 1: { type: "enter", ...base, duration: 0 },
3291
+ 2: { type: "enter", style: "slide", ...base, direction: _nullishCoalesce(DIRECTION_FROM[sub], () => ( "up")), distance: Math.round(Math.max(scene.width, scene.height) / 3) },
3292
+ 10: { type: "enter", style: "fade", ...base },
3293
+ 9: { type: "enter", style: "fade", ...base },
3294
+ 22: { type: "enter", style: "wipe", ...base, direction: _nullishCoalesce(DIRECTION_FROM[sub], () => ( "right")) },
3295
+ 16: { type: "enter", style: "split", ...base, orientation: sub === 26 || sub === 42 ? "vertical" : "horizontal" },
3296
+ 6: { type: "enter", style: "iris", ...base, shape: "circle" },
3297
+ 4: { type: "enter", style: "iris", ...base, shape: "box" },
3298
+ 53: { type: "enter", style: "zoom", ...base },
3299
+ 23: { type: "enter", style: "zoom", ...base },
3300
+ 31: { type: "enter", style: "pop", ...base },
3301
+ 26: { type: "enter", style: "pop", ...base },
3302
+ 55: { type: "enter", style: "grow", ...base },
3303
+ 37: { type: "enter", style: "rise", ...base },
3304
+ 42: { type: "enter", style: "rise", ...base }
3305
+ };
3306
+ if (by[id]) return by[id];
3307
+ ctx.notes.push(`${label} has no match here; it fades in instead.`);
3308
+ return { type: "enter", style: "fade", ...base };
3309
+ }
3310
+ if (cls === "exit") {
3311
+ const by = {
3312
+ 1: { type: "exit", ...base, duration: 0 },
3313
+ 10: { type: "exit", style: "fade", ...base },
3314
+ 9: { type: "exit", style: "fade", ...base },
3315
+ 2: { type: "exit", style: "slide", ...base, direction: _nullishCoalesce(DIRECTION_TO[sub], () => ( "down")), distance: Math.round(Math.max(scene.width, scene.height) / 3) },
3316
+ 22: { type: "exit", style: "wipe", ...base, direction: _nullishCoalesce(DIRECTION_TO[sub], () => ( "right")) },
3317
+ 53: { type: "exit", style: "shrink", ...base },
3318
+ 31: { type: "exit", style: "shrink", ...base }
3319
+ };
3320
+ if (by[id]) return by[id];
3321
+ ctx.notes.push(`${label} has no match here; it fades out instead.`);
3322
+ return { type: "exit", style: "fade", ...base };
3323
+ }
3324
+ if (cls === "emph") {
3325
+ const rot = deep(ctn, "animRot")[0];
3326
+ const scale = kid(deep(ctn, "animScale")[0], "by");
3327
+ const clr = colour(ctx, kid(deep(ctn, "animClr")[0], "to"));
3328
+ switch (id) {
3329
+ case 26:
3330
+ return { type: "pulse", ...base, ...timing };
3331
+ case 27:
3332
+ return { type: "color-pulse", ...base, ...clr ? { color: clr } : {}, ...timing };
3333
+ case 32:
3334
+ return { type: "teeter", ...base, ...timing };
3335
+ case 34:
3336
+ return { type: "wave", ...base, ...timing };
3337
+ case 8:
3338
+ return { type: "rotate", ...base, by: rot ? num(rot, "by") / 6e4 : 360, ...timing };
3339
+ case 6:
3340
+ return { type: "scale", ...base, to: scale ? { x: num(scale, "x", 1e5) / 1e5, y: num(scale, "y", 1e5) / 1e5 } : 1.5, ...timing };
3341
+ case 9:
3342
+ return { type: "fade", ...base, to: 0.5, ...timing };
3343
+ case 1:
3344
+ case 19:
3345
+ return clr ? { type: "style", ...base, fill: clr, ...timing } : null;
3346
+ case 7:
3347
+ return clr ? { type: "style", ...base, stroke: clr, ...timing } : null;
3348
+ }
3349
+ ctx.notes.push(`${label} has no match here and was skipped.`);
3350
+ return null;
3351
+ }
3352
+ if (cls === "path") {
3353
+ const motion = deep(ctn, "animMotion")[0];
3354
+ const d = _optionalChain([motion, 'optionalAccess', _133 => _133.getAttribute, 'call', _134 => _134("path")]);
3355
+ if (!d) return null;
3356
+ const entry = artwork.flatMap(function all(n) {
3357
+ return n.type === "group" ? [n, ...n.children.flatMap(all)] : [n];
3358
+ }).find((n) => n.id === target);
3359
+ const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _135 => _135.transform]), () => ( [1, 0, 0, 1, 0, 0]));
3360
+ const p = _optionalChain([entry, 'optionalAccess', _136 => _136.type]) === "path" ? _optionalChain([entry, 'access', _137 => _137.subpaths, 'access', _138 => _138[0], 'optionalAccess', _139 => _139.anchors]) : void 0;
3361
+ const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
3362
+ const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
3363
+ const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
3364
+ const ly = ys.length ? (Math.min(...ys) + Math.max(...ys)) / 2 : 0;
3365
+ const cx = t[0] * lx + t[2] * ly + t[4];
3366
+ const cy = t[1] * lx + t[3] * ly + t[5];
3367
+ const nums = _nullishCoalesce(d.match(/[MLCZE]|-?[\d.]+(?:e-?\d+)?/gi), () => ( []));
3368
+ const sp = { closed: false, anchors: [] };
3369
+ let i = 0;
3370
+ const read = () => ({ x: cx + Number(nums[i++]) * scene.width, y: cy + Number(nums[i++]) * scene.height });
3371
+ while (i < nums.length) {
3372
+ const c = nums[i++].toUpperCase();
3373
+ if (c === "M" || c === "L") sp.anchors.push(read());
3374
+ else if (c === "C") {
3375
+ const c1 = read();
3376
+ const c2 = read();
3377
+ const e = read();
3378
+ if (sp.anchors.length) sp.anchors[sp.anchors.length - 1].out = c1;
3379
+ sp.anchors.push({ ...e, in: c2 });
3380
+ } else if (c === "Z") sp.closed = true;
3381
+ }
3382
+ if (sp.anchors.length < 2) return null;
3383
+ const pathId = `${target}-path-${hidden.length + 1}`;
3384
+ hidden.push({ id: pathId, type: "path", name: "Motion path", visible: false, fill: null, stroke: "#94a3b8", subpaths: [sp] });
3385
+ return { type: "follow", ...base, path: pathId, ...timing };
3386
+ }
3387
+ return null;
3388
+ }
3389
+ async function fromPptxAnimation(data, options = {}) {
3390
+ const Parser = _nullishCoalesce(options.DOMParser, () => ( globalThis.DOMParser));
3391
+ if (!Parser) throw new Error("No DOMParser: pass one in options (jsdom's or xmldom's in Node).");
3392
+ let zip;
3393
+ try {
3394
+ zip = await _chunkEMQWJA3Gcjs.readZip.call(void 0, data, options);
3395
+ } catch (error) {
3396
+ throw new Error(`This is not a PowerPoint file (.pptx): ${error.message}`);
3397
+ }
3398
+ const ctx = { zip, Parser, notes: [], theme: /* @__PURE__ */ new Map(), nodes: /* @__PURE__ */ new Map(), used: /* @__PURE__ */ new Set() };
3399
+ const pres = await xml(ctx, "ppt/presentation.xml");
3400
+ if (!pres) throw new Error("This is not a PowerPoint file (.pptx): it has no ppt/presentation.xml.");
3401
+ const presRels = await rels(ctx, "ppt/presentation.xml");
3402
+ const slidePaths = deep(pres, "sldId").map((s) => _nullishCoalesce(presRels.get(_nullishCoalesce(_nullishCoalesce(s.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id"), () => ( s.getAttribute("r:id"))), () => ( ""))), () => ( ""))).filter(Boolean);
3403
+ const n = _nullishCoalesce(options.slide, () => ( 1));
3404
+ if (!(Number.isInteger(n) && n >= 1 && n <= slidePaths.length)) throw new Error(`There is no slide ${n}; the file has ${slidePaths.length} slide${slidePaths.length === 1 ? "" : "s"}.`);
3405
+ const size = deep(pres, "sldSz")[0];
3406
+ const width = Math.round(num(size, "cx", 12192e3) / EMU);
3407
+ const height = Math.round(num(size, "cy", 6858e3) / EMU);
3408
+ for (const [, path] of presRels) {
3409
+ if (!path.includes("theme/")) continue;
3410
+ const theme = await xml(ctx, path);
3411
+ const scheme = deep(theme, "clrScheme")[0];
3412
+ for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _140 => _140.children]), () => ( [])))) {
3413
+ const v = c.firstElementChild;
3414
+ const hex = _optionalChain([v, 'optionalAccess', _141 => _141.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _142 => _142.getAttribute, 'call', _143 => _143("lastClr")]);
3415
+ if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
3416
+ }
3417
+ break;
3418
+ }
3419
+ const slide = await xml(ctx, slidePaths[n - 1]);
3420
+ if (!slide) throw new Error(`Slide ${n} cannot be read.`);
3421
+ const tree = deep(slide, "spTree")[0];
3422
+ const toPx = (x, y, w, h) => [x / EMU, y / EMU, w / EMU, h / EMU];
3423
+ const nodes = tree ? shapes(ctx, tree, toPx) : [];
3424
+ const bg = _nullishCoalesce(colour(ctx, _nullishCoalesce(deep(deep(slide, "bg")[0], "solidFill")[0], () => ( null))), () => ( "#ffffff"));
3425
+ const hidden = [];
3426
+ const shots = [];
3427
+ const effects = deep(deep(slide, "timing")[0], "cTn").filter((c) => c.hasAttribute("presetClass"));
3428
+ for (const ctn of effects) {
3429
+ const spid = num(deep(ctn, "spTgt")[0], "spid", -1);
3430
+ const target = ctx.nodes.get(spid);
3431
+ if (!target) {
3432
+ ctx.notes.push(`An effect targets shape ${spid}, which was not imported; it was skipped.`);
3433
+ continue;
3434
+ }
3435
+ if (deep(ctn, "txEl").length) ctx.notes.push(`An effect on "${target}" animates part of its text, which was not imported; it animates the whole shape.`);
3436
+ const cmd = command(ctx, ctn, { width, height }, nodes, target, hidden);
3437
+ if (!cmd) continue;
3438
+ const kind = ctn.getAttribute("nodeType");
3439
+ const delay = num(kid(kid(ctn, "stCondLst"), "cond"), "delay", 0);
3440
+ if (kind === "clickEffect" || !shots.length) shots.push({ id: `click-${shots.length + 1}`, run: [] });
3441
+ const run = shots[shots.length - 1].run;
3442
+ const placed = { ...cmd, ...delay > 0 ? { delay } : {}, ...kind === "withEffect" && run.length ? { with: "previous" } : {} };
3443
+ run.push(placed);
3444
+ }
3445
+ if (effects.length && !shots.length) ctx.notes.push("The slide's effects could not be read.");
3446
+ const artwork = { width, height, background: bg, nodes: [...nodes, ...hidden] };
3447
+ const scene = { version: 1, name: `slide-${n}`, artwork, shots, ...shots.length > 1 ? { trigger: "click" } : {} };
3448
+ const problems = motionSceneShapeProblems(scene);
3449
+ if (problems.length) throw new Error(`The imported scene is not well formed:
3450
+ ${problems.join("\n")}`);
3451
+ return { scene, notes: [...new Set(ctx.notes)], issues: checkMotionScene(scene), slides: slidePaths.length };
3452
+ }
3453
+
3072
3454
  // src/animation-editor/controller.ts
3073
3455
  var BLANK = { width: 800, height: 450, background: "#ffffff", nodes: [] };
3074
3456
  var AnimationEditorController = (_class = class {
@@ -3136,7 +3518,7 @@ var AnimationEditorController = (_class = class {
3136
3518
  time: p.time,
3137
3519
  playing: p.playing,
3138
3520
  loop: p.loop,
3139
- currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _122 => _122(timeline, p.time), 'optionalAccess', _123 => _123.id]), () => ( null)),
3521
+ currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _144 => _144(timeline, p.time), 'optionalAccess', _145 => _145.id]), () => ( null)),
3140
3522
  selection: this.selection,
3141
3523
  readOnly: this.readOnly,
3142
3524
  error: this.error,
@@ -3175,7 +3557,7 @@ var AnimationEditorController = (_class = class {
3175
3557
  this.applying = false;
3176
3558
  }
3177
3559
  this.notify();
3178
- _optionalChain([this, 'access', _124 => _124.onChange, 'optionalCall', _125 => _125(scene)]);
3560
+ _optionalChain([this, 'access', _146 => _146.onChange, 'optionalCall', _147 => _147(scene)]);
3179
3561
  }
3180
3562
  commit(label, next) {
3181
3563
  const before = this.scene;
@@ -3184,14 +3566,14 @@ var AnimationEditorController = (_class = class {
3184
3566
  this.notify();
3185
3567
  return;
3186
3568
  }
3187
- const command2 = {
3569
+ const command3 = {
3188
3570
  name: label,
3189
3571
  tag: "animation-editor",
3190
3572
  execute: () => this.setScene(next),
3191
3573
  undo: () => this.setScene(before),
3192
3574
  redo: () => this.setScene(next)
3193
3575
  };
3194
- this.history.execute(command2);
3576
+ this.history.execute(command3);
3195
3577
  }
3196
3578
  refuse(message) {
3197
3579
  this.error = message;
@@ -3364,11 +3746,11 @@ var DRAW_ORDER = {
3364
3746
  sortBy: { type: "string", enum: ["document", "distance"], description: "With sequence: stacking order (default) or distance from origin (a radial reveal)." },
3365
3747
  origin: object({ x: { type: "number", description: "Document units." }, y: { type: "number", description: "Document units." } }, ["x", "y"], "With sortBy distance: where strokes are drawn out from (default the target's centre).")
3366
3748
  };
3367
- var command = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
3749
+ var command2 = (type, description, extra = {}, required = []) => object({ type: { const: type, description }, ...BASE, ...extra }, ["type", "targets", ...required], description);
3368
3750
  var MOTION_COMMAND_SCHEMA = {
3369
3751
  description: `A command (one of ${MOTION_COMMAND_TYPES.join(", ")}). Commands in a shot play one after another unless "with": "previous".`,
3370
3752
  oneOf: [
3371
- command("enter", "Brings hidden targets in; they are hidden before this shot.", {
3753
+ command2("enter", "Brings hidden targets in; they are hidden before this shot.", {
3372
3754
  ...DRAW_ORDER,
3373
3755
  style: {
3374
3756
  type: "string",
@@ -3381,18 +3763,18 @@ var MOTION_COMMAND_SCHEMA = {
3381
3763
  shape: { type: "string", enum: [...MOTION_IRIS_SHAPES], description: "For iris: open through a circle (default; an ellipse on a box that is not square) or a box." },
3382
3764
  orientation: { type: "string", enum: [...MOTION_SPLIT_ORIENTATIONS], description: "For split: horizontal (default) opens up and down from a horizontal line through the middle; vertical opens left and right." }
3383
3765
  }),
3384
- command("exit", "Takes targets out.", {
3766
+ command2("exit", "Takes targets out.", {
3385
3767
  ...DRAW_ORDER,
3386
3768
  style: { type: "string", enum: [...MOTION_EXIT_STYLES], description: "fade (default), shrink, slide, undraw, or wipe (hides behind a travelling edge through a clip over the target's box: a wipe in, reversed)." },
3387
3769
  direction: { type: "string", enum: [...MOTION_DIRECTIONS], description: "For slide: direction of travel (default down). For wipe: the way the edge travels (default right, hiding from the left)." },
3388
3770
  distance: { type: "number", description: "For slide: document units (default 40)." }
3389
3771
  }),
3390
- command("draw", "Draws strokes on (or off) to a fraction of their length.", { ...DRAW_ORDER, comet: FRACTION("A travelling stroke this fraction of the length long: it runs along the path and off the end (leave out from and to)."), to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
3391
- command("move", "Moves targets by an offset or so their centre lands on a point.", { via: { type: "array", items: POINT("A point the centre passes through."), minItems: 1, maxItems: 64, description: 'Waypoints (document units) the centre passes through on the way to "to" or "by", smoothly (velocity carries through each) and without overshooting any. Default length 700 ms + 400 per waypoint.' }, pacing: { type: "string", enum: ["even", "equal"], description: "With via: even (default) keeps the speed steady along the path; equal gives each stretch the same time." }, blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
3392
- command("rotate", "Turns targets about their centre (degrees, clockwise).", { blend: BLEND("replace"), by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
3393
- command("scale", "Scales targets about their centre (1 = rest size).", { blend: BLEND("replace"), to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
3394
- command("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
3395
- command("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
3772
+ command2("draw", "Draws strokes on (or off) to a fraction of their length.", { ...DRAW_ORDER, comet: FRACTION("A travelling stroke this fraction of the length long: it runs along the path and off the end (leave out from and to)."), to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
3773
+ command2("move", "Moves targets by an offset or so their centre lands on a point.", { via: { type: "array", items: POINT("A point the centre passes through."), minItems: 1, maxItems: 64, description: 'Waypoints (document units) the centre passes through on the way to "to" or "by", smoothly (velocity carries through each) and without overshooting any. Default length 700 ms + 400 per waypoint.' }, pacing: { type: "string", enum: ["even", "equal"], description: "With via: even (default) keeps the speed steady along the path; equal gives each stretch the same time." }, blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
3774
+ command2("rotate", "Turns targets about their centre (degrees, clockwise).", { blend: BLEND("replace"), by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
3775
+ command2("scale", "Scales targets about their centre (1 = rest size).", { blend: BLEND("replace"), to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
3776
+ command2("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
3777
+ command2("style", "Blends solid fill / stroke colours (in OKLab) and stroke width. On a group it changes every path in it.", {
3396
3778
  fill: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
3397
3779
  stroke: { type: "string", description: "CSS colour (hex, rgb(), rgba())." },
3398
3780
  strokeWidth: { type: "number", minimum: 0, description: "Document units." }
@@ -3411,24 +3793,24 @@ var MOTION_COMMAND_SCHEMA = {
3411
3793
  ["type", "targets", "clip"],
3412
3794
  "Plays a clip on the targets."
3413
3795
  ),
3414
- command("match", `Smart Animate: tweens a group into another group (usually hidden), part by part. Parts pair by name, then by id with the group ids taken out (card-a-title \u2194 card-b-title), then by kind in order; each takes its partner's shape, paint and place. Unpaired parts fade out; parts of "into" with no partner do not appear (check_animation lists them).`, { into: { type: "string", minLength: 1, description: "Id of the group to become." } }, ["into"]),
3415
- command("morph", "Morphs each target into the shape (and paint) of another node, which usually stays hidden.", { into: { type: "string", minLength: 1, description: "Id of the node whose shape to take." } }, ["into"]),
3416
- command("follow", "Moves targets along a path node, centre on the path.", {
3796
+ command2("match", `Smart Animate: tweens a group into another group (usually hidden), part by part. Parts pair by name, then by id with the group ids taken out (card-a-title \u2194 card-b-title), then by kind in order; each takes its partner's shape, paint and place. Unpaired parts fade out; parts of "into" with no partner do not appear (check_animation lists them).`, { into: { type: "string", minLength: 1, description: "Id of the group to become." } }, ["into"]),
3797
+ command2("morph", "Morphs each target into the shape (and paint) of another node, which usually stays hidden.", { into: { type: "string", minLength: 1, description: "Id of the node whose shape to take." } }, ["into"]),
3798
+ command2("follow", "Moves targets along a path node, centre on the path.", {
3417
3799
  path: { type: "string", minLength: 1, description: "Id of a path node (it can be hidden)." },
3418
3800
  rotate: { type: "boolean", description: "Turn with the path (default false); moves and shakes made meanwhile turn with it too." },
3419
3801
  from: FRACTION("Where to start along the path (default 0)."),
3420
3802
  to: FRACTION("Where to end along the path (default 1).")
3421
3803
  }, ["path"]),
3422
- command("pulse", "Scales up and back to draw the eye.", { blend: BLEND("add"), amount: { type: "number", description: "Extra scale at the peak (default 0.15)." }, count: { type: "integer", minimum: 1, description: "Pulses (default 1)." } }),
3423
- command("shake", "Shakes side to side (or up and down), settling.", {
3804
+ command2("pulse", "Scales up and back to draw the eye.", { blend: BLEND("add"), amount: { type: "number", description: "Extra scale at the peak (default 0.15)." }, count: { type: "integer", minimum: 1, description: "Pulses (default 1)." } }),
3805
+ command2("shake", "Shakes side to side (or up and down), settling.", {
3424
3806
  blend: BLEND("add"),
3425
3807
  amount: { type: "number", description: "Document units (default 8)." },
3426
3808
  count: { type: "integer", minimum: 1, description: "Shakes (default 3)." },
3427
3809
  axis: { type: "string", enum: ["horizontal", "vertical"], description: "Default horizontal." }
3428
3810
  }),
3429
- command("teeter", "Rocks about the centre either way, settling.", { blend: BLEND("add"), angle: { type: "number", description: "Degrees either way (default 8)." }, count: { type: "integer", minimum: 1, description: "Rocks (default 3)." } }),
3430
- command("wave", "Bobs up and down without settling, like something floating (default 1000 ms).", { blend: BLEND("add"), amount: { type: "number", description: "Height in document units (default 6)." }, count: { type: "integer", minimum: 1, description: "Bobs (default 2)." } }),
3431
- command("wiggle", "Wanders about its place as smooth seeded noise, easing out of and back to rest (default 1500 ms). The same seed always wanders the same way.", {
3811
+ command2("teeter", "Rocks about the centre either way, settling.", { blend: BLEND("add"), angle: { type: "number", description: "Degrees either way (default 8)." }, count: { type: "integer", minimum: 1, description: "Rocks (default 3)." } }),
3812
+ command2("wave", "Bobs up and down without settling, like something floating (default 1000 ms).", { blend: BLEND("add"), amount: { type: "number", description: "Height in document units (default 6)." }, count: { type: "integer", minimum: 1, description: "Bobs (default 2)." } }),
3813
+ command2("wiggle", "Wanders about its place as smooth seeded noise, easing out of and back to rest (default 1500 ms). The same seed always wanders the same way.", {
3432
3814
  blend: BLEND("add"),
3433
3815
  amount: { type: "number", description: "Up to about this far, in document units (default 6)." },
3434
3816
  frequency: { type: "number", exclusiveMinimum: 0, description: "Wanders per second, in Hz (default 3)." },
@@ -3436,12 +3818,12 @@ var MOTION_COMMAND_SCHEMA = {
3436
3818
  rotate: { type: "number", description: "Also turns about the centre by up to about this many degrees (default 0)." },
3437
3819
  seed: { type: "integer", minimum: 0, description: "Default: one picked from the target id, so each target wanders its own way." }
3438
3820
  }),
3439
- command("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
3821
+ command2("color-pulse", "Tints solid paint toward a colour and back (mixed in OKLab). On a group it tints every path in it.", {
3440
3822
  color: { type: "string", description: 'The tint, a CSS colour (default "#f59e0b").' },
3441
3823
  paint: { type: "string", enum: ["fill", "stroke"], description: "Which paint (default fill)." },
3442
3824
  count: { type: "integer", minimum: 1, description: "Pulses (default 1)." }
3443
3825
  }),
3444
- command("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
3826
+ command2("effect", "Tweens a numeric parameter of a live path effect on the targets (twist angle, wiggle time, zig zag size, trim offset\u2026).", {
3445
3827
  effect: { type: "string", minLength: 1, description: `Effect id from get_animation's element "effects".` },
3446
3828
  param: { type: "string", minLength: 1, description: "A numeric parameter of that effect (listed with it)." },
3447
3829
  to: { type: "number", description: "Value at the end." }
@@ -3740,9 +4122,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
3740
4122
  handler: ({ from = 0, to, limit = 200 }) => {
3741
4123
  const s = scene();
3742
4124
  const timeline = compileMotionScene(s);
3743
- const words = _nullishCoalesce(_optionalChain([s, 'access', _126 => _126.narration, 'optionalAccess', _127 => _127.words]), () => ( []));
4125
+ const words = _nullishCoalesce(_optionalChain([s, 'access', _148 => _148.narration, 'optionalAccess', _149 => _149.words]), () => ( []));
3744
4126
  const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
3745
- const shotAt = (ms) => _optionalChain([timeline, 'access', _128 => _128.shots, 'access', _129 => _129.find, 'call', _130 => _130((x) => ms >= x.start && ms < x.end), 'optionalAccess', _131 => _131.id]);
4127
+ const shotAt = (ms) => _optionalChain([timeline, 'access', _150 => _150.shots, 'access', _151 => _151.find, 'call', _152 => _152((x) => ms >= x.start && ms < x.end), 'optionalAccess', _153 => _153.id]);
3746
4128
  const beats = [];
3747
4129
  if (s.beat && s.beat.bpm > 0) {
3748
4130
  const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
@@ -3835,6 +4217,33 @@ function createAnimationEditorToolProvider(controller, options = {}) {
3835
4217
  return apply({ op: "set_artwork", artwork }, "Replace artwork", (s) => ({ elements: describeMotionElements(s) }));
3836
4218
  }
3837
4219
  };
4220
+ const importPptx = {
4221
+ name: "import_pptx_animation",
4222
+ title: "Import a PowerPoint slide's animation",
4223
+ description: "Replaces the whole animation with a PowerPoint slide (one undo step): its shapes become the artwork and its animation pane becomes shots, a shot per click (with previous / after previous, delays, repeats and acceleration kept; the scene plays on click). Text, pictures and charts are left out and effects with no match fade, with notes. Returns the shots, notes and issues. With dry_run it only reports them.",
4224
+ inputSchema: object(
4225
+ {
4226
+ data: { type: "string", minLength: 1, description: "The .pptx file, base64-encoded." },
4227
+ slide: { type: "integer", minimum: 1, description: "Which slide (1 = first, default 1)." },
4228
+ dry_run: { type: "boolean", description: "Report without replacing anything (default false)." }
4229
+ },
4230
+ ["data"]
4231
+ ),
4232
+ annotations: { title: "Import a PowerPoint slide's animation", ...DESTRUCTIVE },
4233
+ handler: async ({ data, slide, dry_run = false }) => {
4234
+ let result;
4235
+ try {
4236
+ const bytes = Uint8Array.from(atob(data.replace(/\s+/g, "")), (c) => c.charCodeAt(0));
4237
+ result = await fromPptxAnimation(bytes, slide ? { slide } : {});
4238
+ } catch (error) {
4239
+ throw new Error(`The slide could not be imported: ${error.message} Nothing was changed.`);
4240
+ }
4241
+ const report = { slides: result.slides, notes: result.notes, issues: issueSummary(result.issues), shots: describeMotionShots(result.scene).map(({ id, start, end, commands }) => ({ id, start, end, commands: commands.length })) };
4242
+ if (dry_run) return { dry_run: true, ...report, hint: "Nothing was replaced; call again without dry_run to import." };
4243
+ const applied = controller.apply({ op: "replace_scene", scene: result.scene }, "Import PowerPoint slide");
4244
+ return outcome(applied, applied.ok ? { ...report, elements: describeMotionElements(result.scene) } : {});
4245
+ }
4246
+ };
3838
4247
  const importFlairEffect = {
3839
4248
  name: "import_flair_effect",
3840
4249
  title: "Import a Flair effect",
@@ -4022,7 +4431,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4022
4431
  inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: MOTION_COMMAND_SCHEMA, minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
4023
4432
  annotations: { title: "Add commands to a shot", ...WRITE },
4024
4433
  handler: ({ shot, commands, at }) => {
4025
- const before = _nullishCoalesce(_optionalChain([scene, 'call', _132 => _132(), 'access', _133 => _133.shots, 'access', _134 => _134.find, 'call', _135 => _135((s) => s.id === shot), 'optionalAccess', _136 => _136.run, 'access', _137 => _137.length]), () => ( 0));
4434
+ const before = _nullishCoalesce(_optionalChain([scene, 'call', _154 => _154(), 'access', _155 => _155.shots, 'access', _156 => _156.find, 'call', _157 => _157((s) => s.id === shot), 'optionalAccess', _158 => _158.run, 'access', _159 => _159.length]), () => ( 0));
4026
4435
  const first = _nullishCoalesce(at, () => ( before));
4027
4436
  return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
4028
4437
  const shots = describeMotionShots(s);
@@ -4045,7 +4454,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4045
4454
  ["shot", "command"]
4046
4455
  ),
4047
4456
  annotations: { title: "Change a command", ...WRITE_IDEMPOTENT },
4048
- handler: ({ shot, command: command2, set, remove }) => apply({ op: "update_command", shot, command: command2, set, remove }, "Change command", (s) => ({ command: describeMotionShots(s).find((x) => x.id === shot).commands[command2] }))
4457
+ handler: ({ shot, command: command3, set, remove }) => apply({ op: "update_command", shot, command: command3, set, remove }, "Change command", (s) => ({ command: describeMotionShots(s).find((x) => x.id === shot).commands[command3] }))
4049
4458
  };
4050
4459
  const deleteCommands = {
4051
4460
  name: "delete_commands",
@@ -4068,7 +4477,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4068
4477
  ["shot", "command", "to"]
4069
4478
  ),
4070
4479
  annotations: { title: "Reorder a command", ...WRITE },
4071
- handler: ({ shot, command: command2, to }) => apply({ op: "move_command", shot, command: command2, to }, "Move command", (s) => ({ shot, command: to, from: command2, commands: describeMotionShots(s).find((x) => x.id === shot).commands.map((c) => ({ index: c.index, type: c.type, start: c.start, end: c.end })) }))
4480
+ handler: ({ shot, command: command3, to }) => apply({ op: "move_command", shot, command: command3, to }, "Move command", (s) => ({ shot, command: to, from: command3, commands: describeMotionShots(s).find((x) => x.id === shot).commands.map((c) => ({ index: c.index, type: c.type, start: c.start, end: c.end })) }))
4072
4481
  };
4073
4482
  const setSettings = {
4074
4483
  name: "set_animation_settings",
@@ -4154,7 +4563,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4154
4563
  }
4155
4564
  };
4156
4565
  const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
4157
- const writes = [setArtworkSvg, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
4566
+ const writes = [setArtworkSvg, importPptx, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
4158
4567
  return {
4159
4568
  id: _nullishCoalesce(options.id, () => ( "animation")),
4160
4569
  namespace: options.namespace,
@@ -4203,7 +4612,7 @@ Commands
4203
4612
  - effect tweens a numeric parameter of a live path effect already on the node (twist angle, wiggle time, zig zag size).
4204
4613
 
4205
4614
  Working method
4206
- 1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect to start from a Flair effect and edit it).
4615
+ 1. get_animation to learn the element ids (set_animation_artwork_svg first if there is no artwork: give every element you will animate an id; or import_flair_effect / import_pptx_animation to start from a Flair effect or a PowerPoint slide).
4207
4616
  2. Plan a few shots, each one idea. Add them with insert_shots (add_commands, update_command, move_command and delete_commands refine a shot), or edit_animation to make several edits as one step (dry_run first when unsure).
4208
4617
  - In edit_animation, a later op can use what an earlier one made: "$0.indexes[0]" (the first command op 1 added), "$last.shot".
4209
4618
  3. To hit a length, fit_animation (keep the shots whose pace matters). check_animation and fix every error and warning; render_animation_frame (shot + "end") to look at the result, or with "times" for a contact sheet of several moments; add onion_skin or motion_paths to see the motion in one picture, or get_motion_path for the numbers.
@@ -4217,7 +4626,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
4217
4626
  var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
4218
4627
  var NODES = /* @__PURE__ */ new Set(["into", "path"]);
4219
4628
  function branch(type) {
4220
- return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _138 => _138.properties, 'optionalAccess', _139 => _139.type, 'optionalAccess', _140 => _140.const]) === type);
4629
+ return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _160 => _160.properties, 'optionalAccess', _161 => _161.type, 'optionalAccess', _162 => _162.const]) === type);
4221
4630
  }
4222
4631
  function unitOf(type, name) {
4223
4632
  if (name === "duration" || name === "delay" || name === "stagger") return "ms";
@@ -4252,7 +4661,7 @@ function kindOf(name, schema) {
4252
4661
  }
4253
4662
  function motionCommandFields(type) {
4254
4663
  const schema = branch(type);
4255
- if (!_optionalChain([schema, 'optionalAccess', _141 => _141.properties])) return [];
4664
+ if (!_optionalChain([schema, 'optionalAccess', _163 => _163.properties])) return [];
4256
4665
  const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
4257
4666
  const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
4258
4667
  const kind = kindOf(name, s);
@@ -4299,17 +4708,17 @@ function parseMotionFieldInput(field, raw) {
4299
4708
  if (field.kind === "enum" && field.options && !field.options.includes(text)) return { error: `${field.label} must be one of ${field.options.join(", ")}.` };
4300
4709
  return { set: text };
4301
4710
  }
4302
- function motionFieldEdit(shot, command2, field, raw) {
4711
+ function motionFieldEdit(shot, command3, field, raw) {
4303
4712
  const input = parseMotionFieldInput(field, raw);
4304
4713
  if ("error" in input) return input;
4305
- if ("remove" in input) return { op: "update_command", shot, command: command2, remove: [field.name] };
4306
- return { op: "update_command", shot, command: command2, set: { [field.name]: input.set } };
4714
+ if ("remove" in input) return { op: "update_command", shot, command: command3, remove: [field.name] };
4715
+ return { op: "update_command", shot, command: command3, set: { [field.name]: input.set } };
4307
4716
  }
4308
4717
  function defaultMotionCommand(type, targets, scene) {
4309
4718
  if (type === "wait") return { type: "wait", duration: 500 };
4310
4719
  if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
4311
4720
  const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
4312
- const other = (pred) => _optionalChain([nodes, 'access', _142 => _142.find, 'call', _143 => _143((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _144 => _144.node, 'access', _145 => _145.id]);
4721
+ const other = (pred) => _optionalChain([nodes, 'access', _164 => _164.find, 'call', _165 => _165((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _166 => _166.node, 'access', _167 => _167.id]);
4313
4722
  const base = { targets: [...targets] };
4314
4723
  switch (type) {
4315
4724
  case "scale":
@@ -4340,8 +4749,8 @@ function defaultMotionCommand(type, targets, scene) {
4340
4749
  }
4341
4750
  case "effect": {
4342
4751
  for (const id of targets) {
4343
- const node = _optionalChain([nodes, 'access', _146 => _146.find, 'call', _147 => _147((e) => e.node.id === id), 'optionalAccess', _148 => _148.node]);
4344
- for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _149 => _149.effects]), () => ( []))) {
4752
+ const node = _optionalChain([nodes, 'access', _168 => _168.find, 'call', _169 => _169((e) => e.node.id === id), 'optionalAccess', _170 => _170.node]);
4753
+ for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _171 => _171.effects]), () => ( []))) {
4345
4754
  const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
4346
4755
  if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
4347
4756
  }
@@ -4352,26 +4761,26 @@ function defaultMotionCommand(type, targets, scene) {
4352
4761
  return { type, ...base };
4353
4762
  }
4354
4763
  }
4355
- function motionCommandSummary(command2) {
4356
- const c = command2;
4357
- const what = [command2.type, typeof c.style === "string" ? c.style : ""].filter(Boolean).join(" ");
4358
- if (command2.type === "wait") return `wait ${command2.duration} ms`;
4764
+ function motionCommandSummary(command3) {
4765
+ const c = command3;
4766
+ const what = [command3.type, typeof c.style === "string" ? c.style : ""].filter(Boolean).join(" ");
4767
+ if (command3.type === "wait") return `wait ${command3.duration} ms`;
4359
4768
  const extra = typeof c.into === "string" ? ` \u2192 ${c.into}` : typeof c.path === "string" ? ` along ${c.path}` : "";
4360
- return `${what} \xB7 ${(_nullishCoalesce(command2.targets, () => ( []))).join(", ")}${extra}`;
4769
+ return `${what} \xB7 ${(_nullishCoalesce(command3.targets, () => ( []))).join(", ")}${extra}`;
4361
4770
  }
4362
4771
  function motionCommandRows(scene, shotId) {
4363
4772
  const index = scene.shots.findIndex((s) => s.id === shotId);
4364
4773
  if (index < 0) return [];
4365
4774
  const timeline = compileMotionScene(scene);
4366
- return scene.shots[index].run.map((command2, i) => {
4775
+ return scene.shots[index].run.map((command3, i) => {
4367
4776
  const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
4368
- const primitive = motionFlairPrimitive(command2);
4369
- return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _150 => _150.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _151 => _151.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
4777
+ const primitive = motionFlairPrimitive(command3);
4778
+ return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _172 => _172.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _173 => _173.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
4370
4779
  });
4371
4780
  }
4372
- function duplicateMotionCommandEdit(scene, shot, command2) {
4373
- const run = _nullishCoalesce(_optionalChain([scene, 'access', _152 => _152.shots, 'access', _153 => _153.find, 'call', _154 => _154((s) => s.id === shot), 'optionalAccess', _155 => _155.run]), () => ( []));
4374
- return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
4781
+ function duplicateMotionCommandEdit(scene, shot, command3) {
4782
+ const run = _nullishCoalesce(_optionalChain([scene, 'access', _174 => _174.shots, 'access', _175 => _175.find, 'call', _176 => _176((s) => s.id === shot), 'optionalAccess', _177 => _177.run]), () => ( []));
4783
+ return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
4375
4784
  }
4376
4785
  var MOTION_EASE_CHOICES = [
4377
4786
  { value: "", label: "Default" },
@@ -4455,7 +4864,7 @@ function motionCueFromKey(key) {
4455
4864
  function motionCueChoices(scene, limit = 256) {
4456
4865
  const choices = [];
4457
4866
  const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
4458
- const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _156 => _156.narration, 'optionalAccess', _157 => _157.words, 'access', _158 => _158.map, 'call', _159 => _159((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
4867
+ const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _178 => _178.narration, 'optionalAccess', _179 => _179.words, 'access', _180 => _180.map, 'call', _181 => _181((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
4459
4868
  if (scene.beat && scene.beat.bpm > 0) {
4460
4869
  for (let beat = 0; choices.length < limit; beat++) {
4461
4870
  const time = motionBeatTime(scene.beat, beat);
@@ -4465,7 +4874,7 @@ function motionCueChoices(scene, limit = 256) {
4465
4874
  choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
4466
4875
  }
4467
4876
  }
4468
- _optionalChain([scene, 'access', _160 => _160.narration, 'optionalAccess', _161 => _161.words, 'access', _162 => _162.forEach, 'call', _163 => _163((w, i) => {
4877
+ _optionalChain([scene, 'access', _182 => _182.narration, 'optionalAccess', _183 => _183.words, 'access', _184 => _184.forEach, 'call', _185 => _185((w, i) => {
4469
4878
  if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
4470
4879
  })]);
4471
4880
  return choices;
@@ -4474,7 +4883,7 @@ function motionShotCueTime(scene, cue) {
4474
4883
  return cue ? motionCueTime(scene, cue) : void 0;
4475
4884
  }
4476
4885
  function formatMotionNarration(narration) {
4477
- return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _164 => _164.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4886
+ return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _186 => _186.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4478
4887
  }
4479
4888
  function parseMotionNarration(text) {
4480
4889
  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -4646,5 +5055,6 @@ function parseMotionDrivers(text) {
4646
5055
 
4647
5056
 
4648
5057
 
4649
- exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_CLIP_TARGET = MOTION_CLIP_TARGET; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_DRIVEN_PROPERTIES = MOTION_DRIVEN_PROPERTIES; exports.MOTION_EASE_CHOICES = MOTION_EASE_CHOICES; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MOTION_TRIGGERS = MOTION_TRIGGERS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionDrivers = applyMotionDrivers; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionDrivers = formatMotionDrivers; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionContactSheetSvg = motionContactSheetSvg; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionDrivenNodes = motionDrivenNodes; exports.motionDriverSources = motionDriverSources; exports.motionEaseKey = motionEaseKey; exports.motionEasingCurve = motionEasingCurve; exports.motionEasingGuides = motionEasingGuides; exports.motionEasingPath = motionEasingPath; exports.motionFieldEdit = motionFieldEdit; exports.motionFieldLabel = motionFieldLabel; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionPropertyValue = motionPropertyValue; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionRulerTicks = motionRulerTicks; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
5058
+
5059
+ exports.ANIMATION_EDITOR_AGENT_INSTRUCTIONS = ANIMATION_EDITOR_AGENT_INSTRUCTIONS; exports.AnimationEditorController = AnimationEditorController; exports.FLAIR_EASES = FLAIR_EASES; exports.FLAIR_EXPORT_VERSION = FLAIR_EXPORT_VERSION; exports.MOTION_ADDITIVE_PROPERTIES = MOTION_ADDITIVE_PROPERTIES; exports.MOTION_BLENDS = MOTION_BLENDS; exports.MOTION_CAMERA_MS = MOTION_CAMERA_MS; exports.MOTION_CLIP_TARGET = MOTION_CLIP_TARGET; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_DEFAULT_DURATIONS = MOTION_DEFAULT_DURATIONS; exports.MOTION_DEFAULT_HOLD = MOTION_DEFAULT_HOLD; exports.MOTION_DIRECTIONS = MOTION_DIRECTIONS; exports.MOTION_DRAW_EFFECT_ID = MOTION_DRAW_EFFECT_ID; exports.MOTION_DRAW_MS_PER_UNIT = MOTION_DRAW_MS_PER_UNIT; exports.MOTION_DRAW_RANGE = MOTION_DRAW_RANGE; exports.MOTION_DRIVEN_PROPERTIES = MOTION_DRIVEN_PROPERTIES; exports.MOTION_EASE_CHOICES = MOTION_EASE_CHOICES; exports.MOTION_EASE_IN_OUT = MOTION_EASE_IN_OUT; exports.MOTION_EASE_OUT = MOTION_EASE_OUT; exports.MOTION_EDIT_OPS = MOTION_EDIT_OPS; exports.MOTION_ENTER_STYLES = MOTION_ENTER_STYLES; exports.MOTION_EXIT_STYLES = MOTION_EXIT_STYLES; exports.MOTION_IRIS_SHAPES = MOTION_IRIS_SHAPES; exports.MOTION_ISSUE_CODES = MOTION_ISSUE_CODES; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_REPEAT_MODES = MOTION_REPEAT_MODES; exports.MOTION_SPEED_RANGE = MOTION_SPEED_RANGE; exports.MOTION_SPLIT_ORIENTATIONS = MOTION_SPLIT_ORIENTATIONS; exports.MOTION_TRIGGERS = MOTION_TRIGGERS; exports.MotionSceneFormatError = MotionSceneFormatError; exports.activeSegment = activeSegment; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionDrivers = applyMotionDrivers; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionDrivers = formatMotionDrivers; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.fromPptxAnimation = fromPptxAnimation; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionContactSheetSvg = motionContactSheetSvg; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; exports.motionDrivenNodes = motionDrivenNodes; exports.motionDriverSources = motionDriverSources; exports.motionEaseKey = motionEaseKey; exports.motionEasingCurve = motionEasingCurve; exports.motionEasingGuides = motionEasingGuides; exports.motionEasingPath = motionEasingPath; exports.motionFieldEdit = motionFieldEdit; exports.motionFieldLabel = motionFieldLabel; exports.motionFlairPrimitive = motionFlairPrimitive; exports.motionFollowRoute = motionFollowRoute; exports.motionFrameAt = motionFrameAt; exports.motionFrameToSvg = motionFrameToSvg; exports.motionGhosts = motionGhosts; exports.motionIssue = motionIssue; exports.motionIssueKey = motionIssueKey; exports.motionIssueLine = motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionPath = motionPath; exports.motionPathLength = motionPathLength; exports.motionPathsSvg = motionPathsSvg; exports.motionPropertyValue = motionPropertyValue; exports.motionRestValue = motionRestValue; exports.motionRevealClip = motionRevealClip; exports.motionRevealPadding = motionRevealPadding; exports.motionRulerTicks = motionRulerTicks; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = namedWithSuggestion; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
4650
5060
  //# sourceMappingURL=index.cjs.map