@pixerate/editor 0.74.0 → 0.75.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.
@@ -20,14 +20,14 @@
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
+ var _chunkXGD3FSNCcjs = require('../chunk-XGD3FSNC.cjs');
31
31
 
32
32
 
33
33
  var _chunkEMQWJA3Gcjs = require('../chunk-EMQWJA3G.cjs');
@@ -61,6 +61,8 @@ var _chunk2FHLHZALcjs = require('../chunk-2FHLHZAL.cjs');
61
61
 
62
62
  // src/animation-editor/types.ts
63
63
  var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
64
+ var MOTION_TEXT_UNITS = ["letter", "word", "line"];
65
+ var MOTION_CASCADES = ["forward", "backward", "center", "edges", "random"];
64
66
  var MOTION_DRIVEN_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY", "opacity"];
65
67
  var MOTION_CLIP_TARGET = "$";
66
68
  var MOTION_COMMAND_TYPES = [
@@ -148,6 +150,7 @@ var MOTION_ISSUE_CODES = {
148
150
  "not-a-path": { severity: "error", wording: "A follow path must be a path node, not a group." },
149
151
  "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
152
  "driver-cycle": { severity: "error", wording: "Drivers follow each other in a loop, so none of them has a value." },
153
+ "split-not-text": { severity: "warning", wording: "A command splits a target into letters, but it is not a group of letter paths, so it animates as a whole." },
151
154
  "unknown-clip": { severity: "error", wording: "A play command names a clip the scene does not have." },
152
155
  "unknown-shape": { severity: "error", wording: "A morph names a shape the artwork does not have." },
153
156
  "match-self": { severity: "error", wording: "A match turns a group into itself or into a group it holds (or that holds it)." },
@@ -229,7 +232,7 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
229
232
  var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
230
233
  var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
231
234
  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"];
235
+ var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps", "split", "cascade"];
233
236
  var DRAW_ORDER_KEYS = ["order", "pace", "align", "sortBy", "origin"];
234
237
  var COMMAND_KEYS = {
235
238
  enter: [...BASE_KEYS, ...DRAW_ORDER_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
@@ -301,6 +304,9 @@ function commandShapeProblems(command3, where) {
301
304
  else if (!(Number.isInteger(command3.repeat) && command3.repeat >= 1 && command3.repeat <= 1e3)) p(`"repeat" must be a whole number from 1 to 1000.`);
302
305
  }
303
306
  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).`);
307
+ 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).`);
308
+ if (command3.cascade !== void 0 && !MOTION_CASCADES.includes(command3.cascade)) p(`"cascade" must be one of ${MOTION_CASCADES.join(", ")}.`);
309
+ if (command3.cascade !== void 0 && command3.split === void 0) p(`"cascade" goes with "split".`);
304
310
  if (command3.repeatMode !== void 0 && !MOTION_REPEAT_MODES.includes(command3.repeatMode)) p(`"repeatMode" must be one of ${MOTION_REPEAT_MODES.join(", ")}.`);
305
311
  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
312
  switch (type) {
@@ -616,6 +622,87 @@ function smoothMotionTimes(points, start, duration, pacing = "even") {
616
622
  return times;
617
623
  }
618
624
 
625
+ // src/animation-editor/text.ts
626
+ function motionTextLayout(nodes, id) {
627
+ const group = _optionalChain([nodes, 'access', _7 => _7.get, 'call', _8 => _8(id), 'optionalAccess', _9 => _9.node]);
628
+ if (!group || group.type !== "group") return null;
629
+ const letters = _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, group).map((p) => ({ id: p.id, b: _optionalChain([nodes, 'access', _10 => _10.get, 'call', _11 => _11(p.id), 'optionalAccess', _12 => _12.bounds]) })).filter((l) => !!l.b && l.b.width + l.b.height > 0);
630
+ if (!letters.length) return null;
631
+ const lines = [];
632
+ for (const l of [...letters].sort((a, c) => a.b.y + a.b.height / 2 - (c.b.y + c.b.height / 2))) {
633
+ const cy = l.b.y + l.b.height / 2;
634
+ const line = lines.find((x) => cy >= x.top && cy <= x.bottom);
635
+ if (line) {
636
+ line.letters.push(l);
637
+ line.top = Math.min(line.top, l.b.y);
638
+ line.bottom = Math.max(line.bottom, l.b.y + l.b.height);
639
+ } else lines.push({ top: l.b.y, bottom: l.b.y + l.b.height, letters: [l] });
640
+ }
641
+ lines.sort((a, c) => a.top - c.top);
642
+ return {
643
+ lines: lines.map((line) => {
644
+ const row = [...line.letters].sort((a, c) => a.b.x - c.b.x);
645
+ const heights = row.map((l) => l.b.height).sort((a, c) => a - c);
646
+ const gap = heights[Math.floor(heights.length / 2)] * 0.35;
647
+ const words = [];
648
+ row.forEach((l, i) => {
649
+ const prev = row[i - 1];
650
+ if (!prev || l.b.x - (prev.b.x + prev.b.width) > gap) words.push({ letters: [] });
651
+ words[words.length - 1].letters.push(l.id);
652
+ });
653
+ return { words };
654
+ })
655
+ };
656
+ }
657
+ function motionTextUnits(layout, by) {
658
+ if (by === "line") return layout.lines.map((l) => l.words.flatMap((w) => w.letters));
659
+ if (by === "word") return layout.lines.flatMap((l) => l.words.map((w) => w.letters));
660
+ return layout.lines.flatMap((l) => l.words.flatMap((w) => w.letters.map((id) => [id])));
661
+ }
662
+ function motionCascade(units, cascade = "forward", seed = 1) {
663
+ const n = units.length;
664
+ const mid = (n - 1) / 2;
665
+ const indexed = units.map((u, i) => ({ u, i }));
666
+ if (cascade === "backward") return [...units].reverse();
667
+ 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);
668
+ 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);
669
+ if (cascade === "random") {
670
+ let s = seed >>> 0 || 1;
671
+ const rand = () => {
672
+ s = s + 1831565813 >>> 0;
673
+ let t = s;
674
+ t = Math.imul(t ^ t >>> 15, t | 1);
675
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
676
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
677
+ };
678
+ const out = [...units];
679
+ for (let i = n - 1; i > 0; i--) {
680
+ const j = Math.floor(rand() * (i + 1));
681
+ [out[i], out[j]] = [out[j], out[i]];
682
+ }
683
+ return out;
684
+ }
685
+ return [...units];
686
+ }
687
+ var MOTION_TEXT_STAGGER = { letter: 40, word: 120, line: 300 };
688
+ function motionCommandSlots(nodes, command3) {
689
+ if (!command3.split) return { slots: command3.targets.map((id, k) => ({ id, slot: k })), stagger: _nullishCoalesce(command3.stagger, () => ( 0)) };
690
+ const slots = [];
691
+ let slot = 0;
692
+ for (const target of command3.targets) {
693
+ const layout = motionTextLayout(nodes, target);
694
+ if (!layout) {
695
+ slots.push({ id: target, slot: slot++ });
696
+ continue;
697
+ }
698
+ for (const unit of motionCascade(motionTextUnits(layout, command3.split), command3.cascade, _chunkZCNLBRT6cjs.motionSeedFromId.call(void 0, target))) {
699
+ for (const id of unit) slots.push({ id, slot });
700
+ slot++;
701
+ }
702
+ }
703
+ return { slots, stagger: _nullishCoalesce(command3.stagger, () => ( MOTION_TEXT_STAGGER[command3.split])) };
704
+ }
705
+
619
706
  // src/animation-editor/compile.ts
620
707
  var indexCache = /* @__PURE__ */ new WeakMap();
621
708
  function indexMotionNodes(nodes) {
@@ -624,21 +711,21 @@ function indexMotionNodes(nodes) {
624
711
  const out = /* @__PURE__ */ new Map();
625
712
  const walk = (list, parentWorld, ancestors) => {
626
713
  for (const node of list) {
627
- const local = _chunkYJLCBA7Vcjs.vectorNodeBounds.call(void 0, node);
628
- const bounds = _chunkYJLCBA7Vcjs.vectorNodeBounds.call(void 0, node, parentWorld);
714
+ const local = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node);
715
+ const bounds = _chunk7MD7C6XQcjs.vectorNodeBounds.call(void 0, node, parentWorld);
629
716
  const center = local ? { x: local.x + local.width / 2, y: local.y + local.height / 2 } : { x: 0, y: 0 };
630
717
  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]);
718
+ if (node.type === "group") walk(node.children, _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node), parentWorld), [...ancestors, node.id]);
632
719
  }
633
720
  };
634
- walk(nodes, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, []);
721
+ walk(nodes, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, []);
635
722
  indexCache.set(nodes, out);
636
723
  return out;
637
724
  }
638
725
  var solid = (paint) => typeof paint === "string" && paint !== "none" ? paint : void 0;
639
726
  function firstPaint(node, key) {
640
727
  if (node.type === "path") return solid(node[key]);
641
- for (const p of _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)) {
728
+ for (const p of _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
642
729
  const s = solid(p[key]);
643
730
  if (s) return s;
644
731
  }
@@ -646,7 +733,7 @@ function firstPaint(node, key) {
646
733
  }
647
734
  function strokeReach(node) {
648
735
  let reach = 0;
649
- for (const p of node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node)) {
736
+ for (const p of node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)) {
650
737
  if (p.stroke == null || p.stroke === "none") continue;
651
738
  const width = _nullishCoalesce(p.strokeWidth, () => ( 1));
652
739
  reach = Math.max(reach, p.strokeAlign === "outside" ? width : p.strokeAlign === "inside" ? 0 : width / 2);
@@ -695,10 +782,10 @@ function motionRevealClip(entry, reveal) {
695
782
  }
696
783
  }
697
784
  function motionRestValue(entry, property, artwork) {
698
- const node = _optionalChain([entry, 'optionalAccess', _7 => _7.node]);
785
+ const node = _optionalChain([entry, 'optionalAccess', _13 => _13.node]);
699
786
  switch (property) {
700
787
  case "opacity":
701
- return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _8 => _8.opacity]), () => ( 1));
788
+ return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _14 => _14.opacity]), () => ( 1));
702
789
  case "x":
703
790
  case "y":
704
791
  case "rotation":
@@ -716,11 +803,11 @@ function motionRestValue(entry, property, artwork) {
716
803
  case "stroke":
717
804
  return _nullishCoalesce((node && firstPaint(node, property)), () => ( "transparent"));
718
805
  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));
806
+ const path = _optionalChain([node, 'optionalAccess', _15 => _15.type]) === "path" ? node : node ? _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node)[0] : void 0;
807
+ return _nullishCoalesce(_optionalChain([path, 'optionalAccess', _16 => _16.strokeWidth]), () => ( 1));
721
808
  }
722
809
  case "shape":
723
- return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _11 => _11.id]), () => ( ""));
810
+ return _nullishCoalesce(_optionalChain([node, 'optionalAccess', _17 => _17.id]), () => ( ""));
724
811
  case "clipRect":
725
812
  case "clipCircle": {
726
813
  const pad = entry && motionRevealPadding(entry);
@@ -730,7 +817,7 @@ function motionRestValue(entry, property, artwork) {
730
817
  return [0, 0, artwork.width, artwork.height];
731
818
  }
732
819
  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)]);
820
+ const effect = _optionalChain([node, 'optionalAccess', _18 => _18.effects, 'optionalAccess', _19 => _19.find, 'call', _20 => _20((e) => e.id === effectId)]);
734
821
  const v = effect ? effect.params[param] : void 0;
735
822
  return typeof v === "number" ? v : 0;
736
823
  }
@@ -779,13 +866,13 @@ function segmentValue(segment, time, raw = false) {
779
866
  return typeof segment.from === "string" ? interpolateMotionValue(segment.from, segment.to, Math.min(1, Math.max(0, p))) : interpolateMotionValue(segment.from, segment.to, p);
780
867
  }
781
868
  function activeSegment(track, time) {
782
- if (!_optionalChain([track, 'optionalAccess', _15 => _15.length])) return void 0;
869
+ if (!_optionalChain([track, 'optionalAccess', _21 => _21.length])) return void 0;
783
870
  let found;
784
871
  for (const s of track) if (s.start <= time && (!found || s.start >= found.start)) found = s;
785
872
  return found;
786
873
  }
787
874
  function trackValue(track, time, raw = false) {
788
- if (!_optionalChain([track, 'optionalAccess', _16 => _16.length])) return void 0;
875
+ if (!_optionalChain([track, 'optionalAccess', _22 => _22.length])) return void 0;
789
876
  const s = activeSegment(track, time);
790
877
  if (s) return segmentValue(s, time, raw);
791
878
  let first = track[0];
@@ -818,7 +905,7 @@ function fitMotionRect(rect, aspect) {
818
905
  function resolveMotionCamera(camera, scene) {
819
906
  if ("frame" in camera && typeof camera.frame === "string") {
820
907
  const entry = indexMotionNodes(scene.artwork.nodes).get(camera.frame);
821
- if (!_optionalChain([entry, 'optionalAccess', _17 => _17.bounds])) return null;
908
+ if (!_optionalChain([entry, 'optionalAccess', _23 => _23.bounds])) return null;
822
909
  const pad = _nullishCoalesce(camera.padding, () => ( 24));
823
910
  const b = entry.bounds;
824
911
  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 +914,12 @@ function resolveMotionCamera(camera, scene) {
827
914
  const r = camera;
828
915
  return { x: r.x, y: r.y, width: r.width, height: r.height };
829
916
  }
830
- function motionPathLength(node, parentWorld = _chunkYJLCBA7Vcjs.IDENTITY_MATRIX) {
917
+ function motionPathLength(node, parentWorld = _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
831
918
  let longest = 0;
832
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
919
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
833
920
  for (const p of paths) {
834
921
  try {
835
- longest = Math.max(longest, _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
922
+ longest = Math.max(longest, _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, parentWorld, { effects: false })));
836
923
  } catch (e2) {
837
924
  }
838
925
  }
@@ -853,12 +940,12 @@ function motionBeatAt(grid, ms) {
853
940
  function motionCueTime(scene, cue) {
854
941
  if (typeof cue.ms === "number") return Math.max(0, cue.ms);
855
942
  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]);
943
+ if (typeof cue.word === "number") return _optionalChain([scene, 'access', _24 => _24.narration, 'optionalAccess', _25 => _25.words, 'access', _26 => _26[cue.word], 'optionalAccess', _27 => _27.start]);
857
944
  return void 0;
858
945
  }
859
946
  var SCALE_LIKE = /* @__PURE__ */ new Set(["scaleX", "scaleY", "opacity"]);
860
947
  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;
948
+ const rest = property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _28 => _28.restOpacity, 'optionalAccess', _29 => _29.get, 'call', _30 => _30(node)]), () => ( 1)) : SCALE_LIKE.has(property) ? 1 : 0;
862
949
  const v = trackValue(timeline.tracks.get(motionTrackKey(node, property)), time, raw);
863
950
  const base = property === "opacity" ? typeof v === "number" ? v : rest : withMotionLayers(timeline, node, property, typeof v === "number" ? v : rest, time, raw);
864
951
  return applyMotionDrivers(timeline, node, property, base, time, raw, depth);
@@ -869,7 +956,7 @@ function applyMotionDrivers(timeline, node, property, value, time, raw = false,
869
956
  for (const d of timeline.drivers) {
870
957
  if (d.target !== node || d.property !== property) continue;
871
958
  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;
959
+ const srcRest = d.source.property === "opacity" ? _nullishCoalesce(_optionalChain([timeline, 'access', _31 => _31.restOpacity, 'optionalAccess', _32 => _32.get, 'call', _33 => _33(d.source.node)]), () => ( 1)) : SCALE_LIKE.has(d.source.property) ? 1 : 0;
873
960
  let change = (src - srcRest) * (_nullishCoalesce(d.factor, () => ( 1))) + (_nullishCoalesce(d.offset, () => ( 0)));
874
961
  if (d.clamp) change = Math.min(d.clamp[1], Math.max(d.clamp[0], change));
875
962
  v = SCALE_LIKE.has(property) ? v * (1 + change) : v + change;
@@ -900,7 +987,7 @@ function motionCommandDuration(command3, scene, target) {
900
987
  return motionCycleDuration(command3, scene, target) * motionCommandRepeat(command3);
901
988
  }
902
989
  function motionClipLayout(scene, clip, target, speed = 1) {
903
- const run = _optionalChain([scene, 'access', _28 => _28.clips, 'optionalAccess', _29 => _29[clip], 'optionalAccess', _30 => _30.run]);
990
+ const run = _optionalChain([scene, 'access', _34 => _34.clips, 'optionalAccess', _35 => _35[clip], 'optionalAccess', _36 => _36.run]);
904
991
  if (!run) return { items: [], length: 0 };
905
992
  const f = speed > 0 && Number.isFinite(speed) ? 1 / speed : 1;
906
993
  const items = [];
@@ -942,7 +1029,7 @@ function motionCycleDuration(command3, scene, target) {
942
1029
  const ms = length * MOTION_DRAW_MS_PER_UNIT;
943
1030
  return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
944
1031
  }
945
- if (command3.type === "move" && _optionalChain([command3, 'access', _31 => _31.via, 'optionalAccess', _32 => _32.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
1032
+ if (command3.type === "move" && _optionalChain([command3, 'access', _37 => _37.via, 'optionalAccess', _38 => _38.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command3.via.length;
946
1033
  return MOTION_DEFAULT_DURATIONS[command3.type];
947
1034
  }
948
1035
  var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
@@ -982,10 +1069,11 @@ function compileMotionScene(scene) {
982
1069
  shot.run.forEach((command3, i) => {
983
1070
  const base = command3.with === "previous" && i > 0 ? prevStart : runEnd;
984
1071
  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);
1072
+ const split = command3.type === "wait" ? null : motionCommandSlots(nodes, command3);
1073
+ const slots = _nullishCoalesce(_optionalChain([split, 'optionalAccess', _39 => _39.slots]), () => ( []));
1074
+ const durations = command3.type === "wait" ? [command3.duration * f] : slots.map((s) => motionCommandDuration(command3, scene, s.id) * f);
1075
+ const stagger = (_nullishCoalesce(_optionalChain([split, 'optionalAccess', _40 => _40.stagger]), () => ( 0))) * f;
1076
+ const end2 = durations.reduce((m, d, k) => Math.max(m, begin + (_nullishCoalesce(_optionalChain([slots, 'access', _41 => _41[k], 'optionalAccess', _42 => _42.slot]), () => ( k))) * stagger + d), begin);
989
1077
  commands.push({ shot: shot.id, shotIndex: index, command: i, type: command3.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
990
1078
  prevStart = begin;
991
1079
  runEnd = Math.max(runEnd, end2);
@@ -1033,14 +1121,15 @@ function compileMotionScene(scene) {
1033
1121
  });
1034
1122
  continue;
1035
1123
  }
1036
- command3.targets.forEach((target, k) => {
1124
+ const split = motionCommandSlots(nodes, command3);
1125
+ for (const { id: target, slot } of split.slots) {
1037
1126
  const entry = nodes.get(target);
1038
- if (!entry) return;
1127
+ if (!entry) continue;
1039
1128
  const f = motionShotTimeScale(shot);
1040
- const start = timing.start + k * (_nullishCoalesce(command3.stagger, () => ( 0))) * f;
1129
+ const start = timing.start + slot * split.stagger * f;
1041
1130
  const cycle = motionCycleDuration(command3, scene, target) * f;
1042
1131
  jobs.push({ start, order: order++, run: () => compileRepeated(command3, target, entry, start, cycle, timing) });
1043
- });
1132
+ }
1044
1133
  }
1045
1134
  jobs.sort((a, b) => a.start - b.start || a.order - b.order).forEach((job) => job.run());
1046
1135
  function compileRepeated(command3, node, entry, start, cycle, timing) {
@@ -1083,16 +1172,16 @@ function compileMotionScene(scene) {
1083
1172
  const order2 = _nullishCoalesce(o.order, () => ( "together"));
1084
1173
  const pace = _nullishCoalesce(o.pace, () => ( "time"));
1085
1174
  if (order2 === "together" && pace === "time") return null;
1086
- const paths = entry.node.type === "path" ? [entry.node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, entry.node);
1175
+ const paths = entry.node.type === "path" ? [entry.node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, entry.node);
1087
1176
  let list = paths.map((p) => {
1088
1177
  const at = nodes.get(p.id);
1089
1178
  let first = { x: 0, y: 0 };
1090
1179
  try {
1091
- const m = _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _33 => _33.parentWorld]), () => ( _chunkYJLCBA7Vcjs.IDENTITY_MATRIX)), { effects: false })[0];
1180
+ const m = _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _43 => _43.parentWorld]), () => ( _chunk7MD7C6XQcjs.IDENTITY_MATRIX)), { effects: false })[0];
1092
1181
  if (m && m.type === "M") first = { x: m.x, y: m.y };
1093
1182
  } catch (e3) {
1094
1183
  }
1095
- return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _34 => _34.parentWorld]))), first };
1184
+ return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _44 => _44.parentWorld]))), first };
1096
1185
  });
1097
1186
  if (!list.length) return null;
1098
1187
  const span = Math.max(0, e - s);
@@ -1121,7 +1210,7 @@ function compileMotionScene(scene) {
1121
1210
  const style = _nullishCoalesce(command3.style, () => ( "fade"));
1122
1211
  const opacity = rest("opacity");
1123
1212
  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);
1213
+ for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _45 => _45.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
1125
1214
  if (reveal) {
1126
1215
  seg("opacity", opacity, "linear", start, start);
1127
1216
  seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
@@ -1197,20 +1286,20 @@ function compileMotionScene(scene) {
1197
1286
  }
1198
1287
  case "move": {
1199
1288
  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));
1289
+ let dx = _nullishCoalesce(_optionalChain([command3, 'access', _46 => _46.by, 'optionalAccess', _47 => _47.x]), () => ( 0));
1290
+ let dy = _nullishCoalesce(_optionalChain([command3, 'access', _48 => _48.by, 'optionalAccess', _49 => _49.y]), () => ( 0));
1202
1291
  if (command3.to) {
1203
- const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1204
- const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command3.to);
1292
+ const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
1293
+ const target = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, inv, command3.to);
1205
1294
  dx = target.x - (entry.center.x + num2("x"));
1206
1295
  dy = target.y - (entry.center.y + num2("y"));
1207
1296
  }
1208
- if (_optionalChain([command3, 'access', _40 => _40.via, 'optionalAccess', _41 => _41.length])) {
1209
- const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1297
+ if (_optionalChain([command3, 'access', _50 => _50.via, 'optionalAccess', _51 => _51.length])) {
1298
+ const inv = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, entry.parentWorld);
1210
1299
  const x0 = num2("x");
1211
1300
  const y0 = num2("y");
1212
1301
  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 }];
1302
+ 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
1303
  const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
1215
1304
  for (const axis of ["x", "y"]) {
1216
1305
  const base = add ? 0 : axis === "x" ? x0 : y0;
@@ -1303,7 +1392,7 @@ function compileMotionScene(scene) {
1303
1392
  for (const track of tracks.values()) track.sort((a, b) => a.start - b.start);
1304
1393
  segments.sort((a, b) => a.start - b.start);
1305
1394
  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))])) } : {} };
1395
+ const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _52 => _52.drivers, 'optionalAccess', _53 => _53.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
1307
1396
  timelineCache.set(scene, timeline);
1308
1397
  return timeline;
1309
1398
  }
@@ -1316,7 +1405,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
1316
1405
  var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
1317
1406
  var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
1318
1407
  function applyMotionControlValues(scene, values) {
1319
- if (!values || !_optionalChain([scene, 'access', _44 => _44.controls, 'optionalAccess', _45 => _45.length])) return scene;
1408
+ if (!values || !_optionalChain([scene, 'access', _54 => _54.controls, 'optionalAccess', _55 => _55.length])) return scene;
1320
1409
  const map = /* @__PURE__ */ new Map();
1321
1410
  for (const control of scene.controls) {
1322
1411
  const value = values[control.name];
@@ -1352,17 +1441,17 @@ function morphBetween(a, b) {
1352
1441
  let inner = morphCache.get(a);
1353
1442
  if (!inner) morphCache.set(a, inner = /* @__PURE__ */ new WeakMap());
1354
1443
  let morph = inner.get(b);
1355
- if (!morph) inner.set(b, morph = _chunkYJLCBA7Vcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
1444
+ if (!morph) inner.set(b, morph = _chunk7MD7C6XQcjs.createVectorMorph.call(void 0, a, b, { id: a.id }));
1356
1445
  return morph;
1357
1446
  }
1358
1447
  function shapeIn(entry, shape) {
1359
1448
  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 } };
1449
+ 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));
1450
+ return { ...shape.node, ..._chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, m) ? { transform: void 0 } : { transform: m } };
1362
1451
  }
1363
1452
  function shapeAt(entry, timeline, nodes, time) {
1364
1453
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
1365
- if (!_optionalChain([track, 'optionalAccess', _46 => _46.length])) return null;
1454
+ if (!_optionalChain([track, 'optionalAccess', _56 => _56.length])) return null;
1366
1455
  const s = activeSegment(track, time);
1367
1456
  const fromId = String(s ? s.from : track[0].from);
1368
1457
  if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
@@ -1378,20 +1467,20 @@ function shapeAt(entry, timeline, nodes, time) {
1378
1467
  function motionFollowRoute(entry, path) {
1379
1468
  if (!path || path.node.type !== "path") return null;
1380
1469
  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));
1470
+ 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
1471
  } catch (e4) {
1383
1472
  return null;
1384
1473
  }
1385
1474
  }
1386
1475
  function followAt(entry, timeline, nodes, time) {
1387
1476
  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;
1477
+ const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _57 => _57[0]])));
1478
+ if (!_optionalChain([s, 'optionalAccess', _58 => _58.path])) return null;
1390
1479
  const route = motionFollowRoute(entry, nodes.get(s.path));
1391
1480
  const progress = Number(trackValue(track, time));
1392
1481
  if (!route || !(progress >= 0)) return null;
1393
1482
  try {
1394
- const at = _chunkO2UH7LZEcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkO2UH7LZEcjs.bezierPathLength.call(void 0, route));
1483
+ const at = _chunkXGD3FSNCcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkXGD3FSNCcjs.bezierPathLength.call(void 0, route));
1395
1484
  if (!at) return null;
1396
1485
  return { x: at.point[0], y: at.point[1], angle: s.rotate ? at.angle * 180 / Math.PI : 0 };
1397
1486
  } catch (e5) {
@@ -1404,7 +1493,7 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
1404
1493
  const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
1405
1494
  return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
1406
1495
  };
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")]);
1496
+ const driven = _optionalChain([timeline, 'access', _59 => _59.drivers, 'optionalAccess', _60 => _60.some, 'call', _61 => _61((d) => d.target === entry.node.id && d.property !== "opacity")]);
1408
1497
  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
1498
  const dx = read("x", 0);
1410
1499
  const dy = read("y", 0);
@@ -1412,9 +1501,9 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
1412
1501
  const scaleX = read("scaleX", 1);
1413
1502
  const scaleY = read("scaleY", 1);
1414
1503
  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));
1504
+ 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
1505
  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)));
1506
+ 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
1507
  return { matrix, dx, dy, rotation, scaleX, scaleY, follow: along };
1419
1508
  }
1420
1509
  function motionNodeClips(id, timeline, time) {
@@ -1448,7 +1537,7 @@ function motionFrameAt(scene, time, options = {}) {
1448
1537
  if (out.visible === void 0) delete out.visible;
1449
1538
  }
1450
1539
  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])) {
1540
+ if (effectTracks.length && _optionalChain([out, 'access', _62 => _62.effects, 'optionalAccess', _63 => _63.length])) {
1452
1541
  out = {
1453
1542
  ...out,
1454
1543
  effects: out.effects.map((effect) => {
@@ -1481,22 +1570,22 @@ function motionFrameAt(scene, time, options = {}) {
1481
1570
  const start = Math.min(1, Math.max(0, typeof drawStart === "number" ? drawStart : 0));
1482
1571
  const end = Math.min(1, Math.max(0, typeof drawEnd === "number" ? drawEnd : 1));
1483
1572
  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) });
1573
+ const trim = _chunk7MD7C6XQcjs.createVectorEffect.call(void 0, "trim", MOTION_DRAW_EFFECT_ID, { start: tidy(start * 100), end: tidy(end * 100) });
1485
1574
  p = { ...p, effects: [trim, ...(_nullishCoalesce(p.effects, () => ( []))).filter((e) => e.id !== MOTION_DRAW_EFFECT_ID)] };
1486
1575
  }
1487
1576
  }
1488
1577
  return p;
1489
1578
  });
1490
1579
  }
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");
1580
+ const opacity = _optionalChain([timeline, 'access', _64 => _64.drivers, 'optionalAccess', _65 => _65.some, 'call', _66 => _66((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
1492
1581
  if (typeof opacity === "number") {
1493
1582
  const o = Math.min(1, Math.max(0, tidy(opacity)));
1494
1583
  out = { ...out, opacity: o };
1495
1584
  if (o >= 1) delete out.opacity;
1496
1585
  }
1497
1586
  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);
1587
+ if (offset && !_chunk7MD7C6XQcjs.isIdentityMatrix.call(void 0, offset.matrix)) {
1588
+ const m = _chunk7MD7C6XQcjs.multiplyMatrices.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, out), offset.matrix).map(tidy);
1500
1589
  out = { ...out, transform: m };
1501
1590
  }
1502
1591
  return out;
@@ -1516,7 +1605,7 @@ function motionFrameToSvg(scene, time, options = {}) {
1516
1605
  const wrap = { ...options.wrap };
1517
1606
  for (const [id, clips] of Object.entries(frame.clips))
1518
1607
  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);
1608
+ return withViewBox(_chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
1520
1609
  }
1521
1610
  function withViewBox(svg, box) {
1522
1611
  const f = (n) => String(Math.round(n * 1e3) / 1e3);
@@ -1561,7 +1650,7 @@ function motionPath(scene, id, options = {}) {
1561
1650
  const r = (n) => Math.round(n * 100) / 100;
1562
1651
  const centreAt = (t) => {
1563
1652
  const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
1564
- const b = _optionalChain([node, 'optionalAccess', _57 => _57.bounds]);
1653
+ const b = _optionalChain([node, 'optionalAccess', _67 => _67.bounds]);
1565
1654
  return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
1566
1655
  };
1567
1656
  const points = [];
@@ -1595,8 +1684,8 @@ function motionBlurTimes(scene, time, blur = {}) {
1595
1684
  const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
1596
1685
  let travel = 0;
1597
1686
  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]);
1687
+ const p = _optionalChain([a, 'access', _68 => _68.get, 'call', _69 => _69(id), 'optionalAccess', _70 => _70.bounds]);
1688
+ const q = _optionalChain([b, 'access', _71 => _71.get, 'call', _72 => _72(id), 'optionalAccess', _73 => _73.bounds]);
1600
1689
  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
1690
  }
1602
1691
  const n = Math.min(most, Math.ceil(travel / 1.5));
@@ -1608,7 +1697,7 @@ function averagedFrames(scene, times, options, prefix) {
1608
1697
  return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
1609
1698
  const own = `${prefix}blur${k}-`;
1610
1699
  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]]), () => ( ""));
1700
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _74 => _74.exec, 'call', _75 => _75(frame), 'optionalAccess', _76 => _76[1]]), () => ( ""));
1612
1701
  const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1613
1702
  return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
1614
1703
  }).join("")}</g>`;
@@ -1623,7 +1712,7 @@ function motionStageSvg(scene, time, options = {}) {
1623
1712
  if (blurTimes.length > 1) {
1624
1713
  const open2 = current.indexOf(">") + 1;
1625
1714
  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]]), () => ( "")) : "";
1715
+ const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _77 => _77.exec, 'call', _78 => _78(body2), 'optionalAccess', _79 => _79[0]]), () => ( "")) : "";
1627
1716
  current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
1628
1717
  }
1629
1718
  if (!onionSkin && !motionPaths) return current;
@@ -1638,7 +1727,7 @@ function motionStageSvg(scene, time, options = {}) {
1638
1727
  const open = current.indexOf(">") + 1;
1639
1728
  const close = current.lastIndexOf("</svg>");
1640
1729
  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]]), () => ( "")) : "";
1730
+ const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _80 => _80.exec, 'call', _81 => _81(body), 'optionalAccess', _82 => _82[0]]), () => ( "")) : "";
1642
1731
  return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
1643
1732
  }
1644
1733
  function motionContactSheetSvg(scene, times, options = {}) {
@@ -1657,7 +1746,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1657
1746
  const x = gap + i % cols * (w + gap);
1658
1747
  const y = gap + Math.floor(i / cols) * (h + label + gap);
1659
1748
  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}`));
1749
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _83 => _83.exec, 'call', _84 => _84(frame), 'optionalAccess', _85 => _85[1]]), () => ( `0 0 ${w} ${h}`));
1661
1750
  const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1662
1751
  const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
1663
1752
  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 +1758,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1669
1758
  // src/animation-editor/check.ts
1670
1759
  var MOTION_MIN_CHANGE_MS = 120;
1671
1760
  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)]);
1761
+ const effect = _optionalChain([node, 'access', _86 => _86.effects, 'optionalAccess', _87 => _87.find, 'call', _88 => _88((e) => e.id === effectId)]);
1673
1762
  if (!effect) return null;
1674
1763
  return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
1675
1764
  };
@@ -1699,8 +1788,8 @@ function visibleAt(timeline, id, time, node) {
1699
1788
  if (Array.isArray(rect) && (rect[2] <= 1e-4 || rect[3] <= 1e-4)) return false;
1700
1789
  const circle = clip("clipCircle");
1701
1790
  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) => {
1791
+ const hasFill = node.type === "path" ? !!node.fill && node.fill !== "none" : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node).some((p) => p.fill && p.fill !== "none");
1792
+ 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
1793
  const v = trackValue(timeline.tracks.get(motionTrackKey(p.id, "drawEnd")), time);
1705
1794
  return typeof v !== "number" || v > 0.01;
1706
1795
  }));
@@ -1750,7 +1839,12 @@ function checkMotionScene(scene) {
1750
1839
  if (command3.type === "follow" && known(command3.path, "unknown-path", "path", where) && nodes.get(command3.path).node.type !== "path")
1751
1840
  issues.push(motionIssue("not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
1752
1841
  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]]))
1842
+ if (command3.type !== "play" && command3.split) {
1843
+ for (const id of targets)
1844
+ if (!motionTextLayout(nodes, id))
1845
+ issues.push(motionIssue("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] }));
1846
+ }
1847
+ if (command3.type === "play" && !_optionalChain([scene, 'access', _89 => _89.clips, 'optionalAccess', _90 => _90[command3.clip]]))
1754
1848
  issues.push(motionIssue("unknown-clip", `There is no clip ${namedWithSuggestion(command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
1755
1849
  if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
1756
1850
  const into = nodes.get(command3.into);
@@ -1781,7 +1875,7 @@ function checkMotionScene(scene) {
1781
1875
  }
1782
1876
  for (const id of targets) {
1783
1877
  const node = nodes.get(id).node;
1784
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
1878
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
1785
1879
  if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
1786
1880
  issues.push(motionIssue("paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
1787
1881
  }
@@ -1794,7 +1888,7 @@ function checkMotionScene(scene) {
1794
1888
  else
1795
1889
  for (const id of targets) {
1796
1890
  const node = nodes.get(id).node;
1797
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
1891
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
1798
1892
  if (paths.some((p) => typeof p[key] !== "string"))
1799
1893
  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] }));
1800
1894
  }
@@ -1865,7 +1959,7 @@ function checkMotionScene(scene) {
1865
1959
  if (!shot.at) return;
1866
1960
  const timing = timeline.shots[i];
1867
1961
  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)`;
1962
+ 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', _91 => _91.narration, 'optionalAccess', _92 => _92.words, 'access', _93 => _93.length]), () => ( 0))} words (indexes from 0)`;
1869
1963
  issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
1870
1964
  } else if (timing.missedBy !== void 0) {
1871
1965
  const late = Math.round(timing.missedBy);
@@ -1898,7 +1992,7 @@ function checkMotionScene(scene) {
1898
1992
  const cam = frame.camera;
1899
1993
  const docIndex = indexMotionNodes(frame.document.nodes);
1900
1994
  for (const id of command3.targets) {
1901
- const b = _optionalChain([docIndex, 'access', _84 => _84.get, 'call', _85 => _85(id), 'optionalAccess', _86 => _86.bounds]);
1995
+ const b = _optionalChain([docIndex, 'access', _94 => _94.get, 'call', _95 => _95(id), 'optionalAccess', _96 => _96.bounds]);
1902
1996
  if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
1903
1997
  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
1998
  if (outside) {
@@ -2130,9 +2224,9 @@ function applyMotionEdits(scene, edits) {
2130
2224
  let next = scene;
2131
2225
  for (let i = 0; i < list.length; i++) {
2132
2226
  const edit = list[i];
2133
- const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _87 => _87.op])}): ` : "";
2227
+ const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _97 => _97.op])}): ` : "";
2134
2228
  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.` };
2229
+ return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _98 => _98.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
2136
2230
  try {
2137
2231
  next = applyOne(next, edit);
2138
2232
  } catch (error) {
@@ -2154,7 +2248,7 @@ function resolveMotionEditRefs(scene, edits) {
2154
2248
  const resolved = [];
2155
2249
  let next = scene;
2156
2250
  for (let i = 0; i < edits.length; i++) {
2157
- const where = `op ${i + 1} (${_optionalChain([edits, 'access', _89 => _89[i], 'optionalAccess', _90 => _90.op])})`;
2251
+ const where = `op ${i + 1} (${_optionalChain([edits, 'access', _99 => _99[i], 'optionalAccess', _100 => _100.op])})`;
2158
2252
  let problem = null;
2159
2253
  const walk = (v) => {
2160
2254
  if (typeof v === "string") {
@@ -2187,9 +2281,9 @@ function resolveMotionEditRefs(scene, edits) {
2187
2281
  resolved.push(edit);
2188
2282
  const out = { op: edit.op };
2189
2283
  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;
2284
+ if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _101 => _101.set, 'optionalAccess', _102 => _102.id]) ? edit.set.id : edit.shot;
2191
2285
  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));
2286
+ const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _103 => _103.shots, 'access', _104 => _104.find, 'call', _105 => _105((s) => s.id === edit.shot), 'optionalAccess', _106 => _106.run, 'access', _107 => _107.length]))), () => ( 0));
2193
2287
  out.indexes = edit.commands.map((_, k) => at + k);
2194
2288
  }
2195
2289
  if (edit.op === "move_command") out.indexes = [edit.to];
@@ -2342,13 +2436,13 @@ function toFlairSvgMotion(scene, options = {}) {
2342
2436
  if (!route) continue;
2343
2437
  const routeId = freshId(`${id}--follow-route`);
2344
2438
  ids.set(seg.path, routeId);
2345
- routes.push(`<path id="${routeId}" d="${_chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
2439
+ routes.push(`<path id="${routeId}" d="${_chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, route, { precision })}" fill="none"/>`);
2346
2440
  }
2347
2441
  if (ids.size) {
2348
2442
  const wrapper = freshId(`${id}--follow`);
2349
2443
  const centre = freshId(`${id}--follow-centre`);
2350
2444
  const c = entry.center;
2351
- const at = _optionalChain([motionNodeOffset, 'call', _98 => _98(entry, timeline, 0, nodes), 'optionalAccess', _99 => _99.follow]);
2445
+ const at = _optionalChain([motionNodeOffset, 'call', _108 => _108(entry, timeline, 0, nodes), 'optionalAccess', _109 => _109.follow]);
2352
2446
  const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
2353
2447
  (wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
2354
2448
  follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
@@ -2378,7 +2472,7 @@ function toFlairSvgMotion(scene, options = {}) {
2378
2472
  raw: (t) => transformAt(t, true)
2379
2473
  });
2380
2474
  }
2381
- const paths = node.type === "path" ? [node] : _chunkYJLCBA7Vcjs.collectPathNodes.call(void 0, node);
2475
+ const paths = node.type === "path" ? [node] : _chunk7MD7C6XQcjs.collectPathNodes.call(void 0, node);
2382
2476
  for (const path of paths) {
2383
2477
  if (pathsSeen.has(path.id)) continue;
2384
2478
  pathsSeen.add(path.id);
@@ -2400,7 +2494,7 @@ function toFlairSvgMotion(scene, options = {}) {
2400
2494
  if (shapeSegments.length) {
2401
2495
  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
2496
  else {
2403
- const inverse = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, node));
2497
+ const inverse = _chunk7MD7C6XQcjs.invertMatrix.call(void 0, _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node));
2404
2498
  channels.push({
2405
2499
  id,
2406
2500
  kind: "attr",
@@ -2409,10 +2503,10 @@ function toFlairSvgMotion(scene, options = {}) {
2409
2503
  exact: () => false,
2410
2504
  value: (t) => {
2411
2505
  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]));
2506
+ const now = _chunk7MD7C6XQcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _110 => _110(frame.document.nodes), 'access', _111 => _111.get, 'call', _112 => _112(id), 'optionalAccess', _113 => _113.node]));
2413
2507
  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) });
2508
+ const bezier = _chunkXGD3FSNCcjs.transformBezierPath.call(void 0, _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, now, _chunk7MD7C6XQcjs.IDENTITY_MATRIX, { effects: false }), inverse);
2509
+ return _chunkXGD3FSNCcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
2416
2510
  }
2417
2511
  });
2418
2512
  }
@@ -2430,8 +2524,8 @@ function toFlairSvgMotion(scene, options = {}) {
2430
2524
  ...delay > 0 ? { delay: round2(delay) } : {},
2431
2525
  ms: round2(ms),
2432
2526
  ease: written,
2433
- ..._optionalChain([segment, 'optionalAccess', _104 => _104.behavior]) ? { behavior: segment.behavior } : {},
2434
- ..._optionalChain([segment, 'optionalAccess', _105 => _105.steps]) ? { strobe: segment.steps } : {}
2527
+ ..._optionalChain([segment, 'optionalAccess', _114 => _114.behavior]) ? { behavior: segment.behavior } : {},
2528
+ ..._optionalChain([segment, 'optionalAccess', _115 => _115.steps]) ? { strobe: segment.steps } : {}
2435
2529
  };
2436
2530
  if (channel.kind === "view") animate.push({ ...base, view: to });
2437
2531
  else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
@@ -2518,10 +2612,10 @@ function toFlairSvgMotion(scene, options = {}) {
2518
2612
  }
2519
2613
  if (scene.motionBlur) notes.push("Motion blur is drawn on the stage only; Flair plays the scene sharp.");
2520
2614
  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 });
2615
+ let svg = _chunk7MD7C6XQcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
2522
2616
  if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
2523
2617
  let motion = { svg, animate };
2524
- if (_optionalChain([scene, 'access', _106 => _106.controls, 'optionalAccess', _107 => _107.length])) {
2618
+ if (_optionalChain([scene, 'access', _116 => _116.controls, 'optionalAccess', _117 => _117.length])) {
2525
2619
  const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
2526
2620
  const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
2527
2621
  svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
@@ -2543,7 +2637,7 @@ function toFlairVectorEffect(scene, options = {}) {
2543
2637
  tags: _nullishCoalesce(options.tags, () => ( [])),
2544
2638
  motion: out.motion,
2545
2639
  hold: out.hold,
2546
- ..._optionalChain([scene, 'access', _108 => _108.presets, 'optionalAccess', _109 => _109.length]) ? { presets: scene.presets } : {},
2640
+ ..._optionalChain([scene, 'access', _118 => _118.presets, 'optionalAccess', _119 => _119.length]) ? { presets: scene.presets } : {},
2547
2641
  ...out.trigger ? { trigger: out.trigger } : {}
2548
2642
  };
2549
2643
  }
@@ -2587,7 +2681,7 @@ function resolvePlaceholders(motion, notes) {
2587
2681
  const filled = text.replace(PLACEHOLDER, (_, name) => {
2588
2682
  const d = declared.get(name);
2589
2683
  if (!d) unknown.add(name);
2590
- return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _110 => _110.value]), () => ( ""))).replace(/"/g, '\\"');
2684
+ return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _120 => _120.value]), () => ( ""))).replace(/"/g, '\\"');
2591
2685
  });
2592
2686
  for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
2593
2687
  return { motion: JSON.parse(filled), controls };
@@ -2602,14 +2696,14 @@ function easingOf(ease, fallback) {
2602
2696
  return fallback;
2603
2697
  }
2604
2698
  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);
2699
+ const t = _chunk7MD7C6XQcjs.parseSvgTransform.call(void 0, String(value));
2700
+ 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
2701
  const sx = Math.hypot(o[0], o[1]);
2608
2702
  if (!(sx > 1e-9)) return null;
2609
2703
  const sy = (o[0] * o[3] - o[1] * o[2]) / sx;
2610
2704
  if (Math.abs(o[2] + o[1] / sx * sy) > 1e-6 || Math.abs(o[3] - o[0] / sx * sy) > 1e-6) return null;
2611
2705
  const c = entry.center;
2612
- const moved = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, o, c);
2706
+ const moved = _chunk7MD7C6XQcjs.applyMatrix.call(void 0, o, c);
2613
2707
  return { dx: moved.x - c.x, dy: moved.y - c.y, rotation: Math.atan2(o[1], o[0]) * 180 / Math.PI, sx, sy };
2614
2708
  }
2615
2709
  var near = (a, b, eps = 1e-6) => Math.abs(a - b) < eps;
@@ -2641,7 +2735,7 @@ function commandsFor(anim, nodes, entered, notes) {
2641
2735
  if (anim.along) {
2642
2736
  const path = nodes.get(anim.along);
2643
2737
  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) });
2738
+ else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _121 => _121.at, 'optionalAccess', _122 => _122[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _123 => _123.at, 'optionalAccess', _124 => _124[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2645
2739
  }
2646
2740
  for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
2647
2741
  if (attr === "opacity") {
@@ -2652,7 +2746,7 @@ function commandsFor(anim, nodes, entered, notes) {
2652
2746
  out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
2653
2747
  } else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
2654
2748
  } 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") });
2749
+ if (_optionalChain([behavior, 'optionalAccess', _125 => _125.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2656
2750
  else {
2657
2751
  if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
2658
2752
  out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
@@ -2694,7 +2788,7 @@ function fromFlairSvgMotion(input, options = {}) {
2694
2788
  const notes = [];
2695
2789
  if (!input || typeof input.svg !== "string") throw new Error('Give a Flair SvgMotion: { svg: "<svg \u2026>", animate: [ \u2026 ] }.');
2696
2790
  const { motion, controls } = resolvePlaceholders(input, notes);
2697
- const artwork = _chunkYJLCBA7Vcjs.parseVectorSvg.call(void 0, motion.svg);
2791
+ const artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, motion.svg);
2698
2792
  const nodes = indexMotionNodes(artwork.nodes);
2699
2793
  const byStep = /* @__PURE__ */ new Map();
2700
2794
  for (const anim of _nullishCoalesce(motion.animate, () => ( []))) {
@@ -2941,11 +3035,11 @@ function toLottie(scene, options = {}) {
2941
3035
  const items = [];
2942
3036
  const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
2943
3037
  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);
3038
+ if (!shapeSegments.length) return _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
3039
+ const now = _optionalChain([indexMotionNodes, 'call', _126 => _126(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _127 => _127.get, 'call', _128 => _128(path.id), 'optionalAccess', _129 => _129.node]);
3040
+ return now && now.type === "path" ? _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunk7MD7C6XQcjs.vectorPathWorldBezier.call(void 0, path);
2947
3041
  };
2948
- const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
3042
+ const rest = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
2949
3043
  rest.forEach((contour, n) => {
2950
3044
  let ks = { a: 0, k: contour };
2951
3045
  if (shapeSegments.length) {
@@ -2954,7 +3048,7 @@ function toLottie(scene, options = {}) {
2954
3048
  const count = Math.max(1, Math.ceil(end * fps / 1e3));
2955
3049
  for (let k = 0; k <= count && fits; k++) {
2956
3050
  const t = end * k / count;
2957
- const c = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(t)), round2)[n];
3051
+ const c = lottieContours(_chunkXGD3FSNCcjs.toBezierPath.call(void 0, geometryAt(t)), round2)[n];
2958
3052
  if (!c || c.v.length !== contour.v.length || c.c !== contour.c) fits = false;
2959
3053
  else keys.push({ t: frame(t), s: [c], ...k < count ? { o: { x: [0], y: [0] }, i: { x: [1], y: [1] } } : {} });
2960
3054
  }
@@ -2990,7 +3084,7 @@ function toLottie(scene, options = {}) {
2990
3084
  lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
2991
3085
  ml: 4
2992
3086
  });
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.`);
3087
+ if (_optionalChain([path, 'access', _130 => _130.strokeDasharray, 'optionalAccess', _131 => _131.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
2994
3088
  if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
2995
3089
  }
2996
3090
  const fill = paintOf(path.fill, "fill", path.id);
@@ -3017,8 +3111,8 @@ function toLottie(scene, options = {}) {
3017
3111
  if (node.type === "path") inner = [...pathShapes(node)];
3018
3112
  else {
3019
3113
  inner = shown(node.children).reverse().map(nodeGroup);
3020
- const m = _chunkYJLCBA7Vcjs.nodeMatrix.call(void 0, node);
3021
- if (m !== _chunkYJLCBA7Vcjs.IDENTITY_MATRIX) {
3114
+ const m = _chunk7MD7C6XQcjs.nodeMatrix.call(void 0, node);
3115
+ if (m !== _chunk7MD7C6XQcjs.IDENTITY_MATRIX) {
3022
3116
  const parts = staticParts(m);
3023
3117
  if (!parts) notes.push(`"${node.id}": its transform skews, which is not exported; it is drawn without the skew.`);
3024
3118
  else {
@@ -3031,7 +3125,7 @@ function toLottie(scene, options = {}) {
3031
3125
  const body = { ty: "gr", nm: `${node.id} (own)`, it: [...inner, innerTr] };
3032
3126
  return { ty: "gr", nm: _nullishCoalesce(node.name, () => ( node.id)), it: [body, poseTransform(entry)] };
3033
3127
  };
3034
- const artwork = { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
3128
+ const artwork = { ...scene.artwork, nodes: _chunk7MD7C6XQcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
3035
3129
  const content = shown(artwork.nodes).reverse().map(nodeGroup);
3036
3130
  if (artwork.background && rgba(artwork.background))
3037
3131
  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 +3174,7 @@ var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName
3080
3174
  var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
3081
3175
  var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
3082
3176
  var num = (el, attr, fallback = 0) => {
3083
- const v = _optionalChain([el, 'optionalAccess', _122 => _122.getAttribute, 'call', _123 => _123(attr)]);
3177
+ const v = _optionalChain([el, 'optionalAccess', _132 => _132.getAttribute, 'call', _133 => _133(attr)]);
3084
3178
  const n = v === null || v === void 0 ? NaN : Number(v);
3085
3179
  return Number.isFinite(n) ? n : fallback;
3086
3180
  };
@@ -3130,11 +3224,11 @@ function preset(prst, w, h) {
3130
3224
  const poly = (pts) => [{ closed: true, anchors: pts.map(([x, y]) => ({ x, y })) }];
3131
3225
  switch (prst) {
3132
3226
  case "rect":
3133
- return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3227
+ return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3134
3228
  case "roundRect":
3135
- return [_chunkYJLCBA7Vcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
3229
+ return [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h }, Math.min(w, h) * 0.16667)];
3136
3230
  case "ellipse":
3137
- return [_chunkYJLCBA7Vcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3231
+ return [_chunk7MD7C6XQcjs.ellipseSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3138
3232
  case "triangle":
3139
3233
  return poly([[w / 2, 0], [w, h], [0, h]]);
3140
3234
  case "rtTriangle":
@@ -3188,8 +3282,8 @@ function placement(xfrm, map) {
3188
3282
  const ext = kid(xfrm, "ext");
3189
3283
  const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
3190
3284
  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;
3285
+ const fx = _optionalChain([xfrm, 'optionalAccess', _134 => _134.getAttribute, 'call', _135 => _135("flipH")]) === "1" ? -1 : 1;
3286
+ const fy = _optionalChain([xfrm, 'optionalAccess', _136 => _136.getAttribute, 'call', _137 => _137("flipV")]) === "1" ? -1 : 1;
3193
3287
  const cx = x + w / 2;
3194
3288
  const cy = y + h / 2;
3195
3289
  const cos = Math.cos(rot);
@@ -3216,7 +3310,7 @@ function shapes(ctx, tree, map) {
3216
3310
  const nv = el.firstElementChild;
3217
3311
  const cNvPr = kid(nv, "cNvPr");
3218
3312
  const spid = num(cNvPr, "id", -1);
3219
- const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _128 => _128.getAttribute, 'call', _129 => _129("name")]), () => ( ""));
3313
+ const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _138 => _138.getAttribute, 'call', _139 => _139("name")]), () => ( ""));
3220
3314
  if (el.localName === "grpSp") {
3221
3315
  const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
3222
3316
  const off = kid(xfrm, "off");
@@ -3237,12 +3331,12 @@ function shapes(ctx, tree, map) {
3237
3331
  if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
3238
3332
  const spPr = kid(el, "spPr");
3239
3333
  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")]);
3334
+ const prst = _optionalChain([kid, 'call', _140 => _140(spPr, "prstGeom"), 'optionalAccess', _141 => _141.getAttribute, 'call', _142 => _142("prst")]);
3241
3335
  const cust = kid(spPr, "custGeom");
3242
3336
  let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
3243
3337
  if (!subpaths) {
3244
3338
  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 })];
3339
+ subpaths = [_chunk7MD7C6XQcjs.rectSubpath.call(void 0, { x: 0, y: 0, width: w, height: h })];
3246
3340
  }
3247
3341
  const style = kid(el, "style");
3248
3342
  const fill = kid(spPr, "noFill") ? null : _nullishCoalesce(colour(ctx, kid(spPr, "solidFill")), () => ( (el.localName === "cxnSp" ? null : colour(ctx, kid(style, "fillRef")))));
@@ -3351,13 +3445,13 @@ function command(ctx, ctn, scene, artwork, target, hidden) {
3351
3445
  }
3352
3446
  if (cls === "path") {
3353
3447
  const motion = deep(ctn, "animMotion")[0];
3354
- const d = _optionalChain([motion, 'optionalAccess', _133 => _133.getAttribute, 'call', _134 => _134("path")]);
3448
+ const d = _optionalChain([motion, 'optionalAccess', _143 => _143.getAttribute, 'call', _144 => _144("path")]);
3355
3449
  if (!d) return null;
3356
3450
  const entry = artwork.flatMap(function all(n) {
3357
3451
  return n.type === "group" ? [n, ...n.children.flatMap(all)] : [n];
3358
3452
  }).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;
3453
+ const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _145 => _145.transform]), () => ( [1, 0, 0, 1, 0, 0]));
3454
+ const p = _optionalChain([entry, 'optionalAccess', _146 => _146.type]) === "path" ? _optionalChain([entry, 'access', _147 => _147.subpaths, 'access', _148 => _148[0], 'optionalAccess', _149 => _149.anchors]) : void 0;
3361
3455
  const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
3362
3456
  const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
3363
3457
  const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
@@ -3409,9 +3503,9 @@ async function fromPptxAnimation(data, options = {}) {
3409
3503
  if (!path.includes("theme/")) continue;
3410
3504
  const theme = await xml(ctx, path);
3411
3505
  const scheme = deep(theme, "clrScheme")[0];
3412
- for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _140 => _140.children]), () => ( [])))) {
3506
+ for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _150 => _150.children]), () => ( [])))) {
3413
3507
  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")]);
3508
+ const hex = _optionalChain([v, 'optionalAccess', _151 => _151.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _152 => _152.getAttribute, 'call', _153 => _153("lastClr")]);
3415
3509
  if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
3416
3510
  }
3417
3511
  break;
@@ -3518,7 +3612,7 @@ var AnimationEditorController = (_class = class {
3518
3612
  time: p.time,
3519
3613
  playing: p.playing,
3520
3614
  loop: p.loop,
3521
- currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _144 => _144(timeline, p.time), 'optionalAccess', _145 => _145.id]), () => ( null)),
3615
+ currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _154 => _154(timeline, p.time), 'optionalAccess', _155 => _155.id]), () => ( null)),
3522
3616
  selection: this.selection,
3523
3617
  readOnly: this.readOnly,
3524
3618
  error: this.error,
@@ -3557,7 +3651,7 @@ var AnimationEditorController = (_class = class {
3557
3651
  this.applying = false;
3558
3652
  }
3559
3653
  this.notify();
3560
- _optionalChain([this, 'access', _146 => _146.onChange, 'optionalCall', _147 => _147(scene)]);
3654
+ _optionalChain([this, 'access', _156 => _156.onChange, 'optionalCall', _157 => _157(scene)]);
3561
3655
  }
3562
3656
  commit(label, next) {
3563
3657
  const before = this.scene;
@@ -3730,6 +3824,8 @@ var BASE = {
3730
3824
  with: { type: "string", enum: ["after", "previous"], description: '"after" (default) starts when the commands before it finish; "previous" starts together with the command before.' },
3731
3825
  ease: EASE,
3732
3826
  note: { type: "string", description: "Why this command is here, in a few words." },
3827
+ 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." },
3828
+ 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
3829
  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
3830
  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
3831
  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.` }
@@ -4122,9 +4218,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4122
4218
  handler: ({ from = 0, to, limit = 200 }) => {
4123
4219
  const s = scene();
4124
4220
  const timeline = compileMotionScene(s);
4125
- const words = _nullishCoalesce(_optionalChain([s, 'access', _148 => _148.narration, 'optionalAccess', _149 => _149.words]), () => ( []));
4221
+ const words = _nullishCoalesce(_optionalChain([s, 'access', _158 => _158.narration, 'optionalAccess', _159 => _159.words]), () => ( []));
4126
4222
  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]);
4223
+ const shotAt = (ms) => _optionalChain([timeline, 'access', _160 => _160.shots, 'access', _161 => _161.find, 'call', _162 => _162((x) => ms >= x.start && ms < x.end), 'optionalAccess', _163 => _163.id]);
4128
4224
  const beats = [];
4129
4225
  if (s.beat && s.beat.bpm > 0) {
4130
4226
  const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
@@ -4145,6 +4241,21 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4145
4241
  };
4146
4242
  }
4147
4243
  };
4244
+ const getTextLayout = {
4245
+ name: "get_text_layout",
4246
+ title: "Read outlined text as letters, words and lines",
4247
+ 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.',
4248
+ inputSchema: object({ group: { type: "string", minLength: 1, description: "Element id of the group of letters." } }, ["group"]),
4249
+ annotations: { title: "Read outlined text as letters, words and lines", ...READ },
4250
+ handler: ({ group }) => {
4251
+ const s = scene();
4252
+ const nodes = indexMotionNodes(s.artwork.nodes);
4253
+ if (!nodes.has(group)) throw new Error(`There is no element ${namedWithSuggestion(group, [...nodes.keys()])}.`);
4254
+ const layout = motionTextLayout(nodes, group);
4255
+ if (!layout) throw new Error(`"${group}" is not a group of paths; convert the text to outlines (one path a letter) and group it.`);
4256
+ return { group, letters: layout.lines.reduce((n, l) => n + l.words.reduce((m, w) => m + w.letters.length, 0), 0), ...layout };
4257
+ }
4258
+ };
4148
4259
  const getMotionPath = {
4149
4260
  name: "get_motion_path",
4150
4261
  title: "Read where a node travels",
@@ -4210,7 +4321,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4210
4321
  handler: ({ svg }) => {
4211
4322
  let artwork;
4212
4323
  try {
4213
- artwork = _chunkYJLCBA7Vcjs.parseVectorSvg.call(void 0, svg);
4324
+ artwork = _chunk7MD7C6XQcjs.parseVectorSvg.call(void 0, svg);
4214
4325
  } catch (error) {
4215
4326
  throw new Error(`The SVG could not be read: ${error.message}. Nothing was changed.`);
4216
4327
  }
@@ -4431,7 +4542,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4431
4542
  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
4543
  annotations: { title: "Add commands to a shot", ...WRITE },
4433
4544
  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));
4545
+ const before = _nullishCoalesce(_optionalChain([scene, 'call', _164 => _164(), 'access', _165 => _165.shots, 'access', _166 => _166.find, 'call', _167 => _167((s) => s.id === shot), 'optionalAccess', _168 => _168.run, 'access', _169 => _169.length]), () => ( 0));
4435
4546
  const first = _nullishCoalesce(at, () => ( before));
4436
4547
  return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
4437
4548
  const shots = describeMotionShots(s);
@@ -4562,7 +4673,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4562
4673
  return { redone, ...redone ? { label } : {} };
4563
4674
  }
4564
4675
  };
4565
- const reads = [getAnimation, getShot, findElements, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
4676
+ const reads = [getAnimation, getShot, findElements, getTextLayout, getMotionPath, getTimingGrid, checkAnimation, renderFrame, exportFlairMotion, exportFlairEffect, exportLottie, seekAnimation];
4566
4677
  const writes = [setArtworkSvg, importPptx, setDrivers, setClip, copyAnimation, fitAnimation, importFlairEffect, insertShots, updateShot, deleteShots, moveShot, addCommands, updateCommand, deleteCommands, moveCommand, setSettings, setControls, editAnimation, writeAnimation, undo, redo];
4567
4678
  return {
4568
4679
  id: _nullishCoalesce(options.id, () => ( "animation")),
@@ -4595,6 +4706,7 @@ Commands
4595
4706
  - enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
4596
4707
  - 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
4708
  - 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.
4709
+ - 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
4710
  - 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
4711
  - Fast motion reads better with blur: set_animation_settings { "motionBlur": { "shutter": 180 } } (stage and rendered frames only).
4600
4712
  - 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 +4738,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
4626
4738
  var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
4627
4739
  var NODES = /* @__PURE__ */ new Set(["into", "path"]);
4628
4740
  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);
4741
+ return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _170 => _170.properties, 'optionalAccess', _171 => _171.type, 'optionalAccess', _172 => _172.const]) === type);
4630
4742
  }
4631
4743
  function unitOf(type, name) {
4632
4744
  if (name === "duration" || name === "delay" || name === "stagger") return "ms";
@@ -4661,7 +4773,7 @@ function kindOf(name, schema) {
4661
4773
  }
4662
4774
  function motionCommandFields(type) {
4663
4775
  const schema = branch(type);
4664
- if (!_optionalChain([schema, 'optionalAccess', _163 => _163.properties])) return [];
4776
+ if (!_optionalChain([schema, 'optionalAccess', _173 => _173.properties])) return [];
4665
4777
  const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
4666
4778
  const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
4667
4779
  const kind = kindOf(name, s);
@@ -4718,7 +4830,7 @@ function defaultMotionCommand(type, targets, scene) {
4718
4830
  if (type === "wait") return { type: "wait", duration: 500 };
4719
4831
  if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
4720
4832
  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]);
4833
+ const other = (pred) => _optionalChain([nodes, 'access', _174 => _174.find, 'call', _175 => _175((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _176 => _176.node, 'access', _177 => _177.id]);
4722
4834
  const base = { targets: [...targets] };
4723
4835
  switch (type) {
4724
4836
  case "scale":
@@ -4749,8 +4861,8 @@ function defaultMotionCommand(type, targets, scene) {
4749
4861
  }
4750
4862
  case "effect": {
4751
4863
  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]), () => ( []))) {
4864
+ const node = _optionalChain([nodes, 'access', _178 => _178.find, 'call', _179 => _179((e) => e.node.id === id), 'optionalAccess', _180 => _180.node]);
4865
+ for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _181 => _181.effects]), () => ( []))) {
4754
4866
  const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
4755
4867
  if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
4756
4868
  }
@@ -4775,11 +4887,11 @@ function motionCommandRows(scene, shotId) {
4775
4887
  return scene.shots[index].run.map((command3, i) => {
4776
4888
  const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
4777
4889
  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 } : {} };
4890
+ return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _182 => _182.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _183 => _183.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
4779
4891
  });
4780
4892
  }
4781
4893
  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]), () => ( []));
4894
+ const run = _nullishCoalesce(_optionalChain([scene, 'access', _184 => _184.shots, 'access', _185 => _185.find, 'call', _186 => _186((s) => s.id === shot), 'optionalAccess', _187 => _187.run]), () => ( []));
4783
4895
  return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
4784
4896
  }
4785
4897
  var MOTION_EASE_CHOICES = [
@@ -4864,7 +4976,7 @@ function motionCueFromKey(key) {
4864
4976
  function motionCueChoices(scene, limit = 256) {
4865
4977
  const choices = [];
4866
4978
  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;
4979
+ const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _188 => _188.narration, 'optionalAccess', _189 => _189.words, 'access', _190 => _190.map, 'call', _191 => _191((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
4868
4980
  if (scene.beat && scene.beat.bpm > 0) {
4869
4981
  for (let beat = 0; choices.length < limit; beat++) {
4870
4982
  const time = motionBeatTime(scene.beat, beat);
@@ -4874,7 +4986,7 @@ function motionCueChoices(scene, limit = 256) {
4874
4986
  choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
4875
4987
  }
4876
4988
  }
4877
- _optionalChain([scene, 'access', _182 => _182.narration, 'optionalAccess', _183 => _183.words, 'access', _184 => _184.forEach, 'call', _185 => _185((w, i) => {
4989
+ _optionalChain([scene, 'access', _192 => _192.narration, 'optionalAccess', _193 => _193.words, 'access', _194 => _194.forEach, 'call', _195 => _195((w, i) => {
4878
4990
  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
4991
  })]);
4880
4992
  return choices;
@@ -4883,7 +4995,7 @@ function motionShotCueTime(scene, cue) {
4883
4995
  return cue ? motionCueTime(scene, cue) : void 0;
4884
4996
  }
4885
4997
  function formatMotionNarration(narration) {
4886
- return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _186 => _186.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4998
+ return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _196 => _196.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
4887
4999
  }
4888
5000
  function parseMotionNarration(text) {
4889
5001
  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -5056,5 +5168,12 @@ function parseMotionDrivers(text) {
5056
5168
 
5057
5169
 
5058
5170
 
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;
5171
+
5172
+
5173
+
5174
+
5175
+
5176
+
5177
+
5178
+ 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 = 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 = 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.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; 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;
5060
5179
  //# sourceMappingURL=index.cjs.map