@pixerate/editor 0.74.0 → 0.76.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 (62) hide show
  1. package/THIRD_PARTY_NOTICES.md +2 -0
  2. package/dist/agent/index.cjs +28 -28
  3. package/dist/agent/index.js +3 -3
  4. package/dist/animation-editor/index.cjs +322 -273
  5. package/dist/animation-editor/index.cjs.map +1 -1
  6. package/dist/animation-editor/index.d.cts +96 -3
  7. package/dist/animation-editor/index.d.ts +96 -3
  8. package/dist/animation-editor/index.js +138 -89
  9. package/dist/animation-editor/index.js.map +1 -1
  10. package/dist/canvas/index.cjs +26 -26
  11. package/dist/canvas/index.js +2 -2
  12. package/dist/{chunk-3TLL5OID.js → chunk-4JLB2USO.js} +2 -2
  13. package/dist/{chunk-YJLCBA7V.cjs → chunk-7MD7C6XQ.cjs} +87 -87
  14. package/dist/{chunk-YJLCBA7V.cjs.map → chunk-7MD7C6XQ.cjs.map} +1 -1
  15. package/dist/{chunk-OK7T2LHK.js → chunk-GNO5PEMH.js} +2 -2
  16. package/dist/{chunk-EIXXBKUB.js → chunk-IMSX4IVG.js} +7 -7
  17. package/dist/chunk-INZJALPY.js +87 -0
  18. package/dist/chunk-INZJALPY.js.map +1 -0
  19. package/dist/{chunk-MLREO6J3.cjs → chunk-JEYDXRWQ.cjs} +46 -46
  20. package/dist/{chunk-MLREO6J3.cjs.map → chunk-JEYDXRWQ.cjs.map} +1 -1
  21. package/dist/{chunk-PL3MPFPA.cjs → chunk-MXF4DP2C.cjs} +77 -77
  22. package/dist/{chunk-PL3MPFPA.cjs.map → chunk-MXF4DP2C.cjs.map} +1 -1
  23. package/dist/{chunk-T4XWVPJK.cjs → chunk-RKJDBXTY.cjs} +3 -3
  24. package/dist/{chunk-T4XWVPJK.cjs.map → chunk-RKJDBXTY.cjs.map} +1 -1
  25. package/dist/{chunk-HNDSPZ5T.cjs → chunk-ROXFP2LQ.cjs} +4 -4
  26. package/dist/{chunk-HNDSPZ5T.cjs.map → chunk-ROXFP2LQ.cjs.map} +1 -1
  27. package/dist/{chunk-WON34HKM.js → chunk-SVW2UNUC.js} +2 -2
  28. package/dist/{chunk-66IMF6OD.cjs → chunk-TYOAJDFD.cjs} +3 -3
  29. package/dist/{chunk-66IMF6OD.cjs.map → chunk-TYOAJDFD.cjs.map} +1 -1
  30. package/dist/chunk-WAJQKWQU.cjs +87 -0
  31. package/dist/chunk-WAJQKWQU.cjs.map +1 -0
  32. package/dist/{chunk-O2UH7LZE.cjs → chunk-XGD3FSNC.cjs} +239 -239
  33. package/dist/chunk-XGD3FSNC.cjs.map +1 -0
  34. package/dist/{chunk-VWZB6BCY.js → chunk-Y3NW4VJE.js} +2 -2
  35. package/dist/{chunk-GTMJ4Y3S.js → chunk-YCSFS3GK.js} +244 -244
  36. package/dist/{chunk-GTMJ4Y3S.js.map → chunk-YCSFS3GK.js.map} +1 -1
  37. package/dist/{chunk-UKI64KUD.js → chunk-ZQNDSUZO.js} +6 -6
  38. package/dist/extensions/index.cjs +7 -7
  39. package/dist/extensions/index.cjs.map +1 -1
  40. package/dist/extensions/index.js +6 -6
  41. package/dist/index.cjs +35 -35
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.js +17 -17
  44. package/dist/serializers/index.cjs +4 -4
  45. package/dist/serializers/index.cjs.map +1 -1
  46. package/dist/serializers/index.js +3 -3
  47. package/dist/vector/index.cjs +532 -532
  48. package/dist/vector/index.js +3 -3
  49. package/dist/video-editor/index.cjs +2219 -0
  50. package/dist/video-editor/index.cjs.map +1 -0
  51. package/dist/video-editor/index.d.cts +985 -0
  52. package/dist/video-editor/index.d.ts +985 -0
  53. package/dist/video-editor/index.js +2219 -0
  54. package/dist/video-editor/index.js.map +1 -0
  55. package/package.json +6 -1
  56. package/dist/chunk-O2UH7LZE.cjs.map +0 -1
  57. /package/dist/{chunk-3TLL5OID.js.map → chunk-4JLB2USO.js.map} +0 -0
  58. /package/dist/{chunk-OK7T2LHK.js.map → chunk-GNO5PEMH.js.map} +0 -0
  59. /package/dist/{chunk-EIXXBKUB.js.map → chunk-IMSX4IVG.js.map} +0 -0
  60. /package/dist/{chunk-WON34HKM.js.map → chunk-SVW2UNUC.js.map} +0 -0
  61. /package/dist/{chunk-VWZB6BCY.js.map → chunk-Y3NW4VJE.js.map} +0 -0
  62. /package/dist/{chunk-UKI64KUD.js.map → chunk-ZQNDSUZO.js.map} +0 -0
@@ -20,14 +20,22 @@
20
20
 
21
21
 
22
22
 
23
- var _chunkYJLCBA7Vcjs = require('../chunk-YJLCBA7V.cjs');
23
+ var _chunk7MD7C6XQcjs = require('../chunk-7MD7C6XQ.cjs');
24
24
 
25
25
 
26
26
 
27
27
 
28
28
 
29
29
 
30
- var _chunkO2UH7LZEcjs = require('../chunk-O2UH7LZE.cjs');
30
+
31
+ var _chunkWAJQKWQUcjs = require('../chunk-WAJQKWQU.cjs');
32
+
33
+
34
+
35
+
36
+
37
+
38
+ var _chunkXGD3FSNCcjs = require('../chunk-XGD3FSNC.cjs');
31
39
 
32
40
 
33
41
  var _chunkEMQWJA3Gcjs = require('../chunk-EMQWJA3G.cjs');
@@ -61,6 +69,8 @@ var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
61
69
 
62
70
  // src/animation-editor/types.ts
63
71
  var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
72
+ var MOTION_TEXT_UNITS = ["letter", "word", "line"];
73
+ var MOTION_CASCADES = ["forward", "backward", "center", "edges", "random"];
64
74
  var MOTION_DRIVEN_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY", "opacity"];
65
75
  var MOTION_CLIP_TARGET = "$";
66
76
  var MOTION_COMMAND_TYPES = [
@@ -139,83 +149,6 @@ function motionFlairPrimitive(command3) {
139
149
  }
140
150
  }
141
151
 
142
- // src/animation-editor/issues.ts
143
- var MOTION_ISSUE_CODES = {
144
- "no-shots": { severity: "note", wording: "The scene has no shots yet." },
145
- "duplicate-shot-id": { severity: "error", wording: "Two shots share an id." },
146
- "unknown-target": { severity: "error", wording: "A command names a node the artwork does not have." },
147
- "unknown-path": { severity: "error", wording: "A follow command names a path the artwork does not have." },
148
- "not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
149
- "reveal-no-box": { severity: "warning", wording: "A wipe, iris or split cannot clip a node with no width or height (a lone straight line), so it fades instead." },
150
- "driver-cycle": { severity: "error", wording: "Drivers follow each other in a loop, so none of them has a value." },
151
- "unknown-clip": { severity: "error", wording: "A play command names a clip the scene does not have." },
152
- "unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
153
- "match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
154
- "match-unpaired": { severity: "note", wording: `Parts of a match's "into" group have no partner in the target, so they do not appear.` },
155
- "unknown-effect": { severity: "error", wording: "An effect command names an effect the node does not have." },
156
- "unknown-effect-param": { severity: "error", wording: "An effect command names a parameter that is not a number of that effect." },
157
- "unknown-frame": { severity: "error", wording: "A camera frames a node the artwork does not have." },
158
- "invalid-camera": { severity: "error", wording: "A camera rectangle has no area." },
159
- "invalid-color": { severity: "error", wording: "A colour cannot be read." },
160
- "paint-not-color": { severity: "warning", wording: "A style command recolours a gradient or empty paint, which only switches at the end, or a colour pulse has no solid paint to tint." },
161
- "overlap": { severity: "warning", wording: "Two commands change the same property of a node at the same time; the later one wins." },
162
- "enter-visible": { severity: "warning", wording: "A node enters while it is already showing, so it blinks out first." },
163
- "exit-hidden": { severity: "warning", wording: "A node exits or animates while it is hidden." },
164
- "out-of-frame": { severity: "warning", wording: "A node a command animates ends up outside the camera." },
165
- "too-fast": { severity: "warning", wording: "A change is too quick to follow." },
166
- "spring-cut-short": { severity: "warning", wording: "A spring is given a duration shorter than it takes to settle, so it jumps to its end." },
167
- "unknown-cue": { severity: "error", wording: "A shot is cued to a beat with no beat grid, or to a word the narration does not have." },
168
- "cue-missed": { severity: "warning", wording: "A shot starts after its cue, because the shot before runs past it." },
169
- "trigger-loop": { severity: "note", wording: "A scene that plays on a trigger ignores its loop." },
170
- "click-cue": { severity: "warning", wording: "A shot of a click-triggered scene is cued, but clicks decide when its shots start." },
171
- "click-one-shot": { severity: "note", wording: "A click-triggered scene has one shot, so every click replays it." },
172
- "scene-too-long": { severity: "warning", wording: "The scene runs past its target length." },
173
- "scene-too-short": { severity: "warning", wording: "The scene ends before its target length." },
174
- "unknown-control-color": { severity: "warning", wording: "A control stands for a colour the scene never uses." },
175
- "empty-shot": { severity: "note", wording: "A shot neither moves the camera nor runs a command." },
176
- "camera-aspect": { severity: "note", wording: "A camera rectangle has a different shape from the artwork, so it is letterboxed." }
177
- };
178
- function motionIssue(code, message, extra = {}) {
179
- return { code, severity: MOTION_ISSUE_CODES[code].severity, message, ...extra };
180
- }
181
- function motionIssueKey(issue) {
182
- if (_optionalChain([issue, 'access', _2 => _2.ids, 'optionalAccess', _3 => _3.length])) return `${issue.code}:${[...issue.ids].sort().join(",")}`;
183
- return `${issue.code}@${_nullishCoalesce(issue.shot, () => ( ""))}#${_nullishCoalesce(issue.command, () => ( ""))}`;
184
- }
185
- function motionIssueLine(issue) {
186
- const where = issue.shot !== void 0 ? `Shot "${issue.shot}"${issue.command !== void 0 ? `, command ${issue.command + 1}` : ""}: ` : "";
187
- return `${where}${issue.message}`;
188
- }
189
- function editDistance(a, b) {
190
- const d = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
191
- for (let j = 1; j <= b.length; j++) d[0][j] = j;
192
- for (let i = 1; i <= a.length; i++) {
193
- for (let j = 1; j <= b.length; j++) {
194
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
195
- d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
196
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
197
- }
198
- }
199
- return d[a.length][b.length];
200
- }
201
- function suggestName(word, candidates) {
202
- const w = word.toLowerCase();
203
- let best;
204
- let bestDistance = Infinity;
205
- for (const c of candidates) {
206
- const distance = editDistance(w, c.toLowerCase());
207
- if (distance < bestDistance) {
208
- best = c;
209
- bestDistance = distance;
210
- }
211
- }
212
- return best !== void 0 && bestDistance <= Math.max(1, Math.floor(word.length / 3)) ? best : void 0;
213
- }
214
- function namedWithSuggestion(word, candidates) {
215
- const s = suggestName(word, candidates);
216
- return s !== void 0 && s !== word ? `"${word}" (did you mean "${s}"?)` : `"${word}"`;
217
- }
218
-
219
152
  // src/animation-editor/parse.ts
220
153
  var MotionSceneFormatError = class extends Error {
221
154
 
@@ -229,7 +162,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
229
162
  var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
230
163
  var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
231
164
  var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
232
- var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps"];
165
+ var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps", "split", "cascade"];
233
166
  var DRAW_ORDER_KEYS = ["order", "pace", "align", "sortBy", "origin"];
234
167
  var COMMAND_KEYS = {
235
168
  enter: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
@@ -257,14 +190,14 @@ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
257
190
  var isNum = (v) => typeof v === "number" && Number.isFinite(v);
258
191
  var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
259
192
  function unknownKeys(value, known, where, problems) {
260
- for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${namedWithSuggestion(key, known)}.`);
193
+ for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, key, known)}.`);
261
194
  }
262
195
  function commandShapeProblems(command3, where) {
263
196
  const problems = [];
264
197
  if (!isObject(command3)) return [`${where} must be an object.`];
265
198
  const type = command3.type;
266
199
  if (typeof type !== "string" || !MOTION_COMMAND_TYPES.includes(type)) {
267
- return [`${where}: unknown type ${typeof type === "string" ? namedWithSuggestion(type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
200
+ return [`${where}: unknown type ${typeof type === "string" ? _chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
268
201
  }
269
202
  unknownKeys(command3, COMMAND_KEYS[type], `${where} (${type})`, problems);
270
203
  const p = (msg) => problems.push(`${where} (${type}): ${msg}`);
@@ -301,6 +234,9 @@ function commandShapeProblems(command3, where) {
301
234
  else if (!(Number.isInteger(command3.repeat) && command3.repeat >= 1 && command3.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
302
235
  }
303
236
  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).`);
237
+ if (command3.split !== void 0 && !MOTION_TEXT_UNITS.includes(command3.split)) p(`"split" must be letter, word or line (for outlined text: a group of letter paths).`);
238
+ if (command3.cascade !== void 0 && !MOTION_CASCADES.includes(command3.cascade)) p(`"cascade" must be one of ${MOTION_CASCADES.join(", ")}.`);
239
+ if (command3.cascade !== void 0 && command3.split === void 0) p(`"cascade" goes with "split".`);
304
240
  if (command3.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command3.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
305
241
  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).`);
306
242
  switch (type) {
@@ -308,7 +244,7 @@ function commandShapeProblems(command3, where) {
308
244
  case "exit": {
309
245
  const styles = type === "enter" ? MOTION_ENTER_STYLES : MOTION_EXIT_STYLES;
310
246
  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)})` : ""}.`);
247
+ p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, command3.style, styles)})` : ""}.`);
312
248
  if (command3.direction !== void 0 && !MOTION_DIRECTIONS.includes(command3.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
313
249
  optionalNumber("distance");
314
250
  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).`);
@@ -560,7 +496,7 @@ function matchMotionNodes(from, into) {
560
496
  else out.pairs.push([x.id, y.id]);
561
497
  }
562
498
  };
563
- pair((n) => _optionalChain([n, 'access', _4 => _4.name, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]) || void 0);
499
+ pair((n) => _optionalChain([n, 'access', _2 => _2.name, 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]) || void 0);
564
500
  pair((n, g) => localId(n.id, g.id) || void 0);
565
501
  for (const x of [...left]) {
566
502
  const y = [...right].find((n) => n.type === x.type);
@@ -616,6 +552,87 @@ function smoothMotionTimes(points, start, duration, pacing = "even") {
616
552
  return times;
617
553
  }
618
554
 
555
+ // src/animation-editor/text.ts
556
+ function motionTextLayout(nodes, id) {
557
+ const group = _optionalChain([nodes, 'access', _5 => _5.get, 'call', _6 => _6(id), 'optionalAccess', _7 => _7.node]);
558
+ if (!group || group.type !== "group") return null;
559
+ const letters = _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, group).map((p) => ({ id: p.id, b: _optionalChain([nodes, 'access', _8 => _8.get, 'call', _9 => _9(p.id), 'optionalAccess', _10 => _10.bounds]) })).filter((l) => !!l.b && l.b.width + l.b.height > 0);
560
+ if (!letters.length) return null;
561
+ const lines = [];
562
+ for (const l of [...letters].sort((a, c) => a.b.y + a.b.height / 2 - (c.b.y + c.b.height / 2))) {
563
+ const cy = l.b.y + l.b.height / 2;
564
+ const line = lines.find((x) => cy >= x.top && cy <= x.bottom);
565
+ if (line) {
566
+ line.letters.push(l);
567
+ line.top = Math.min(line.top, l.b.y);
568
+ line.bottom = Math.max(line.bottom, l.b.y + l.b.height);
569
+ } else lines.push({ top: l.b.y, bottom: l.b.y + l.b.height, letters: [l] });
570
+ }
571
+ lines.sort((a, c) => a.top - c.top);
572
+ return {
573
+ lines: lines.map((line) => {
574
+ const row = [...line.letters].sort((a, c) => a.b.x - c.b.x);
575
+ const heights = row.map((l) => l.b.height).sort((a, c) => a - c);
576
+ const gap = heights[Math.floor(heights.length / 2)] * 0.35;
577
+ const words = [];
578
+ row.forEach((l, i) => {
579
+ const prev = row[i - 1];
580
+ if (!prev || l.b.x - (prev.b.x + prev.b.width) > gap) words.push({ letters: [] });
581
+ words[words.length - 1].letters.push(l.id);
582
+ });
583
+ return { words };
584
+ })
585
+ };
586
+ }
587
+ function motionTextUnits(layout, by) {
588
+ if (by === "line") return layout.lines.map((l) => l.words.flatMap((w) => w.letters));
589
+ if (by === "word") return layout.lines.flatMap((l) => l.words.map((w) => w.letters));
590
+ return layout.lines.flatMap((l) => l.words.flatMap((w) => w.letters.map((id) => [id])));
591
+ }
592
+ function motionCascade(units, cascade = "forward", seed = 1) {
593
+ const n = units.length;
594
+ const mid = (n - 1) / 2;
595
+ const indexed = units.map((u, i) => ({ u, i }));
596
+ if (cascade === "backward") return [...units].reverse();
597
+ if (cascade === "center") return indexed.sort((a, b) => Math.abs(a.i - mid) - Math.abs(b.i - mid) || a.i - b.i).map((x) => x.u);
598
+ if (cascade === "edges") return indexed.sort((a, b) => Math.abs(b.i - mid) - Math.abs(a.i - mid) || a.i - b.i).map((x) => x.u);
599
+ if (cascade === "random") {
600
+ let s = seed >>> 0 || 1;
601
+ const rand = () => {
602
+ s = s + 1831565813 >>> 0;
603
+ let t = s;
604
+ t = Math.imul(t ^ t >>> 15, t | 1);
605
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
606
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
607
+ };
608
+ const out = [...units];
609
+ for (let i = n - 1; i > 0; i--) {
610
+ const j = Math.floor(rand() * (i + 1));
611
+ [out[i], out[j]] = [out[j], out[i]];
612
+ }
613
+ return out;
614
+ }
615
+ return [...units];
616
+ }
617
+ var MOTION_TEXT_STAGGER = { letter: 40, word: 120, line: 300 };
618
+ function motionCommandSlots(nodes, command3) {
619
+ if (!command3.split) return { slots: command3.targets.map((id, k) => ({ id, slot: k })), stagger: _nullishCoalesce(command3.stagger, () => ( 0)) };
620
+ const slots = [];
621
+ let slot = 0;
622
+ for (const target of command3.targets) {
623
+ const layout = motionTextLayout(nodes, target);
624
+ if (!layout) {
625
+ slots.push({ id: target, slot: slot++ });
626
+ continue;
627
+ }
628
+ for (const unit of motionCascade(motionTextUnits(layout, command3.split), command3.cascade, _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, target))) {
629
+ for (const id of unit) slots.push({ id, slot });
630
+ slot++;
631
+ }
632
+ }
633
+ return { slots, stagger: _nullishCoalesce(command3.stagger, () => ( MOTION_TEXT_STAGGER[command3.split])) };
634
+ }
635
+
619
636
  // src/animation-editor/compile.ts
620
637
  var indexCache = /* @__PURE__ */ new WeakMap();
621
638
  function indexMotionNodes(nodes) {
@@ -624,21 +641,21 @@ function indexMotionNodes(nodes) {
624
641
  const out = /* @__PURE__ */ new Map();
625
642
  const walk = (list, parentWorld, ancestors) => {
626
643
  for (const node of list) {
627
- const local = _chunkYJLCBA7Vcjs.vectorNodeBounds.call(void 0, node);
628
- const bounds = _chunkYJLCBA7Vcjs.vectorNodeBounds.call(void 0, node, parentWorld);
644
+ const local = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node);
645
+ const bounds = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node, parentWorld);
629
646
  const center = local ? { x: local.x + local.width / 2, y: local.y + local.height / 2 } : { x: 0, y: 0 };
630
647
  if (!out.has(node.id)) out.set(node.id, { node, ancestors, parentWorld, center, bounds, box: local });
631
- if (node.type === "group") walk(node.children, _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, node), parentWorld), [...ancestors, node.id]);
648
+ if (node.type === "group") walk(node.children, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node), parentWorld), [...ancestors, node.id]);
632
649
  }
633
650
  };
634
- walk(nodes, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, []);
651
+ walk(nodes, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, []);
635
652
  indexCache.set(nodes, out);
636
653
  return out;
637
654
  }
638
655
  var solid = (paint) => typeof paint === "string" && paint !== "none" ? paint : void 0;
639
656
  function firstPaint(node, key) {
640
657
  if (node.type === "path") return solid(node[key]);
641
- for (const p of _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)) {
658
+ for (const p of _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
642
659
  const s = solid(p[key]);
643
660
  if (s) return s;
644
661
  }
@@ -646,7 +663,7 @@ function firstPaint(node, key) {
646
663
  }
647
664
  function strokeReach(node) {
648
665
  let reach = 0;
649
- for (const p of node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)) {
666
+ for (const p of node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
650
667
  if (p.stroke == null || p.stroke === "none") continue;
651
668
  const width = _nullishCoalesce(p.strokeWidth, () => ( 1));
652
669
  reach = Math.max(reach, p.strokeAlign === "outside" ? width : p.strokeAlign === "inside" ? 0 : width / 2);
@@ -695,10 +712,10 @@ function motionRevealClip(entry, reveal) {
695
712
  }
696
713
  }
697
714
  function motionRestValue(entry, property, artwork) {
698
- const node = _optionalChain([entry, 'optionalAccess', _7 => _7.node]);
715
+ const node = _optionalChain([entry, 'optionalAccess', _11 => _11.node]);
699
716
  switch (property) {
700
717
  case "opacity":
701
- return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _8 => _8.opacity]), () => ( 1));
718
+ return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _12 => _12.opacity]), () => ( 1));
702
719
  case "x":
703
720
  case "y":
704
721
  case "rotation":
@@ -716,11 +733,11 @@ function motionRestValue(entry, property, artwork) {
716
733
  case "stroke":
717
734
  return _nullishCoalesce((node && firstPaint(node, property)), () => ( "transparent"));
718
735
  case "strokeWidth": {
719
- const path = _optionalChain([node, 'optionalAccess', _9 => _9.type]) === "path" ? node : node ? _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)[0] : void 0;
720
- return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _10 => _10.strokeWidth]), () => ( 1));
736
+ const path = _optionalChain([node, 'optionalAccess', _13 => _13.type]) === "path" ? node : node ? _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)[0] : void 0;
737
+ return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _14 => _14.strokeWidth]), () => ( 1));
721
738
  }
722
739
  case "shape":
723
- return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _11 => _11.id]), () => ( ""));
740
+ return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _15 => _15.id]), () => ( ""));
724
741
  case "clipRect":
725
742
  case "clipCircle": {
726
743
  const pad = entry && motionRevealPadding(entry);
@@ -730,7 +747,7 @@ function motionRestValue(entry, property, artwork) {
730
747
  return [0, 0, artwork.width, artwork.height];
731
748
  }
732
749
  const [, effectId, param] = property.split(":");
733
- const effect = _optionalChain([node, 'optionalAccess', _12 => _12.effects, 'optionalAccess', _13 => _13.find, 'call', _14 => _14((e) => e.id === effectId)]);
750
+ const effect = _optionalChain([node, 'optionalAccess', _16 => _16.effects, 'optionalAccess', _17 => _17.find, 'call', _18 => _18((e) => e.id === effectId)]);
734
751
  const v = effect ? effect.params[param] : void 0;
735
752
  return typeof v === "number" ? v : 0;
736
753
  }
@@ -779,13 +796,13 @@ function segmentValue(segment, time, raw = false) {
779
796
  return typeof segment.from === "string" ? interpolateMotionValue(segment.from, segment.to, Math.min(1, Math.max(0, p))) : interpolateMotionValue(segment.from, segment.to, p);
780
797
  }
781
798
  function activeSegment(track, time) {
782
- if (!_optionalChain([track, 'optionalAccess', _15 => _15.length])) return void 0;
799
+ if (!_optionalChain([track, 'optionalAccess', _19 => _19.length])) return void 0;
783
800
  let found;
784
801
  for (const s of track) if (s.start <= time && (!found || s.start >= found.start)) found = s;
785
802
  return found;
786
803
  }
787
804
  function trackValue(track, time, raw = false) {
788
- if (!_optionalChain([track, 'optionalAccess', _16 => _16.length])) return void 0;
805
+ if (!_optionalChain([track, 'optionalAccess', _20 => _20.length])) return void 0;
789
806
  const s = activeSegment(track, time);
790
807
  if (s) return segmentValue(s, time, raw);
791
808
  let first = track[0];
@@ -818,7 +835,7 @@ function fitMotionRect(rect, aspect) {
818
835
  function resolveMotionCamera(camera, scene) {
819
836
  if ("frame" in camera && typeof camera.frame === "string") {
820
837
  const entry = indexMotionNodes(scene.artwork.nodes).get(camera.frame);
821
- if (!_optionalChain([entry, 'optionalAccess', _17 => _17.bounds])) return null;
838
+ if (!_optionalChain([entry, 'optionalAccess', _21 => _21.bounds])) return null;
822
839
  const pad = _nullishCoalesce(camera.padding, () => ( 24));
823
840
  const b = entry.bounds;
824
841
  const rect = { x: b.x - pad, y: b.y - pad, width: Math.max(1, b.width + pad * 2), height: Math.max(1, b.height + pad * 2) };
@@ -827,12 +844,12 @@ function resolveMotionCamera(camera, scene) {
827
844
  const r = camera;
828
845
  return { x: r.x, y: r.y, width: r.width, height: r.height };
829
846
  }
830
- function motionPathLength(node, parentWorld = _chunkYJLCBA7Vcjs.IDENTITY_MATRIX) {
847
+ function motionPathLength(node, parentWorld = _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
831
848
  let longest = 0;
832
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
849
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
833
850
  for (const p of paths) {
834
851
  try {
835
- longest = Math.max(longest, _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
852
+ longest = Math.max(longest, _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
836
853
  } catch (e2) {
837
854
  }
838
855
  }
@@ -853,12 +870,12 @@ function motionBeatAt(grid, ms) {
853
870
  function motionCueTime(scene, cue) {
854
871
  if (typeof cue.ms === "number") return Math.max(0, cue.ms);
855
872
  if (typeof cue.beat === "number") return scene.beat && scene.beat.bpm > 0 ? Math.max(0, motionBeatTime(scene.beat, cue.beat)) : void 0;
856
- if (typeof cue.word === "number") return _optionalChain([scene, 'access', _18 => _18.narration, 'optionalAccess', _19 => _19.words, 'access', _20 => _20[cue.word], 'optionalAccess', _21 => _21.start]);
873
+ if (typeof cue.word === "number") return _optionalChain([scene, 'access', _22 => _22.narration, 'optionalAccess', _23 => _23.words, 'access', _24 => _24[cue.word], 'optionalAccess', _25 => _25.start]);
857
874
  return void 0;
858
875
  }
859
876
  var SCALE_LIKE = /* @__PURE__ */ new Set(["scaleX", "scaleY", "opacity"]);
860
877
  function motionPropertyValue(timeline, node, property, time, raw = false, depth = 0) {
861
- const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _22 => _22.restOpacity, 'optionalAccess', _23 => _23.get, 'call', _24 => _24(node)]), () => ( 1)) : SCALE_LIKE.has(property) ? 1 : 0;
878
+ const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _26 => _26.restOpacity, 'optionalAccess', _27 => _27.get, 'call', _28 => _28(node)]), () => ( 1)) : SCALE_LIKE.has(property) ? 1 : 0;
862
879
  const v = trackValue(timeline.tracks.get(motionTrackKey(node, property)), time, raw);
863
880
  const base = property === "opacity" ? typeof v === "number" ? v : rest : withMotionLayers(timeline, node, property, typeof v === "number" ? v : rest, time, raw);
864
881
  return applyMotionDrivers(timeline, node, property, base, time, raw, depth);
@@ -869,7 +886,7 @@ function applyMotionDrivers(timeline, node, property, value, time, raw = false,
869
886
  for (const d of timeline.drivers) {
870
887
  if (d.target !== node || d.property !== property) continue;
871
888
  const src = motionPropertyValue(timeline, d.source.node, d.source.property, time, raw, depth + 1);
872
- const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _25 => _25.restOpacity, 'optionalAccess', _26 => _26.get, 'call', _27 => _27(d.source.node)]), () => ( 1)) : SCALE_LIKE.has(d.source.property) ? 1 : 0;
889
+ const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _29 => _29.restOpacity, 'optionalAccess', _30 => _30.get, 'call', _31 => _31(d.source.node)]), () => ( 1)) : SCALE_LIKE.has(d.source.property) ? 1 : 0;
873
890
  let change = (src - srcRest) * (_nullishCoalesce(d.factor, () => ( 1))) + (_nullishCoalesce(d.offset, () => ( 0)));
874
891
  if (d.clamp) change = Math.min(d.clamp[1], Math.max(d.clamp[0], change));
875
892
  v = SCALE_LIKE.has(property) ? v * (1 + change) : v + change;
@@ -900,7 +917,7 @@ function motionCommandDuration(command3, scene, target) {
900
917
  return motionCycleDuration(command3, scene, target) * motionCommandRepeat(command3);
901
918
  }
902
919
  function motionClipLayout(scene, clip, target, speed = 1) {
903
- const run = _optionalChain([scene, 'access', _28 => _28.clips, 'optionalAccess', _29 => _29[clip], 'optionalAccess', _30 => _30.run]);
920
+ const run = _optionalChain([scene, 'access', _32 => _32.clips, 'optionalAccess', _33 => _33[clip], 'optionalAccess', _34 => _34.run]);
904
921
  if (!run) return { items: [], length: 0 };
905
922
  const f = speed > 0 && Number.isFinite(speed) ? 1 / speed : 1;
906
923
  const items = [];
@@ -942,7 +959,7 @@ function motionCycleDuration(command3, scene, target) {
942
959
  const ms = length * MOTION_DRAW_MS_PER_UNIT;
943
960
  return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
944
961
  }
945
- if (command3.type === "move" && _optionalChain([command3, 'access', _31 => _31.via, 'optionalAccess', _32 => _32.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
962
+ if (command3.type === "move" && _optionalChain([command3, 'access', _35 => _35.via, 'optionalAccess', _36 => _36.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
946
963
  return MOTION_DEFAULT_DURATIONS[command3.type];
947
964
  }
948
965
  var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
@@ -982,10 +999,11 @@ function compileMotionScene(scene) {
982
999
  shot.run.forEach((command3, i) => {
983
1000
  const base = command3.with === "previous" && i > 0 ? prevStart : runEnd;
984
1001
  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;
988
- const end2 = durations.reduce((m, d, k) => Math.max(m, begin + k * stagger + d), begin);
1002
+ const split = command3.type === "wait" ? null : motionCommandSlots(nodes, command3);
1003
+ const slots = _nullishCoalesce(_optionalChain([split, 'optionalAccess', _37 => _37.slots]), () => ( []));
1004
+ const durations = command3.type === "wait" ? [command3.duration * f] : slots.map((s) => motionCommandDuration(command3, scene, s.id) * f);
1005
+ const stagger = (_nullishCoalesce(_optionalChain([split, 'optionalAccess', _38 => _38.stagger]), () => ( 0))) * f;
1006
+ const end2 = durations.reduce((m, d, k) => Math.max(m, begin + (_nullishCoalesce(_optionalChain([slots, 'access', _39 => _39[k], 'optionalAccess', _40 => _40.slot]), () => ( k))) * stagger + d), begin);
989
1007
  commands.push({ shot: shot.id, shotIndex: index, command: i, type: command3.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
990
1008
  prevStart = begin;
991
1009
  runEnd = Math.max(runEnd, end2);
@@ -1033,14 +1051,15 @@ function compileMotionScene(scene) {
1033
1051
  });
1034
1052
  continue;
1035
1053
  }
1036
- command3.targets.forEach((target, k) => {
1054
+ const split = motionCommandSlots(nodes, command3);
1055
+ for (const { id: target, slot } of split.slots) {
1037
1056
  const entry = nodes.get(target);
1038
- if (!entry) return;
1057
+ if (!entry) continue;
1039
1058
  const f = motionShotTimeScale(shot);
1040
- const start = timing.start + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
1059
+ const start = timing.start + slot * split.stagger * f;
1041
1060
  const cycle = motionCycleDuration(command3, scene, target) * f;
1042
1061
  jobs.push({ start, order: order++, run: () => compileRepeated(command3, target, entry, start, cycle, timing) });
1043
- });
1062
+ }
1044
1063
  }
1045
1064
  jobs.sort((a, b) => a.start - b.start || a.order - b.order).forEach((job) => job.run());
1046
1065
  function compileRepeated(command3, node, entry, start, cycle, timing) {
@@ -1083,16 +1102,16 @@ function compileMotionScene(scene) {
1083
1102
  const order2 = _nullishCoalesce(o.order, () => ( "together"));
1084
1103
  const pace = _nullishCoalesce(o.pace, () => ( "time"));
1085
1104
  if (order2 === "together" && pace === "time") return null;
1086
- const paths = entry.node.type === "path" ? [entry.node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, entry.node);
1105
+ const paths = entry.node.type === "path" ? [entry.node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, entry.node);
1087
1106
  let list = paths.map((p) => {
1088
1107
  const at = nodes.get(p.id);
1089
1108
  let first = { x: 0, y: 0 };
1090
1109
  try {
1091
- const m = _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _33 => _33.parentWorld]), () => ( _chunkYJLCBA7Vcjs.IDENTITY_MATRIX)), { effects: false })[0];
1110
+ const m = _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _41 => _41.parentWorld]), () => ( _chunk7MD7C6XQcjs.IDENTITY_MATRIX)), { effects: false })[0];
1092
1111
  if (m && m.type === "M") first = { x: m.x, y: m.y };
1093
1112
  } catch (e3) {
1094
1113
  }
1095
- return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _34 => _34.parentWorld]))), first };
1114
+ return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _42 => _42.parentWorld]))), first };
1096
1115
  });
1097
1116
  if (!list.length) return null;
1098
1117
  const span = Math.max(0, e - s);
@@ -1121,7 +1140,7 @@ function compileMotionScene(scene) {
1121
1140
  const style = _nullishCoalesce(command3.style, () => ( "fade"));
1122
1141
  const opacity = rest("opacity");
1123
1142
  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;
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);
1143
+ for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _43 => _43.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
1125
1144
  if (reveal) {
1126
1145
  seg("opacity", opacity, "linear", start, start);
1127
1146
  seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
@@ -1197,20 +1216,20 @@ function compileMotionScene(scene) {
1197
1216
  }
1198
1217
  case "move": {
1199
1218
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
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));
1219
+ let dx = _nullishCoalesce(_optionalChain([command3, 'access', _44 => _44.by, 'optionalAccess', _45 => _45.x]), () => ( 0));
1220
+ let dy = _nullishCoalesce(_optionalChain([command3, 'access', _46 => _46.by, 'optionalAccess', _47 => _47.y]), () => ( 0));
1202
1221
  if (command3.to) {
1203
- const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1204
- const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command3.to);
1222
+ const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
1223
+ const target = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, inv, command3.to);
1205
1224
  dx = target.x - (entry.center.x + num2("x"));
1206
1225
  dy = target.y - (entry.center.y + num2("y"));
1207
1226
  }
1208
- if (_optionalChain([command3, 'access', _40 => _40.via, 'optionalAccess', _41 => _41.length])) {
1209
- const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1227
+ if (_optionalChain([command3, 'access', _48 => _48.via, 'optionalAccess', _49 => _49.length])) {
1228
+ const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
1210
1229
  const x0 = num2("x");
1211
1230
  const y0 = num2("y");
1212
1231
  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 }];
1232
+ const offsets = [{ x: 0, y: 0 }, ...command3.via.map((p) => _chunk7MD7C6XQcjs.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
1233
  const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
1215
1234
  for (const axis of ["x", "y"]) {
1216
1235
  const base = add ? 0 : axis === "x" ? x0 : y0;
@@ -1303,7 +1322,7 @@ function compileMotionScene(scene) {
1303
1322
  for (const track of tracks.values()) track.sort((a, b) => a.start - b.start);
1304
1323
  segments.sort((a, b) => a.start - b.start);
1305
1324
  const duration = shots.length ? shots[shots.length - 1].end : 0;
1306
- const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _42 => _42.drivers, 'optionalAccess', _43 => _43.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
1325
+ const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _50 => _50.drivers, 'optionalAccess', _51 => _51.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
1307
1326
  timelineCache.set(scene, timeline);
1308
1327
  return timeline;
1309
1328
  }
@@ -1316,7 +1335,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
1316
1335
  var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
1317
1336
  var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
1318
1337
  function applyMotionControlValues(scene, values) {
1319
- if (!values || !_optionalChain([scene, 'access', _44 => _44.controls, 'optionalAccess', _45 => _45.length])) return scene;
1338
+ if (!values || !_optionalChain([scene, 'access', _52 => _52.controls, 'optionalAccess', _53 => _53.length])) return scene;
1320
1339
  const map = /* @__PURE__ */ new Map();
1321
1340
  for (const control of scene.controls) {
1322
1341
  const value = values[control.name];
@@ -1352,17 +1371,17 @@ function morphBetween(a, b) {
1352
1371
  let inner = morphCache.get(a);
1353
1372
  if (!inner) morphCache.set(a, inner = /* @__PURE__ */ new WeakMap());
1354
1373
  let morph = inner.get(b);
1355
- if (!morph) inner.set(b, morph = _chunkYJLCBA7Vcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
1374
+ if (!morph) inner.set(b, morph = _chunk7MD7C6XQcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
1356
1375
  return morph;
1357
1376
  }
1358
1377
  function shapeIn(entry, shape) {
1359
1378
  if (shape === entry) return entry.node;
1360
- const m = _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, shape.node), shape.parentWorld), _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld));
1361
- return { ...shape.node, ..._chunkYJLCBA7Vcjs.isIdentityMatrix.call(void 0, m) ? { transform: void 0 } : { transform: m } };
1379
+ const m = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, shape.node), shape.parentWorld), _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld));
1380
+ return { ...shape.node, ..._chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, m) ? { transform: void 0 } : { transform: m } };
1362
1381
  }
1363
1382
  function shapeAt(entry, timeline, nodes, time) {
1364
1383
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
1365
- if (!_optionalChain([track, 'optionalAccess', _46 => _46.length])) return null;
1384
+ if (!_optionalChain([track, 'optionalAccess', _54 => _54.length])) return null;
1366
1385
  const s = activeSegment(track, time);
1367
1386
  const fromId = String(s ? s.from : track[0].from);
1368
1387
  if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
@@ -1378,20 +1397,20 @@ function shapeAt(entry, timeline, nodes, time) {
1378
1397
  function motionFollowRoute(entry, path) {
1379
1398
  if (!path || path.node.type !== "path") return null;
1380
1399
  try {
1381
- return _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path.node, path.parentWorld, { effects: false }), _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld));
1400
+ return _chunkXGD3FSNCcjs.transformBezierPath.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path.node, path.parentWorld, { effects: false }), _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld));
1382
1401
  } catch (e4) {
1383
1402
  return null;
1384
1403
  }
1385
1404
  }
1386
1405
  function followAt(entry, timeline, nodes, time) {
1387
1406
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
1388
- const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _47 => _47[0]])));
1389
- if (!_optionalChain([s, 'optionalAccess', _48 => _48.path])) return null;
1407
+ const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _55 => _55[0]])));
1408
+ if (!_optionalChain([s, 'optionalAccess', _56 => _56.path])) return null;
1390
1409
  const route = motionFollowRoute(entry, nodes.get(s.path));
1391
1410
  const progress = Number(trackValue(track, time));
1392
1411
  if (!route || !(progress >= 0)) return null;
1393
1412
  try {
1394
- const at = _chunkO2UH7LZEcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, route));
1413
+ const at = _chunkXGD3FSNCcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, route));
1395
1414
  if (!at) return null;
1396
1415
  return { x: at.point[0], y: at.point[1], angle: s.rotate ? at.angle * 180 / Math.PI : 0 };
1397
1416
  } catch (e5) {
@@ -1404,7 +1423,7 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
1404
1423
  const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
1405
1424
  return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
1406
1425
  };
1407
- const driven = _optionalChain([timeline, 'access', _49 => _49.drivers, 'optionalAccess', _50 => _50.some, 'call', _51 => _51((d) => d.target === entry.node.id && d.property !== "opacity")]);
1426
+ const driven = _optionalChain([timeline, 'access', _57 => _57.drivers, 'optionalAccess', _58 => _58.some, 'call', _59 => _59((d) => d.target === entry.node.id && d.property !== "opacity")]);
1408
1427
  if (!driven && !TRANSFORM_PROPS.some((p) => (follow || p !== "follow") && (timeline.tracks.has(motionTrackKey(entry.node.id, p)) || timeline.tracks.has(motionAddTrackKey(entry.node.id, p))))) return null;
1409
1428
  const dx = read("x", 0);
1410
1429
  const dy = read("y", 0);
@@ -1412,9 +1431,9 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
1412
1431
  const scaleX = read("scaleX", 1);
1413
1432
  const scaleY = read("scaleY", 1);
1414
1433
  const c = entry.center;
1415
- let matrix = _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.scaleMatrix.call(void 0, scaleX, scaleY, c), _chunkYJLCBA7Vcjs.rotateMatrix.call(void 0, rotation, c)), _chunkYJLCBA7Vcjs.translateMatrix.call(void 0, dx, dy));
1434
+ let matrix = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.scaleMatrix.call(void 0, scaleX, scaleY, c), _chunk7MD7C6XQcjs.rotateMatrix.call(void 0, rotation, c)), _chunk7MD7C6XQcjs.translateMatrix.call(void 0, dx, dy));
1416
1435
  const along = follow ? followAt(entry, timeline, nodes, time) : null;
1417
- if (along) matrix = _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, matrix, _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.translateMatrix.call(void 0, -c.x, -c.y), _chunkYJLCBA7Vcjs.rotateMatrix.call(void 0, along.angle)), _chunkYJLCBA7Vcjs.translateMatrix.call(void 0, along.x, along.y)));
1436
+ if (along) matrix = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, matrix, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.translateMatrix.call(void 0, -c.x, -c.y), _chunk7MD7C6XQcjs.rotateMatrix.call(void 0, along.angle)), _chunk7MD7C6XQcjs.translateMatrix.call(void 0, along.x, along.y)));
1418
1437
  return { matrix, dx, dy, rotation, scaleX, scaleY, follow: along };
1419
1438
  }
1420
1439
  function motionNodeClips(id, timeline, time) {
@@ -1448,7 +1467,7 @@ function motionFrameAt(scene, time, options = {}) {
1448
1467
  if (out.visible === void 0) delete out.visible;
1449
1468
  }
1450
1469
  const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
1451
- if (effectTracks.length && _optionalChain([out, 'access', _52 => _52.effects, 'optionalAccess', _53 => _53.length])) {
1470
+ if (effectTracks.length && _optionalChain([out, 'access', _60 => _60.effects, 'optionalAccess', _61 => _61.length])) {
1452
1471
  out = {
1453
1472
  ...out,
1454
1473
  effects: out.effects.map((effect) => {
@@ -1481,22 +1500,22 @@ function motionFrameAt(scene, time, options = {}) {
1481
1500
  const start = Math.min(1, Math.max(0, typeof drawStart === "number" ? drawStart : 0));
1482
1501
  const end = Math.min(1, Math.max(0, typeof drawEnd === "number" ? drawEnd : 1));
1483
1502
  if (start > 0 || end < 1) {
1484
- const trim = _chunkYJLCBA7Vcjs.createVectorEffect.call(void 0, "trim", MOTION_DRAW_EFFECT_ID, { start: tidy(start * 100), end: tidy(end * 100) });
1503
+ const trim = _chunk7MD7C6XQcjs.createVectorEffect.call(void 0, "trim", MOTION_DRAW_EFFECT_ID, { start: tidy(start * 100), end: tidy(end * 100) });
1485
1504
  p = { ...p, effects: [trim, ...(_nullishCoalesce(p.effects, () => ( []))).filter((e) => e.id !== MOTION_DRAW_EFFECT_ID)] };
1486
1505
  }
1487
1506
  }
1488
1507
  return p;
1489
1508
  });
1490
1509
  }
1491
- const opacity = _optionalChain([timeline, 'access', _54 => _54.drivers, 'optionalAccess', _55 => _55.some, 'call', _56 => _56((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
1510
+ const opacity = _optionalChain([timeline, 'access', _62 => _62.drivers, 'optionalAccess', _63 => _63.some, 'call', _64 => _64((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
1492
1511
  if (typeof opacity === "number") {
1493
1512
  const o = Math.min(1, Math.max(0, tidy(opacity)));
1494
1513
  out = { ...out, opacity: o };
1495
1514
  if (o >= 1) delete out.opacity;
1496
1515
  }
1497
1516
  const offset = options.offsets === false ? null : motionNodeOffset(entry, timeline, time, nodes);
1498
- if (offset && !_chunkYJLCBA7Vcjs.isIdentityMatrix.call(void 0, offset.matrix)) {
1499
- const m = _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, out), offset.matrix).map(tidy);
1517
+ if (offset && !_chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, offset.matrix)) {
1518
+ const m = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, out), offset.matrix).map(tidy);
1500
1519
  out = { ...out, transform: m };
1501
1520
  }
1502
1521
  return out;
@@ -1516,7 +1535,7 @@ function motionFrameToSvg(scene, time, options = {}) {
1516
1535
  const wrap = { ...options.wrap };
1517
1536
  for (const [id, clips] of Object.entries(frame.clips))
1518
1537
  wrap[id] = [..._nullishCoalesce(wrap[id], () => ( [])), ...clips.map((clip, i) => ({ clip: { id: `${prefix}reveal-${id}-${i}`, shape: clip.shape, attrs: motionClipAttrs(clip) } }))];
1519
- return withViewBox(_chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
1538
+ return withViewBox(_chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
1520
1539
  }
1521
1540
  function withViewBox(svg, box) {
1522
1541
  const f = (n) => String(Math.round(n * 1e3) / 1e3);
@@ -1561,7 +1580,7 @@ function motionPath(scene, id, options = {}) {
1561
1580
  const r = (n) => Math.round(n * 100) / 100;
1562
1581
  const centreAt = (t) => {
1563
1582
  const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
1564
- const b = _optionalChain([node, 'optionalAccess', _57 => _57.bounds]);
1583
+ const b = _optionalChain([node, 'optionalAccess', _65 => _65.bounds]);
1565
1584
  return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
1566
1585
  };
1567
1586
  const points = [];
@@ -1595,8 +1614,8 @@ function motionBlurTimes(scene, time, blur = {}) {
1595
1614
  const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
1596
1615
  let travel = 0;
1597
1616
  for (const id of ids) {
1598
- const p = _optionalChain([a, 'access', _58 => _58.get, 'call', _59 => _59(id), 'optionalAccess', _60 => _60.bounds]);
1599
- const q = _optionalChain([b, 'access', _61 => _61.get, 'call', _62 => _62(id), 'optionalAccess', _63 => _63.bounds]);
1617
+ const p = _optionalChain([a, 'access', _66 => _66.get, 'call', _67 => _67(id), 'optionalAccess', _68 => _68.bounds]);
1618
+ const q = _optionalChain([b, 'access', _69 => _69.get, 'call', _70 => _70(id), 'optionalAccess', _71 => _71.bounds]);
1600
1619
  if (p && q) travel = Math.max(travel, Math.abs(p.x - q.x), Math.abs(p.y - q.y), Math.abs(p.x + p.width - q.x - q.width), Math.abs(p.y + p.height - q.y - q.height));
1601
1620
  }
1602
1621
  const n = Math.min(most, Math.ceil(travel / 1.5));
@@ -1608,7 +1627,7 @@ function averagedFrames(scene, times, options, prefix) {
1608
1627
  return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
1609
1628
  const own = `${prefix}blur${k}-`;
1610
1629
  const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
1611
- const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _64 => _64.exec, 'call', _65 => _65(frame), 'optionalAccess', _66 => _66[1]]), () => ( ""));
1630
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _72 => _72.exec, 'call', _73 => _73(frame), 'optionalAccess', _74 => _74[1]]), () => ( ""));
1612
1631
  const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1613
1632
  return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
1614
1633
  }).join("")}</g>`;
@@ -1623,7 +1642,7 @@ function motionStageSvg(scene, time, options = {}) {
1623
1642
  if (blurTimes.length > 1) {
1624
1643
  const open2 = current.indexOf(">") + 1;
1625
1644
  const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
1626
- const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _67 => _67.exec, 'call', _68 => _68(body2), 'optionalAccess', _69 => _69[0]]), () => ( "")) : "";
1645
+ const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _75 => _75.exec, 'call', _76 => _76(body2), 'optionalAccess', _77 => _77[0]]), () => ( "")) : "";
1627
1646
  current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
1628
1647
  }
1629
1648
  if (!onionSkin && !motionPaths) return current;
@@ -1638,7 +1657,7 @@ function motionStageSvg(scene, time, options = {}) {
1638
1657
  const open = current.indexOf(">") + 1;
1639
1658
  const close = current.lastIndexOf("</svg>");
1640
1659
  const body = current.slice(open, close);
1641
- const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _70 => _70.exec, 'call', _71 => _71(body), 'optionalAccess', _72 => _72[0]]), () => ( "")) : "";
1660
+ const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _78 => _78.exec, 'call', _79 => _79(body), 'optionalAccess', _80 => _80[0]]), () => ( "")) : "";
1642
1661
  return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
1643
1662
  }
1644
1663
  function motionContactSheetSvg(scene, times, options = {}) {
@@ -1657,7 +1676,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1657
1676
  const x = gap + i % cols * (w + gap);
1658
1677
  const y = gap + Math.floor(i / cols) * (h + label + gap);
1659
1678
  const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
1660
- const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _73 => _73.exec, 'call', _74 => _74(frame), 'optionalAccess', _75 => _75[1]]), () => ( `0 0 ${w} ${h}`));
1679
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _81 => _81.exec, 'call', _82 => _82(frame), 'optionalAccess', _83 => _83[1]]), () => ( `0 0 ${w} ${h}`));
1661
1680
  const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1662
1681
  const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
1663
1682
  const caption = labels ? `<text x="${x + w / 2}" y="${y + h + label * 0.8}" font-family="system-ui, sans-serif" font-size="${Math.round(label * 0.7)}" text-anchor="middle" fill="#64748b">${(t / 1e3).toFixed(2)} s${shot ? ` \xB7 ${shot.id.replace(/[<&]/g, "")}` : ""}</text>` : "";
@@ -1669,7 +1688,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1669
1688
  // src/animation-editor/check.ts
1670
1689
  var MOTION_MIN_CHANGE_MS = 120;
1671
1690
  var NUMERIC_PARAMS = (node, effectId) => {
1672
- const effect = _optionalChain([node, 'access', _76 => _76.effects, 'optionalAccess', _77 => _77.find, 'call', _78 => _78((e) => e.id === effectId)]);
1691
+ const effect = _optionalChain([node, 'access', _84 => _84.effects, 'optionalAccess', _85 => _85.find, 'call', _86 => _86((e) => e.id === effectId)]);
1673
1692
  if (!effect) return null;
1674
1693
  return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
1675
1694
  };
@@ -1699,8 +1718,8 @@ function visibleAt(timeline, id, time, node) {
1699
1718
  if (Array.isArray(rect) && (rect[2] <= 1e-4 || rect[3] <= 1e-4)) return false;
1700
1719
  const circle = clip("clipCircle");
1701
1720
  if (Array.isArray(circle) && circle[2] <= 1e-4) return false;
1702
- const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
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) => {
1721
+ const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
1722
+ const drawn = num2("drawEnd", 1) > 0.01 && (node.type === "path" || _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).length === 0 || _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).some((p) => {
1704
1723
  const v = trackValue(timeline.tracks.get(motionTrackKey(p.id, "drawEnd")), time);
1705
1724
  return typeof v !== "number" || v > 0.01;
1706
1725
  }));
@@ -1712,91 +1731,96 @@ function checkMotionScene(scene) {
1712
1731
  const ids = [...nodes.keys()];
1713
1732
  const timeline = compileMotionScene(scene);
1714
1733
  const artAspect = scene.artwork.width / scene.artwork.height;
1715
- if (!scene.shots.length) issues.push(motionIssue("no-shots", "The scene has no shots yet; add one with a list of commands."));
1734
+ if (!scene.shots.length) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "no-shots", "The scene has no shots yet; add one with a list of commands."));
1716
1735
  const seen = /* @__PURE__ */ new Set();
1717
1736
  for (const shot of scene.shots) {
1718
- if (seen.has(shot.id)) issues.push(motionIssue("duplicate-shot-id", `Shot id "${shot.id}" is used twice; give each shot its own id.`, { shot: shot.id }));
1737
+ if (seen.has(shot.id)) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "duplicate-shot-id", `Shot id "${shot.id}" is used twice; give each shot its own id.`, { shot: shot.id }));
1719
1738
  seen.add(shot.id);
1720
1739
  }
1721
1740
  const known = (id, code, what, where) => {
1722
1741
  if (nodes.has(id)) return true;
1723
- issues.push(motionIssue(code, `There is no ${what} ${namedWithSuggestion(id, ids)} in the artwork${ids.length ? "" : " (it has no nodes yet)"}.`, { ...where, ids: [id] }));
1742
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, code, `There is no ${what} ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, ids)} in the artwork${ids.length ? "" : " (it has no nodes yet)"}.`, { ...where, ids: [id] }));
1724
1743
  return false;
1725
1744
  };
1726
1745
  scene.shots.forEach((shot, shotIndex2) => {
1727
1746
  if (shot.camera && "frame" in shot.camera && typeof shot.camera.frame === "string") known(shot.camera.frame, "unknown-frame", "node to frame", { shot: shot.id });
1728
1747
  else if (shot.camera) {
1729
1748
  const c = shot.camera;
1730
- if (!(c.width > 0 && c.height > 0)) issues.push(motionIssue("invalid-camera", `The camera needs a positive width and height (got ${c.width} \xD7 ${c.height}).`, { shot: shot.id }));
1749
+ if (!(c.width > 0 && c.height > 0)) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "invalid-camera", `The camera needs a positive width and height (got ${c.width} \xD7 ${c.height}).`, { shot: shot.id }));
1731
1750
  else if (Math.abs(c.width / c.height / artAspect - 1) > 0.02)
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 }));
1751
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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 }));
1733
1752
  }
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 }));
1753
+ if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
1735
1754
  shot.run.forEach((command3, i) => {
1736
1755
  const where = { shot: shot.id, command: i };
1737
1756
  if (command3.type === "wait") return;
1738
1757
  const targets = command3.targets.filter((id) => known(id, "unknown-target", "node", where));
1739
1758
  const timing = timeline.commands.find((c) => c.shot === shot.id && c.command === i);
1740
1759
  if (timing && timing.duration > 0 && timing.duration < MOTION_MIN_CHANGE_MS)
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 }));
1760
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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
1761
  if (command3.duration !== void 0 && command3.ease !== void 0) {
1743
1762
  const ease = _chunk2FHLHZALcjs.resolveEasing.call(void 0, command3.ease);
1744
1763
  if (ease !== "hold" && ease.type === "spring") {
1745
1764
  const settle = _chunk2FHLHZALcjs.springSettleMs.call(void 0, ease);
1746
1765
  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 }));
1766
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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 }));
1748
1767
  }
1749
1768
  }
1750
1769
  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] }));
1770
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
1752
1771
  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));
1772
+ if (command3.type !== "play" && command3.split) {
1773
+ for (const id of targets)
1774
+ if (!motionTextLayout(nodes, id))
1775
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "split-not-text", `"${id}" is not a group of letter paths, so "split": "${command3.split}" animates it as a whole; convert the text to outlines and group the letters (get_text_layout shows how they read).`, { ...where, ids: [id] }));
1776
+ }
1777
+ if (command3.type === "play" && !_optionalChain([scene, 'access', _87 => _87.clips, 'optionalAccess', _88 => _88[command3.clip]]))
1778
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-clip", `There is no clip ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
1755
1779
  if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
1756
1780
  const into = nodes.get(command3.into);
1757
1781
  for (const id of targets) {
1758
1782
  const entry = nodes.get(id);
1759
1783
  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] }));
1784
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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] }));
1761
1785
  continue;
1762
1786
  }
1763
1787
  const m = matchMotionNodes(entry.node, into.node);
1764
1788
  if (m.unpairedInto.length)
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 }));
1789
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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 }));
1766
1790
  }
1767
1791
  }
1768
1792
  const style = command3.type === "enter" || command3.type === "exit" ? command3.style : void 0;
1769
1793
  if (style === "wipe" || style === "iris" || style === "split") {
1770
1794
  for (const id of targets)
1771
1795
  if (!motionRevealPadding(nodes.get(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] }));
1796
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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] }));
1773
1797
  }
1774
1798
  if (command3.type === "style") {
1775
1799
  for (const key of ["fill", "stroke"]) {
1776
1800
  const color = command3[key];
1777
1801
  if (color === void 0) continue;
1778
1802
  if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) {
1779
- issues.push(motionIssue("invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1803
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1780
1804
  continue;
1781
1805
  }
1782
1806
  for (const id of targets) {
1783
1807
  const node = nodes.get(id).node;
1784
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
1808
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
1785
1809
  if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
1786
- issues.push(motionIssue("paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
1810
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
1787
1811
  }
1788
1812
  }
1789
1813
  }
1790
1814
  if (command3.type === "color-pulse") {
1791
1815
  const key = _nullishCoalesce(command3.paint, () => ( "fill"));
1792
1816
  const color = _nullishCoalesce(command3.color, () => ( "#f59e0b"));
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));
1817
+ if (_chunkA6PHCAGXcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1794
1818
  else
1795
1819
  for (const id of targets) {
1796
1820
  const node = nodes.get(id).node;
1797
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
1821
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
1798
1822
  if (paths.some((p) => typeof p[key] !== "string"))
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] }));
1823
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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] }));
1800
1824
  }
1801
1825
  }
1802
1826
  if (command3.type === "effect") {
@@ -1805,9 +1829,9 @@ function checkMotionScene(scene) {
1805
1829
  const params = NUMERIC_PARAMS(node, command3.effect);
1806
1830
  const effects = (_nullishCoalesce(node.effects, () => ( []))).map((e) => e.id);
1807
1831
  if (!params)
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] }));
1832
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-effect", `"${id}" has no effect ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
1809
1833
  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] }));
1834
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
1811
1835
  }
1812
1836
  }
1813
1837
  if (timing) {
@@ -1816,10 +1840,10 @@ function checkMotionScene(scene) {
1816
1840
  const before = Math.max(0, timing.start - 0.5);
1817
1841
  const visible = timing.start > 0 ? visibleAt(timeline, id, before, node) : node.visible !== false;
1818
1842
  if (command3.type === "enter" && visible && timing.start > 0)
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] }));
1843
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
1820
1844
  const probe = command3.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
1821
1845
  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] }));
1846
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
1823
1847
  }
1824
1848
  }
1825
1849
  });
@@ -1827,7 +1851,7 @@ function checkMotionScene(scene) {
1827
1851
  const drivers = _nullishCoalesce(scene.drivers, () => ( []));
1828
1852
  drivers.forEach((d, i) => {
1829
1853
  for (const id of [d.target, d.source.node])
1830
- if (!nodes.has(id)) issues.push(motionIssue("unknown-target", `Driver ${i + 1} names ${namedWithSuggestion(id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
1854
+ if (!nodes.has(id)) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-target", `Driver ${i + 1} names ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
1831
1855
  });
1832
1856
  {
1833
1857
  const key = (n, p) => `${n}.${p}`;
@@ -1844,20 +1868,20 @@ function checkMotionScene(scene) {
1844
1868
  return false;
1845
1869
  };
1846
1870
  for (const k of edges.keys()) if (visit(k, [])) break;
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]))] }));
1871
+ if (loop.length) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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]))] }));
1848
1872
  }
1849
1873
  for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
1850
1874
  for (const command3 of clip.run)
1851
1875
  if (command3.type !== "wait") {
1852
1876
  for (const id of command3.targets)
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] }));
1877
+ if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-target", `Clip "${name}" names ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
1854
1878
  }
1855
1879
  if (scene.trigger) {
1856
- if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(motionIssue("trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
1880
+ if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
1857
1881
  if (scene.trigger === "click") {
1858
- if (scene.shots.length === 1) issues.push(motionIssue("click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
1882
+ if (scene.shots.length === 1) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
1859
1883
  scene.shots.forEach((shot, i) => {
1860
- if (i > 0 && shot.at) issues.push(motionIssue("click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
1884
+ if (i > 0 && shot.at) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
1861
1885
  });
1862
1886
  }
1863
1887
  }
@@ -1865,11 +1889,11 @@ function checkMotionScene(scene) {
1865
1889
  if (!shot.at) return;
1866
1890
  const timing = timeline.shots[i];
1867
1891
  if (timing.cue === void 0) {
1868
- const what = shot.at.beat !== void 0 ? `beat ${shot.at.beat}, but the scene has no beat grid; set one with set_animation_settings ({ "beat": { "bpm": \u2026 } })` : `word ${shot.at.word}, but the narration has ${_nullishCoalesce(_optionalChain([scene, 'access', _81 => _81.narration, 'optionalAccess', _82 => _82.words, 'access', _83 => _83.length]), () => ( 0))} words (indexes from 0)`;
1869
- issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
1892
+ const what = shot.at.beat !== void 0 ? `beat ${shot.at.beat}, but the scene has no beat grid; set one with set_animation_settings ({ "beat": { "bpm": \u2026 } })` : `word ${shot.at.word}, but the narration has ${_nullishCoalesce(_optionalChain([scene, 'access', _89 => _89.narration, 'optionalAccess', _90 => _90.words, 'access', _91 => _91.length]), () => ( 0))} words (indexes from 0)`;
1893
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
1870
1894
  } else if (timing.missedBy !== void 0) {
1871
1895
  const late = Math.round(timing.missedBy);
1872
- issues.push(motionIssue("cue-missed", `Shot "${shot.id}" is cued at ${Math.round(timing.cue)} ms but starts ${late} ms late, because the shot before runs until ${Math.round(timing.start)} ms; shorten that shot (its hold, durations or speed) or cue this one later.`, { shot: shot.id, measured: late, needed: 0, unit: "ms" }));
1896
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "cue-missed", `Shot "${shot.id}" is cued at ${Math.round(timing.cue)} ms but starts ${late} ms late, because the shot before runs until ${Math.round(timing.start)} ms; shorten that shot (its hold, durations or speed) or cue this one later.`, { shot: shot.id, measured: late, needed: 0, unit: "ms" }));
1873
1897
  }
1874
1898
  });
1875
1899
  for (const [key, track] of timeline.tracks) {
@@ -1881,7 +1905,7 @@ function checkMotionScene(scene) {
1881
1905
  const property = key.split("\0")[1];
1882
1906
  if (!a.node) continue;
1883
1907
  issues.push(
1884
- motionIssue("overlap", `"${a.node}" ${property} is changed by two commands at once (shot "${a.shot}" command ${a.command + 1} and shot "${b.shot}" command ${b.command + 1}); the later one takes over. Start it after the first ends, or use with: "after".`, {
1908
+ _chunkWAJQKWQUcjs.motionIssue.call(void 0, "overlap", `"${a.node}" ${property} is changed by two commands at once (shot "${a.shot}" command ${a.command + 1} and shot "${b.shot}" command ${b.command + 1}); the later one takes over. Start it after the first ends, or use with: "after".`, {
1885
1909
  shot: b.shot,
1886
1910
  command: b.command,
1887
1911
  ids: [a.node]
@@ -1898,26 +1922,26 @@ function checkMotionScene(scene) {
1898
1922
  const cam = frame.camera;
1899
1923
  const docIndex = indexMotionNodes(frame.document.nodes);
1900
1924
  for (const id of command3.targets) {
1901
- const b = _optionalChain([docIndex, 'access', _84 => _84.get, 'call', _85 => _85(id), 'optionalAccess', _86 => _86.bounds]);
1925
+ const b = _optionalChain([docIndex, 'access', _92 => _92.get, 'call', _93 => _93(id), 'optionalAccess', _94 => _94.bounds]);
1902
1926
  if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
1903
1927
  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;
1904
1928
  if (outside) {
1905
1929
  reported.add(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] }));
1930
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "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] }));
1907
1931
  }
1908
1932
  }
1909
1933
  }
1910
1934
  if (scene.controls) {
1911
1935
  for (const control of scene.controls) {
1912
1936
  if (!usesColor(scene, control.default))
1913
- issues.push(motionIssue("unknown-control-color", `Control "${control.name}" stands for ${control.default}, which the scene never uses; set its default to a colour in the artwork.`));
1937
+ issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "unknown-control-color", `Control "${control.name}" stands for ${control.default}, which the scene never uses; set its default to a colour in the artwork.`));
1914
1938
  }
1915
1939
  }
1916
1940
  if (scene.target && scene.shots.length) {
1917
1941
  const seconds = Math.round(timeline.duration / 100) / 10;
1918
1942
  const [min, max] = scene.target;
1919
- if (seconds > max) issues.push(motionIssue("scene-too-long", `The scene runs ${seconds} s, past its ${max} s target; shorten holds or durations, or fit it (fit_animation).`, { measured: seconds, needed: max, unit: "s" }));
1920
- if (seconds < min) issues.push(motionIssue("scene-too-short", `The scene runs ${seconds} s, under its ${min} s target; hold longer, add shots, or fit it (fit_animation).`, { measured: seconds, needed: min, unit: "s" }));
1943
+ if (seconds > max) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "scene-too-long", `The scene runs ${seconds} s, past its ${max} s target; shorten holds or durations, or fit it (fit_animation).`, { measured: seconds, needed: max, unit: "s" }));
1944
+ if (seconds < min) issues.push(_chunkWAJQKWQUcjs.motionIssue.call(void 0, "scene-too-short", `The scene runs ${seconds} s, under its ${min} s target; hold longer, add shots, or fit it (fit_animation).`, { measured: seconds, needed: min, unit: "s" }));
1921
1945
  }
1922
1946
  return issues;
1923
1947
  }
@@ -1946,7 +1970,7 @@ var fail = (message) => {
1946
1970
  };
1947
1971
  function shotIndex(scene, id) {
1948
1972
  const i = scene.shots.findIndex((s) => s.id === id);
1949
- if (i < 0) fail(`There is no shot ${namedWithSuggestion(id, scene.shots.map((s) => s.id))}; the shots are ${scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
1973
+ if (i < 0) fail(`There is no shot ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, scene.shots.map((s) => s.id))}; the shots are ${scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
1950
1974
  return i;
1951
1975
  }
1952
1976
  function position(at, length, what) {
@@ -2004,7 +2028,7 @@ function applyOne(scene, edit) {
2004
2028
  if (typeof edit.name !== "string" || !edit.name) fail('Give the clip a "name".');
2005
2029
  const clips = { ..._nullishCoalesce(scene.clips, () => ( {})) };
2006
2030
  if (edit.clip === null) {
2007
- if (!clips[edit.name]) fail(`There is no clip ${namedWithSuggestion(edit.name, Object.keys(clips))} to delete.`);
2031
+ if (!clips[edit.name]) fail(`There is no clip ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, edit.name, Object.keys(clips))} to delete.`);
2008
2032
  const playing = scene.shots.filter((s) => s.run.some((c) => c.type === "play" && c.clip === edit.name)).map((s) => `"${s.id}"`);
2009
2033
  if (playing.length) fail(`Clip "${edit.name}" is played in shot${playing.length > 1 ? "s" : ""} ${playing.join(", ")}; remove those play commands first.`);
2010
2034
  delete clips[edit.name];
@@ -2110,7 +2134,7 @@ function applyOne(scene, edit) {
2110
2134
  const names = new Set(edit.controls.map((c) => c.name));
2111
2135
  for (const preset2 of _nullishCoalesce(next.presets, () => ( [])))
2112
2136
  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.`);
2137
+ if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, key, names)}, which is not a control.`);
2114
2138
  return next;
2115
2139
  }
2116
2140
  case "replace_scene":
@@ -2118,11 +2142,11 @@ function applyOne(scene, edit) {
2118
2142
  }
2119
2143
  }
2120
2144
  function errorKeys(issues) {
2121
- return new Set(issues.filter((i) => i.severity === "error").map(motionIssueKey));
2145
+ return new Set(issues.filter((i) => i.severity === "error").map(_chunkWAJQKWQUcjs.motionIssueKey));
2122
2146
  }
2123
2147
  function editHints(before, after) {
2124
- const old = new Set(before.map(motionIssueKey));
2125
- return after.filter((i) => i.code === "overlap" && !old.has(motionIssueKey(i))).map(motionIssueLine);
2148
+ const old = new Set(before.map(_chunkWAJQKWQUcjs.motionIssueKey));
2149
+ return after.filter((i) => i.code === "overlap" && !old.has(_chunkWAJQKWQUcjs.motionIssueKey.call(void 0, i))).map(_chunkWAJQKWQUcjs.motionIssueLine);
2126
2150
  }
2127
2151
  function applyMotionEdits(scene, edits) {
2128
2152
  const list = Array.isArray(edits) ? edits : [edits];
@@ -2130,9 +2154,9 @@ function applyMotionEdits(scene, edits) {
2130
2154
  let next = scene;
2131
2155
  for (let i = 0; i < list.length; i++) {
2132
2156
  const edit = list[i];
2133
- const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _87 => _87.op])}): ` : "";
2157
+ const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _95 => _95.op])}): ` : "";
2134
2158
  if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
2135
- return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _88 => _88.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
2159
+ return { ok: false, error: `${prefix}Unknown op ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, String(_optionalChain([edit, 'optionalAccess', _96 => _96.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
2136
2160
  try {
2137
2161
  next = applyOne(next, edit);
2138
2162
  } catch (error) {
@@ -2144,8 +2168,8 @@ function applyMotionEdits(scene, edits) {
2144
2168
  }
2145
2169
  const issues = checkMotionScene(next);
2146
2170
  const had = errorKeys(before);
2147
- const added = issues.filter((i) => i.severity === "error" && !had.has(motionIssueKey(i)));
2148
- if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(motionIssueLine).join(" ")}` };
2171
+ const added = issues.filter((i) => i.severity === "error" && !had.has(_chunkWAJQKWQUcjs.motionIssueKey.call(void 0, i)));
2172
+ if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(_chunkWAJQKWQUcjs.motionIssueLine).join(" ")}` };
2149
2173
  return { ok: true, scene: next, issues, hints: editHints(before, issues) };
2150
2174
  }
2151
2175
  var REF = /^\$(\d+|last)((?:\.[A-Za-z_]\w*|\[\d+\])+)$/;
@@ -2154,7 +2178,7 @@ function resolveMotionEditRefs(scene, edits) {
2154
2178
  const resolved = [];
2155
2179
  let next = scene;
2156
2180
  for (let i = 0; i < edits.length; i++) {
2157
- const where = `op ${i + 1} (${_optionalChain([edits, 'access', _89 => _89[i], 'optionalAccess', _90 => _90.op])})`;
2181
+ const where = `op ${i + 1} (${_optionalChain([edits, 'access', _97 => _97[i], 'optionalAccess', _98 => _98.op])})`;
2158
2182
  let problem = null;
2159
2183
  const walk = (v) => {
2160
2184
  if (typeof v === "string") {
@@ -2187,9 +2211,9 @@ function resolveMotionEditRefs(scene, edits) {
2187
2211
  resolved.push(edit);
2188
2212
  const out = { op: edit.op };
2189
2213
  if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
2190
- if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _91 => _91.set, 'optionalAccess', _92 => _92.id]) ? edit.set.id : edit.shot;
2214
+ if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _99 => _99.set, 'optionalAccess', _100 => _100.id]) ? edit.set.id : edit.shot;
2191
2215
  if (edit.op === "add_commands") {
2192
- const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _93 => _93.shots, 'access', _94 => _94.find, 'call', _95 => _95((s) => s.id === edit.shot), 'optionalAccess', _96 => _96.run, 'access', _97 => _97.length]))), () => ( 0));
2216
+ const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _101 => _101.shots, 'access', _102 => _102.find, 'call', _103 => _103((s) => s.id === edit.shot), 'optionalAccess', _104 => _104.run, 'access', _105 => _105.length]))), () => ( 0));
2193
2217
  out.indexes = edit.commands.map((_, k) => at + k);
2194
2218
  }
2195
2219
  if (edit.op === "move_command") out.indexes = [edit.to];
@@ -2208,7 +2232,7 @@ function fitMotionScene(scene, ms, options = {}) {
2208
2232
  if (!(Number.isFinite(ms) && ms > 0)) throw new Error("Give the length to fit as a number of milliseconds above 0.");
2209
2233
  const ids = scene.shots.map((s) => s.id);
2210
2234
  const keep = new Set(_nullishCoalesce(options.keep, () => ( [])));
2211
- for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${namedWithSuggestion(id, ids)} to keep.`);
2235
+ for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, ids)} to keep.`);
2212
2236
  const timeline = compileMotionScene(scene);
2213
2237
  let kept = 0;
2214
2238
  let rest = 0;
@@ -2342,13 +2366,13 @@ function toFlairSvgMotion(scene, options = {}) {
2342
2366
  if (!route) continue;
2343
2367
  const routeId = freshId(`${id}--follow-route`);
2344
2368
  ids.set(seg.path, routeId);
2345
- routes.push(`<path id="${routeId}" d="${_chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
2369
+ routes.push(`<path id="${routeId}" d="${_chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
2346
2370
  }
2347
2371
  if (ids.size) {
2348
2372
  const wrapper = freshId(`${id}--follow`);
2349
2373
  const centre = freshId(`${id}--follow-centre`);
2350
2374
  const c = entry.center;
2351
- const at = _optionalChain([motionNodeOffset, 'call', _98 => _98(entry, timeline, 0, nodes), 'optionalAccess', _99 => _99.follow]);
2375
+ const at = _optionalChain([motionNodeOffset, 'call', _106 => _106(entry, timeline, 0, nodes), 'optionalAccess', _107 => _107.follow]);
2352
2376
  const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
2353
2377
  (wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
2354
2378
  follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
@@ -2378,7 +2402,7 @@ function toFlairSvgMotion(scene, options = {}) {
2378
2402
  raw: (t) => transformAt(t, true)
2379
2403
  });
2380
2404
  }
2381
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
2405
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
2382
2406
  for (const path of paths) {
2383
2407
  if (pathsSeen.has(path.id)) continue;
2384
2408
  pathsSeen.add(path.id);
@@ -2400,7 +2424,7 @@ function toFlairSvgMotion(scene, options = {}) {
2400
2424
  if (shapeSegments.length) {
2401
2425
  if (node.type !== "path") notes.push(`"${id}" is a group: its morph or effect animation is not exported (Flair tweens one path's "d").`);
2402
2426
  else {
2403
- const inverse = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, node));
2427
+ const inverse = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node));
2404
2428
  channels.push({
2405
2429
  id,
2406
2430
  kind: "attr",
@@ -2409,10 +2433,10 @@ function toFlairSvgMotion(scene, options = {}) {
2409
2433
  exact: () => false,
2410
2434
  value: (t) => {
2411
2435
  const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
2412
- const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _100 => _100(frame.document.nodes), 'access', _101 => _101.get, 'call', _102 => _102(id), 'optionalAccess', _103 => _103.node]));
2436
+ const now = _chunk7MD7C6XQcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _108 => _108(frame.document.nodes), 'access', _109 => _109.get, 'call', _110 => _110(id), 'optionalAccess', _111 => _111.node]));
2413
2437
  if (!now || now.type !== "path") return "";
2414
- const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
2415
- return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
2438
+ const bezier = _chunkXGD3FSNCcjs.transformBezierPath.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, now, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, { effects: false }), inverse);
2439
+ return _chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
2416
2440
  }
2417
2441
  });
2418
2442
  }
@@ -2430,8 +2454,8 @@ function toFlairSvgMotion(scene, options = {}) {
2430
2454
  ...delay > 0 ? { delay: round2(delay) } : {},
2431
2455
  ms: round2(ms),
2432
2456
  ease: written,
2433
- ..._optionalChain([segment, 'optionalAccess', _104 => _104.behavior]) ? { behavior: segment.behavior } : {},
2434
- ..._optionalChain([segment, 'optionalAccess', _105 => _105.steps]) ? { strobe: segment.steps } : {}
2457
+ ..._optionalChain([segment, 'optionalAccess', _112 => _112.behavior]) ? { behavior: segment.behavior } : {},
2458
+ ..._optionalChain([segment, 'optionalAccess', _113 => _113.steps]) ? { strobe: segment.steps } : {}
2435
2459
  };
2436
2460
  if (channel.kind === "view") animate.push({ ...base, view: to });
2437
2461
  else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
@@ -2518,10 +2542,10 @@ function toFlairSvgMotion(scene, options = {}) {
2518
2542
  }
2519
2543
  if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
2520
2544
  if (trigger && (_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") notes.push(`The scene plays on ${trigger}, so its loop does not apply in Flair.`);
2521
- let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
2545
+ let svg = _chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
2522
2546
  if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
2523
2547
  let motion = { svg, animate };
2524
- if (_optionalChain([scene, 'access', _106 => _106.controls, 'optionalAccess', _107 => _107.length])) {
2548
+ if (_optionalChain([scene, 'access', _114 => _114.controls, 'optionalAccess', _115 => _115.length])) {
2525
2549
  const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
2526
2550
  const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
2527
2551
  svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
@@ -2543,7 +2567,7 @@ function toFlairVectorEffect(scene, options = {}) {
2543
2567
  tags: _nullishCoalesce(options.tags, () => ( [])),
2544
2568
  motion: out.motion,
2545
2569
  hold: out.hold,
2546
- ..._optionalChain([scene, 'access', _108 => _108.presets, 'optionalAccess', _109 => _109.length]) ? { presets: scene.presets } : {},
2570
+ ..._optionalChain([scene, 'access', _116 => _116.presets, 'optionalAccess', _117 => _117.length]) ? { presets: scene.presets } : {},
2547
2571
  ...out.trigger ? { trigger: out.trigger } : {}
2548
2572
  };
2549
2573
  }
@@ -2587,7 +2611,7 @@ function resolvePlaceholders(motion, notes) {
2587
2611
  const filled = text.replace(PLACEHOLDER, (_, name) => {
2588
2612
  const d = declared.get(name);
2589
2613
  if (!d) unknown.add(name);
2590
- return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _110 => _110.value]), () => ( ""))).replace(/"/g, '\\"');
2614
+ return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _118 => _118.value]), () => ( ""))).replace(/"/g, '\\"');
2591
2615
  });
2592
2616
  for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
2593
2617
  return { motion: JSON.parse(filled), controls };
@@ -2602,14 +2626,14 @@ function easingOf(ease, fallback) {
2602
2626
  return fallback;
2603
2627
  }
2604
2628
  function poseOf(value, entry) {
2605
- const t = _chunkYJLCBA7Vcjs.parseSvgTransform.call(void 0, String(value));
2606
- const o = _chunkYJLCBA7Vcjs.multiplyMatrices.call(void 0, _nullishCoalesce(_chunkYJLCBA7Vcjs.invertMatrix.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, entry.node)), () => ( [1, 0, 0, 1, 0, 0])), t);
2629
+ const t = _chunk7MD7C6XQcjs.parseSvgTransform.call(void 0, String(value));
2630
+ const o = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _nullishCoalesce(_chunk7MD7C6XQcjs.invertMatrix.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, entry.node)), () => ( [1, 0, 0, 1, 0, 0])), t);
2607
2631
  const sx = Math.hypot(o[0], o[1]);
2608
2632
  if (!(sx > 1e-9)) return null;
2609
2633
  const sy = (o[0] * o[3] - o[1] * o[2]) / sx;
2610
2634
  if (Math.abs(o[2] + o[1] / sx * sy) > 1e-6 || Math.abs(o[3] - o[0] / sx * sy) > 1e-6) return null;
2611
2635
  const c = entry.center;
2612
- const moved = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, o, c);
2636
+ const moved = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, o, c);
2613
2637
  return { dx: moved.x - c.x, dy: moved.y - c.y, rotation: Math.atan2(o[1], o[0]) * 180 / Math.PI, sx, sy };
2614
2638
  }
2615
2639
  var near = (a, b, eps = 1e-6) => Math.abs(a - b) < eps;
@@ -2641,7 +2665,7 @@ function commandsFor(anim, nodes, entered, notes) {
2641
2665
  if (anim.along) {
2642
2666
  const path = nodes.get(anim.along);
2643
2667
  if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
2644
- else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _111 => _111.at, 'optionalAccess', _112 => _112[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _113 => _113.at, 'optionalAccess', _114 => _114[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2668
+ else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _119 => _119.at, 'optionalAccess', _120 => _120[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _121 => _121.at, 'optionalAccess', _122 => _122[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2645
2669
  }
2646
2670
  for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
2647
2671
  if (attr === "opacity") {
@@ -2652,7 +2676,7 @@ function commandsFor(anim, nodes, entered, notes) {
2652
2676
  out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
2653
2677
  } else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
2654
2678
  } else if (attr === "fill" || attr === "stroke") {
2655
- if (_optionalChain([behavior, 'optionalAccess', _115 => _115.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2679
+ if (_optionalChain([behavior, 'optionalAccess', _123 => _123.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2656
2680
  else {
2657
2681
  if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
2658
2682
  out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
@@ -2694,7 +2718,7 @@ function fromFlairSvgMotion(input, options = {}) {
2694
2718
  const notes = [];
2695
2719
  if (!input || typeof input.svg !== "string") throw new Error('Give a Flair SvgMotion: { svg: "<svg \u2026>", animate: [ \u2026 ] }.');
2696
2720
  const { motion, controls } = resolvePlaceholders(input, notes);
2697
- const artwork = _chunkYJLCBA7Vcjs.parseVectorSvg.call(void 0, motion.svg);
2721
+ const artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, motion.svg);
2698
2722
  const nodes = indexMotionNodes(artwork.nodes);
2699
2723
  const byStep = /* @__PURE__ */ new Map();
2700
2724
  for (const anim of _nullishCoalesce(motion.animate, () => ( []))) {
@@ -2941,11 +2965,11 @@ function toLottie(scene, options = {}) {
2941
2965
  const items = [];
2942
2966
  const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
2943
2967
  const geometryAt = (t) => {
2944
- if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
2945
- const now = _optionalChain([indexMotionNodes, 'call', _116 => _116(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _117 => _117.get, 'call', _118 => _118(path.id), 'optionalAccess', _119 => _119.node]);
2946
- return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
2968
+ if (!shapeSegments.length) return _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
2969
+ const now = _optionalChain([indexMotionNodes, 'call', _124 => _124(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _125 => _125.get, 'call', _126 => _126(path.id), 'optionalAccess', _127 => _127.node]);
2970
+ return now && now.type === "path" ? _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
2947
2971
  };
2948
- const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
2972
+ const rest = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
2949
2973
  rest.forEach((contour, n) => {
2950
2974
  let ks = { a: 0, k: contour };
2951
2975
  if (shapeSegments.length) {
@@ -2954,7 +2978,7 @@ function toLottie(scene, options = {}) {
2954
2978
  const count = Math.max(1, Math.ceil(end * fps / 1e3));
2955
2979
  for (let k = 0; k <= count && fits; k++) {
2956
2980
  const t = end * k / count;
2957
- const c = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(t)), round2)[n];
2981
+ const c = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(t)), round2)[n];
2958
2982
  if (!c || c.v.length !== contour.v.length || c.c !== contour.c) fits = false;
2959
2983
  else keys.push({ t: frame(t), s: [c], ...k < count ? { o: { x: [0], y: [0] }, i: { x: [1], y: [1] } } : {} });
2960
2984
  }
@@ -2990,7 +3014,7 @@ function toLottie(scene, options = {}) {
2990
3014
  lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
2991
3015
  ml: 4
2992
3016
  });
2993
- if (_optionalChain([path, 'access', _120 => _120.strokeDasharray, 'optionalAccess', _121 => _121.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
3017
+ if (_optionalChain([path, 'access', _128 => _128.strokeDasharray, 'optionalAccess', _129 => _129.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
2994
3018
  if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
2995
3019
  }
2996
3020
  const fill = paintOf(path.fill, "fill", path.id);
@@ -3017,8 +3041,8 @@ function toLottie(scene, options = {}) {
3017
3041
  if (node.type === "path") inner = [...pathShapes(node)];
3018
3042
  else {
3019
3043
  inner = shown(node.children).reverse().map(nodeGroup);
3020
- const m = _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, node);
3021
- if (m !== _chunkYJLCBA7Vcjs.IDENTITY_MATRIX) {
3044
+ const m = _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node);
3045
+ if (m !== _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
3022
3046
  const parts = staticParts(m);
3023
3047
  if (!parts) notes.push(`"${node.id}": its transform skews, which is not exported; it is drawn without the skew.`);
3024
3048
  else {
@@ -3031,7 +3055,7 @@ function toLottie(scene, options = {}) {
3031
3055
  const body = { ty: "gr", nm: `${node.id} (own)`, it: [...inner, innerTr] };
3032
3056
  return { ty: "gr", nm: _nullishCoalesce(node.name, () => ( node.id)), it: [body, poseTransform(entry)] };
3033
3057
  };
3034
- const artwork = { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
3058
+ const artwork = { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
3035
3059
  const content = shown(artwork.nodes).reverse().map(nodeGroup);
3036
3060
  if (artwork.background && rgba(artwork.background))
3037
3061
  content.push({ ty: "gr", nm: "Background", it: [{ ty: "rc", nm: "Background", p: { a: 0, k: [artwork.width / 2, artwork.height / 2] }, s: { a: 0, k: [artwork.width, artwork.height] }, r: { a: 0, k: 0 } }, { ty: "fl", c: { a: 0, k: rgba(artwork.background).map(round2) }, o: { a: 0, k: 100 }, r: 1 }, STATIC_TR()] });
@@ -3080,7 +3104,7 @@ var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName
3080
3104
  var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
3081
3105
  var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
3082
3106
  var num = (el, attr, fallback = 0) => {
3083
- const v = _optionalChain([el, 'optionalAccess', _122 => _122.getAttribute, 'call', _123 => _123(attr)]);
3107
+ const v = _optionalChain([el, 'optionalAccess', _130 => _130.getAttribute, 'call', _131 => _131(attr)]);
3084
3108
  const n = v === null || v === void 0 ? NaN : Number(v);
3085
3109
  return Number.isFinite(n) ? n : fallback;
3086
3110
  };
@@ -3130,11 +3154,11 @@ function preset(prst, w, h) {
3130
3154
  const poly = (pts) => [{ closed: true, anchors: pts.map(([x, y]) => ({ x, y })) }];
3131
3155
  switch (prst) {
3132
3156
  case "rect":
3133
- return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3157
+ return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3134
3158
  case "roundRect":
3135
- return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
3159
+ return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
3136
3160
  case "ellipse":
3137
- return [_chunkYJLCBA7Vcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3161
+ return [_chunk7MD7C6XQcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3138
3162
  case "triangle":
3139
3163
  return poly([[w / 2, 0], [w, h], [0, h]]);
3140
3164
  case "rtTriangle":
@@ -3188,8 +3212,8 @@ function placement(xfrm, map) {
3188
3212
  const ext = kid(xfrm, "ext");
3189
3213
  const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
3190
3214
  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;
3215
+ const fx = _optionalChain([xfrm, 'optionalAccess', _132 => _132.getAttribute, 'call', _133 => _133("flipH")]) === "1" ? -1 : 1;
3216
+ const fy = _optionalChain([xfrm, 'optionalAccess', _134 => _134.getAttribute, 'call', _135 => _135("flipV")]) === "1" ? -1 : 1;
3193
3217
  const cx = x + w / 2;
3194
3218
  const cy = y + h / 2;
3195
3219
  const cos = Math.cos(rot);
@@ -3216,7 +3240,7 @@ function shapes(ctx, tree, map) {
3216
3240
  const nv = el.firstElementChild;
3217
3241
  const cNvPr = kid(nv, "cNvPr");
3218
3242
  const spid = num(cNvPr, "id", -1);
3219
- const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _128 => _128.getAttribute, 'call', _129 => _129("name")]), () => ( ""));
3243
+ const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _136 => _136.getAttribute, 'call', _137 => _137("name")]), () => ( ""));
3220
3244
  if (el.localName === "grpSp") {
3221
3245
  const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
3222
3246
  const off = kid(xfrm, "off");
@@ -3237,12 +3261,12 @@ function shapes(ctx, tree, map) {
3237
3261
  if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
3238
3262
  const spPr = kid(el, "spPr");
3239
3263
  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")]);
3264
+ const prst = _optionalChain([kid, 'call', _138 => _138(spPr, "prstGeom"), 'optionalAccess', _139 => _139.getAttribute, 'call', _140 => _140("prst")]);
3241
3265
  const cust = kid(spPr, "custGeom");
3242
3266
  let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
3243
3267
  if (!subpaths) {
3244
3268
  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 })];
3269
+ subpaths = [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3246
3270
  }
3247
3271
  const style = kid(el, "style");
3248
3272
  const fill = kid(spPr, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(spPr, "solidFill")), () => ( (el.localName === "cxnSp" ? null : colour(ctx, kid(style, "fillRef")))));
@@ -3351,13 +3375,13 @@ function command(ctx, ctn, scene, artwork, target, hidden) {
3351
3375
  }
3352
3376
  if (cls === "path") {
3353
3377
  const motion = deep(ctn, "animMotion")[0];
3354
- const d = _optionalChain([motion, 'optionalAccess', _133 => _133.getAttribute, 'call', _134 => _134("path")]);
3378
+ const d = _optionalChain([motion, 'optionalAccess', _141 => _141.getAttribute, 'call', _142 => _142("path")]);
3355
3379
  if (!d) return null;
3356
3380
  const entry = artwork.flatMap(function all(n) {
3357
3381
  return n.type === "group" ? [n, ...n.children.flatMap(all)] : [n];
3358
3382
  }).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;
3383
+ const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _143 => _143.transform]), () => ( [1, 0, 0, 1, 0, 0]));
3384
+ const p = _optionalChain([entry, 'optionalAccess', _144 => _144.type]) === "path" ? _optionalChain([entry, 'access', _145 => _145.subpaths, 'access', _146 => _146[0], 'optionalAccess', _147 => _147.anchors]) : void 0;
3361
3385
  const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
3362
3386
  const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
3363
3387
  const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
@@ -3409,9 +3433,9 @@ async function fromPptxAnimation(data, options = {}) {
3409
3433
  if (!path.includes("theme/")) continue;
3410
3434
  const theme = await xml(ctx, path);
3411
3435
  const scheme = deep(theme, "clrScheme")[0];
3412
- for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _140 => _140.children]), () => ( [])))) {
3436
+ for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _148 => _148.children]), () => ( [])))) {
3413
3437
  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")]);
3438
+ const hex = _optionalChain([v, 'optionalAccess', _149 => _149.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _150 => _150.getAttribute, 'call', _151 => _151("lastClr")]);
3415
3439
  if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
3416
3440
  }
3417
3441
  break;
@@ -3518,7 +3542,7 @@ var AnimationEditorController = (_class = class {
3518
3542
  time: p.time,
3519
3543
  playing: p.playing,
3520
3544
  loop: p.loop,
3521
- currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _144 => _144(timeline, p.time), 'optionalAccess', _145 => _145.id]), () => ( null)),
3545
+ currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _152 => _152(timeline, p.time), 'optionalAccess', _153 => _153.id]), () => ( null)),
3522
3546
  selection: this.selection,
3523
3547
  readOnly: this.readOnly,
3524
3548
  error: this.error,
@@ -3557,7 +3581,7 @@ var AnimationEditorController = (_class = class {
3557
3581
  this.applying = false;
3558
3582
  }
3559
3583
  this.notify();
3560
- _optionalChain([this, 'access', _146 => _146.onChange, 'optionalCall', _147 => _147(scene)]);
3584
+ _optionalChain([this, 'access', _154 => _154.onChange, 'optionalCall', _155 => _155(scene)]);
3561
3585
  }
3562
3586
  commit(label, next) {
3563
3587
  const before = this.scene;
@@ -3730,6 +3754,8 @@ var BASE = {
3730
3754
  with: { type: "string", enum: ["after", "previous"], description: '"after" (default) starts when the commands before it finish; "previous" starts together with the command before.' },
3731
3755
  ease: EASE,
3732
3756
  note: { type: "string", description: "Why this command is here, in a few words." },
3757
+ split: { type: "string", enum: ["letter", "word", "line"], description: "For outlined text (a group of letter paths): animate it a letter, word or line at a time in reading order, staggered (default 40 ms a letter, 120 a word, 300 a line). get_text_layout shows the units." },
3758
+ cascade: { type: "string", enum: ["forward", "backward", "center", "edges", "random"], description: "With split: the order units go in (default forward; random is the same every time)." },
3733
3759
  repeat: { type: "integer", minimum: 1, maximum: 1e3, description: 'Play it this many times (default 1); "duration" is one cycle. Not for enter or exit.' },
3734
3760
  repeatMode: { type: "string", enum: [...MOTION_REPEAT_MODES], description: "loop (default) restarts each cycle, mirror plays every other one backwards, offset carries on from where the last ended (rotate by 90 with repeat 4 makes a full turn)." },
3735
3761
  steps: { type: "number", exclusiveMinimum: 0, maximum: 120, description: `Stepped time: hold on a grid of this many frames per second (12 = "on twos"). Default: the scene's steps, else smooth.` }
@@ -3962,7 +3988,7 @@ var issueSummary = (issues) => ({
3962
3988
  errors: issues.filter((i) => i.severity === "error").length,
3963
3989
  warnings: issues.filter((i) => i.severity === "warning").length,
3964
3990
  notes: issues.filter((i) => i.severity === "note").length,
3965
- lines: issues.map((i) => `${i.severity}: ${motionIssueLine(i)}`)
3991
+ lines: issues.map((i) => `${i.severity}: ${_chunkWAJQKWQUcjs.motionIssueLine.call(void 0, i)}`)
3966
3992
  });
3967
3993
  function createAnimationEditorToolProvider(controller, options = {}) {
3968
3994
  const readOnlyReason = () => {
@@ -4084,7 +4110,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4084
4110
  }
4085
4111
  if (Array.isArray(motion_paths)) {
4086
4112
  const known = new Set(describeMotionElements(s).map((e) => e.id));
4087
- for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${namedWithSuggestion(id, known)} to draw a motion path for.`);
4113
+ for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, known)} to draw a motion path for.`);
4088
4114
  }
4089
4115
  const overlays = { ...onion_skin ? { onionSkin: onion_skin } : {}, ...motion_paths ? { motionPaths: motion_paths } : {} };
4090
4116
  if (times) {
@@ -4122,9 +4148,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4122
4148
  handler: ({ from = 0, to, limit = 200 }) => {
4123
4149
  const s = scene();
4124
4150
  const timeline = compileMotionScene(s);
4125
- const words = _nullishCoalesce(_optionalChain([s, 'access', _148 => _148.narration, 'optionalAccess', _149 => _149.words]), () => ( []));
4151
+ const words = _nullishCoalesce(_optionalChain([s, 'access', _156 => _156.narration, 'optionalAccess', _157 => _157.words]), () => ( []));
4126
4152
  const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
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]);
4153
+ const shotAt = (ms) => _optionalChain([timeline, 'access', _158 => _158.shots, 'access', _159 => _159.find, 'call', _160 => _160((x) => ms >= x.start && ms < x.end), 'optionalAccess', _161 => _161.id]);
4128
4154
  const beats = [];
4129
4155
  if (s.beat && s.beat.bpm > 0) {
4130
4156
  const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
@@ -4145,6 +4171,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4145
4171
  };
4146
4172
  }
4147
4173
  };
4174
+ const getTextLayout = {
4175
+ name: "get_text_layout",
4176
+ title: "Read outlined text as letters, words and lines",
4177
+ description: 'Returns how a group of letter paths (text converted to outlines) reads: its lines, each a list of words, each a list of letter ids, in reading order \u2014 the units a command with "split": "letter" | "word" | "line" animates. Errors if the element is not a group with paths.',
4178
+ inputSchema: object({ group: { type: "string", minLength: 1, description: "Element id of the group of letters." } }, ["group"]),
4179
+ annotations: { title: "Read outlined text as letters, words and lines", ...READ },
4180
+ handler: ({ group }) => {
4181
+ const s = scene();
4182
+ const nodes = indexMotionNodes(s.artwork.nodes);
4183
+ if (!nodes.has(group)) throw new Error(`There is no element ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, group, [...nodes.keys()])}.`);
4184
+ const layout = motionTextLayout(nodes, group);
4185
+ if (!layout) throw new Error(`"${group}" is not a group of paths; convert the text to outlines (one path a letter) and group it.`);
4186
+ return { group, letters: layout.lines.reduce((n, l) => n + l.words.reduce((m, w) => m + w.letters.length, 0), 0), ...layout };
4187
+ }
4188
+ };
4148
4189
  const getMotionPath = {
4149
4190
  name: "get_motion_path",
4150
4191
  title: "Read where a node travels",
@@ -4159,7 +4200,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4159
4200
  handler: ({ node, from, to, step }) => {
4160
4201
  const s = scene();
4161
4202
  const ids = describeMotionElements(s).map((e) => e.id);
4162
- if (!ids.includes(node)) throw new Error(`There is no element ${namedWithSuggestion(node, ids)}.`);
4203
+ if (!ids.includes(node)) throw new Error(`There is no element ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, node, ids)}.`);
4163
4204
  return motionPath(s, node, { from, to, step });
4164
4205
  }
4165
4206
  };
@@ -4210,7 +4251,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4210
4251
  handler: ({ svg }) => {
4211
4252
  let artwork;
4212
4253
  try {
4213
- artwork = _chunkYJLCBA7Vcjs.parseVectorSvg.call(void 0, svg);
4254
+ artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, svg);
4214
4255
  } catch (error) {
4215
4256
  throw new Error(`The SVG could not be read: ${error.message}. Nothing was changed.`);
4216
4257
  }
@@ -4357,11 +4398,11 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4357
4398
  handler: ({ from, to, shots, stagger }) => {
4358
4399
  const s = scene();
4359
4400
  const ids = describeMotionElements(s).map((e) => e.id);
4360
- for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${namedWithSuggestion(id, ids)}. Nothing was changed.`);
4401
+ for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, ids)}. Nothing was changed.`);
4361
4402
  if (to.includes(from)) throw new Error(`"to" includes "${from}" itself; give other elements. Nothing was changed.`);
4362
4403
  const only = shots ? new Set(shots) : null;
4363
4404
  if (only) {
4364
- for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${namedWithSuggestion(id, s.shots.map((x) => x.id))}. Nothing was changed.`);
4405
+ for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${_chunkWAJQKWQUcjs.namedWithSuggestion.call(void 0, id, s.shots.map((x) => x.id))}. Nothing was changed.`);
4365
4406
  }
4366
4407
  const copied = {};
4367
4408
  const edits = [];
@@ -4431,7 +4472,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4431
4472
  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"]),
4432
4473
  annotations: { title: "Add commands to a shot", ...WRITE },
4433
4474
  handler: ({ shot, commands, at }) => {
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));
4475
+ const before = _nullishCoalesce(_optionalChain([scene, 'call', _162 => _162(), 'access', _163 => _163.shots, 'access', _164 => _164.find, 'call', _165 => _165((s) => s.id === shot), 'optionalAccess', _166 => _166.run, 'access', _167 => _167.length]), () => ( 0));
4435
4476
  const first = _nullishCoalesce(at, () => ( before));
4436
4477
  return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
4437
4478
  const shots = describeMotionShots(s);
@@ -4562,7 +4603,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4562
4603
  return { redone, ...redone ? { label } : {} };
4563
4604
  }
4564
4605
  };
4565
- const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
4606
+ const reads = [getAnimation, getShot, findElements, getTextLayout, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
4566
4607
  const writes = [setArtworkSvg, importPptx, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
4567
4608
  return {
4568
4609
  id: _nullishCoalesce(options.id, () => ( "animation")),
@@ -4595,6 +4636,7 @@ Commands
4595
4636
  - enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
4596
4637
  - enter also reveals through a clip over the target's box: wipe (behind an edge travelling "direction", default right), iris (from the centre; "shape": circle or box) and split (from a line through the middle; "orientation": horizontal or vertical). exit wipe hides the same way. Reveals need a width and a height: use draw / undraw for a straight line.
4597
4638
  - draw draws strokes on to a fraction; move, rotate, scale and fade change the pose (about the centre); style blends solid colours and stroke width.
4639
+ - Text: convert it to outlines (a group with a path per letter) and give a command "split": "letter", "word" or "line" (and "cascade") to animate it a unit at a time; get_text_layout shows the units.
4598
4640
  - Drawing a group of strokes: "order": "sequence" draws them one after another (a signature, a diagram), "sortBy": "distance" from "origin" reveals outward, "pace": "speed" keeps one speed; draw with "comet": 0.2 sends a short stroke along a path and off the end.
4599
4641
  - Fast motion reads better with blur: set_animation_settings { "motionBlur": { "shutter": 180 } } (stage and rendered frames only).
4600
4642
  - Tie properties together with set_animation_drivers: parallax layers, a wheel that turns as it rolls, a shadow that fades as something rises. Drivers add to the target's own commands.
@@ -4626,7 +4668,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
4626
4668
  var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
4627
4669
  var NODES = /* @__PURE__ */ new Set(["into", "path"]);
4628
4670
  function branch(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);
4671
+ return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _168 => _168.properties, 'optionalAccess', _169 => _169.type, 'optionalAccess', _170 => _170.const]) === type);
4630
4672
  }
4631
4673
  function unitOf(type, name) {
4632
4674
  if (name === "duration" || name === "delay" || name === "stagger") return "ms";
@@ -4661,7 +4703,7 @@ function kindOf(name, schema) {
4661
4703
  }
4662
4704
  function motionCommandFields(type) {
4663
4705
  const schema = branch(type);
4664
- if (!_optionalChain([schema, 'optionalAccess', _163 => _163.properties])) return [];
4706
+ if (!_optionalChain([schema, 'optionalAccess', _171 => _171.properties])) return [];
4665
4707
  const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
4666
4708
  const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
4667
4709
  const kind = kindOf(name, s);
@@ -4718,7 +4760,7 @@ function defaultMotionCommand(type, targets, scene) {
4718
4760
  if (type === "wait") return { type: "wait", duration: 500 };
4719
4761
  if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
4720
4762
  const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
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]);
4763
+ const other = (pred) => _optionalChain([nodes, 'access', _172 => _172.find, 'call', _173 => _173((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _174 => _174.node, 'access', _175 => _175.id]);
4722
4764
  const base = { targets: [...targets] };
4723
4765
  switch (type) {
4724
4766
  case "scale":
@@ -4749,8 +4791,8 @@ function defaultMotionCommand(type, targets, scene) {
4749
4791
  }
4750
4792
  case "effect": {
4751
4793
  for (const id of targets) {
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]), () => ( []))) {
4794
+ const node = _optionalChain([nodes, 'access', _176 => _176.find, 'call', _177 => _177((e) => e.node.id === id), 'optionalAccess', _178 => _178.node]);
4795
+ for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _179 => _179.effects]), () => ( []))) {
4754
4796
  const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
4755
4797
  if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
4756
4798
  }
@@ -4775,11 +4817,11 @@ function motionCommandRows(scene, shotId) {
4775
4817
  return scene.shots[index].run.map((command3, i) => {
4776
4818
  const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
4777
4819
  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 } : {} };
4820
+ return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _180 => _180.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _181 => _181.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
4779
4821
  });
4780
4822
  }
4781
4823
  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]), () => ( []));
4824
+ const run = _nullishCoalesce(_optionalChain([scene, 'access', _182 => _182.shots, 'access', _183 => _183.find, 'call', _184 => _184((s) => s.id === shot), 'optionalAccess', _185 => _185.run]), () => ( []));
4783
4825
  return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
4784
4826
  }
4785
4827
  var MOTION_EASE_CHOICES = [
@@ -4864,7 +4906,7 @@ function motionCueFromKey(key) {
4864
4906
  function motionCueChoices(scene, limit = 256) {
4865
4907
  const choices = [];
4866
4908
  const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
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;
4909
+ const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _186 => _186.narration, 'optionalAccess', _187 => _187.words, 'access', _188 => _188.map, 'call', _189 => _189((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
4868
4910
  if (scene.beat && scene.beat.bpm > 0) {
4869
4911
  for (let beat = 0; choices.length < limit; beat++) {
4870
4912
  const time = motionBeatTime(scene.beat, beat);
@@ -4874,7 +4916,7 @@ function motionCueChoices(scene, limit = 256) {
4874
4916
  choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
4875
4917
  }
4876
4918
  }
4877
- _optionalChain([scene, 'access', _182 => _182.narration, 'optionalAccess', _183 => _183.words, 'access', _184 => _184.forEach, 'call', _185 => _185((w, i) => {
4919
+ _optionalChain([scene, 'access', _190 => _190.narration, 'optionalAccess', _191 => _191.words, 'access', _192 => _192.forEach, 'call', _193 => _193((w, i) => {
4878
4920
  if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
4879
4921
  })]);
4880
4922
  return choices;
@@ -4883,7 +4925,7 @@ function motionShotCueTime(scene, cue) {
4883
4925
  return cue ? motionCueTime(scene, cue) : void 0;
4884
4926
  }
4885
4927
  function formatMotionNarration(narration) {
4886
- return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _186 => _186.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4928
+ return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _194 => _194.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4887
4929
  }
4888
4930
  function parseMotionNarration(text) {
4889
4931
  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -5056,5 +5098,12 @@ function parseMotionDrivers(text) {
5056
5098
 
5057
5099
 
5058
5100
 
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;
5101
+
5102
+
5103
+
5104
+
5105
+
5106
+
5107
+
5108
+ 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_CASCADES = MOTION_CASCADES; 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 = _chunkWAJQKWQUcjs.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_TEXT_STAGGER = MOTION_TEXT_STAGGER; exports.MOTION_TEXT_UNITS = MOTION_TEXT_UNITS; 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.motionCascade = motionCascade; exports.motionClipAttrs = motionClipAttrs; exports.motionClipLayout = motionClipLayout; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSlots = motionCommandSlots; 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 = _chunkWAJQKWQUcjs.motionIssue; exports.motionIssueKey = _chunkWAJQKWQUcjs.motionIssueKey; exports.motionIssueLine = _chunkWAJQKWQUcjs.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.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = _chunkWAJQKWQUcjs.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 = _chunkWAJQKWQUcjs.suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
5060
5109
  //# sourceMappingURL=index.cjs.map