@pixerate/editor 0.67.1 → 0.68.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.
@@ -222,7 +222,7 @@ var COMMAND_KEYS = {
222
222
  enter: [...BASE_KEYS, "style", "direction", "distance", "scale", "shape", "orientation"],
223
223
  exit: [...BASE_KEYS, "style", "direction", "distance"],
224
224
  draw: [...BASE_KEYS, "from", "to"],
225
- move: [...BASE_KEYS, "by", "to", "blend"],
225
+ move: [...BASE_KEYS, "by", "to", "via", "pacing", "blend"],
226
226
  rotate: [...BASE_KEYS, "by", "to", "blend"],
227
227
  scale: [...BASE_KEYS, "to", "geometric", "blend"],
228
228
  fade: [...BASE_KEYS, "to"],
@@ -303,6 +303,9 @@ function commandShapeProblems(command2, where) {
303
303
  if (command2.by !== void 0 && command2.to !== void 0) p(`give "by" or "to", not both.`);
304
304
  if (command2.by !== void 0 && !isPoint(command2.by)) p(`"by" must be { "x": number, "y": number }.`);
305
305
  if (command2.to !== void 0 && !isPoint(command2.to)) p(`"to" must be { "x": number, "y": number }.`);
306
+ if (command2.via !== void 0 && !(Array.isArray(command2.via) && command2.via.length > 0 && command2.via.length <= 64 && command2.via.every(isPoint))) p(`"via" must be a list of 1 to 64 points { "x": number, "y": number } (document units).`);
307
+ if (command2.pacing !== void 0 && command2.pacing !== "even" && command2.pacing !== "equal") p(`"pacing" must be "even" (steady speed) or "equal" (each leg the same time).`);
308
+ if (command2.pacing !== void 0 && command2.via === void 0) p(`"pacing" goes with "via".`);
306
309
  break;
307
310
  case "rotate":
308
311
  if (command2.by === void 0 && command2.to === void 0) p(`give "by" or "to" (degrees).`);
@@ -503,6 +506,45 @@ function matchMotionNodes(from, into) {
503
506
  return out;
504
507
  }
505
508
 
509
+ // src/animation-editor/smooth.ts
510
+ function smoothMotionLegs(times, values) {
511
+ const n = values.length;
512
+ const slope = new Array(n).fill(0);
513
+ const secant = (i) => (values[i + 1] - values[i]) / Math.max(1e-9, times[i + 1] - times[i]);
514
+ for (let i = 1; i < n - 1; i++) {
515
+ const a = secant(i - 1);
516
+ const b = secant(i);
517
+ if (a * b <= 0) continue;
518
+ const ha = times[i] - times[i - 1];
519
+ const hb = times[i + 1] - times[i];
520
+ slope[i] = 3 * (ha + hb) / ((2 * hb + ha) / a + (hb + 2 * ha) / b);
521
+ }
522
+ const legs = [];
523
+ for (let i = 0; i + 1 < n; i++) {
524
+ const dt = times[i + 1] - times[i];
525
+ const dv = values[i + 1] - values[i];
526
+ if (Math.abs(dv) < 1e-9) {
527
+ legs.push({ start: times[i], end: times[i + 1], from: values[i], to: values[i + 1], ease: "linear" });
528
+ continue;
529
+ }
530
+ const y1 = slope[i] * dt / (3 * dv);
531
+ const y2 = 1 - slope[i + 1] * dt / (3 * dv);
532
+ legs.push({ start: times[i], end: times[i + 1], from: values[i], to: values[i + 1], ease: { type: "cubic-bezier", x1: 1 / 3, y1, x2: 2 / 3, y2 } });
533
+ }
534
+ return legs;
535
+ }
536
+ function smoothMotionTimes(points, start, duration, pacing = "even") {
537
+ const legs = points.slice(1).map((p, i) => pacing === "equal" ? 1 : Math.hypot(p.x - points[i].x, p.y - points[i].y));
538
+ const total = legs.reduce((a, b) => a + b, 0) || legs.length || 1;
539
+ const times = [start];
540
+ let acc = 0;
541
+ for (const l of legs) {
542
+ acc += total > 0 ? l : 1;
543
+ times.push(start + duration * acc / total);
544
+ }
545
+ return times;
546
+ }
547
+
506
548
  // src/animation-editor/compile.ts
507
549
  var indexCache = /* @__PURE__ */ new WeakMap();
508
550
  function indexMotionNodes(nodes) {
@@ -764,6 +806,7 @@ function motionCycleDuration(command2, scene, target) {
764
806
  const ms = length * MOTION_DRAW_MS_PER_UNIT;
765
807
  return Math.round(Math.min(MOTION_DRAW_RANGE[1], Math.max(MOTION_DRAW_RANGE[0], ms)));
766
808
  }
809
+ if (command2.type === "move" && _optionalChain([command2, 'access', _22 => _22.via, 'optionalAccess', _23 => _23.length])) return MOTION_DEFAULT_DURATIONS.move + 400 * command2.via.length;
767
810
  return MOTION_DEFAULT_DURATIONS[command2.type];
768
811
  }
769
812
  var MOTION_EASE_OUT = { type: "cubic-bezier", x1: 1 / 3, y1: 1, x2: 2 / 3, y2: 1 };
@@ -892,7 +935,7 @@ function compileMotionScene(scene) {
892
935
  const style = _nullishCoalesce(command2.style, () => ( "fade"));
893
936
  const opacity = rest("opacity");
894
937
  const reveal = style === "wipe" ? motionRevealClip(entry, { style, direction: command2.direction }) : style === "iris" ? motionRevealClip(entry, { style, shape: command2.shape }) : style === "split" ? motionRevealClip(entry, { style, orientation: command2.orientation }) : null;
895
- for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _22 => _22.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
938
+ for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _24 => _24.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
896
939
  if (reveal) {
897
940
  seg("opacity", opacity, "linear", start, start);
898
941
  seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
@@ -954,14 +997,28 @@ function compileMotionScene(scene) {
954
997
  }
955
998
  case "move": {
956
999
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
957
- let dx = _nullishCoalesce(_optionalChain([command2, 'access', _23 => _23.by, 'optionalAccess', _24 => _24.x]), () => ( 0));
958
- let dy = _nullishCoalesce(_optionalChain([command2, 'access', _25 => _25.by, 'optionalAccess', _26 => _26.y]), () => ( 0));
1000
+ let dx = _nullishCoalesce(_optionalChain([command2, 'access', _25 => _25.by, 'optionalAccess', _26 => _26.x]), () => ( 0));
1001
+ let dy = _nullishCoalesce(_optionalChain([command2, 'access', _27 => _27.by, 'optionalAccess', _28 => _28.y]), () => ( 0));
959
1002
  if (command2.to) {
960
1003
  const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
961
1004
  const target = _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, command2.to);
962
1005
  dx = target.x - (entry.center.x + num("x"));
963
1006
  dy = target.y - (entry.center.y + num("y"));
964
1007
  }
1008
+ if (_optionalChain([command2, 'access', _29 => _29.via, 'optionalAccess', _30 => _30.length])) {
1009
+ const inv = _chunkYJLCBA7Vcjs.invertMatrix.call(void 0, entry.parentWorld);
1010
+ const x0 = num("x");
1011
+ const y0 = num("y");
1012
+ const add = command2.blend === "add";
1013
+ const offsets = [{ x: 0, y: 0 }, ...command2.via.map((p) => _chunkYJLCBA7Vcjs.applyMatrix.call(void 0, inv, p)).map((p) => ({ x: p.x - entry.center.x - x0, y: p.y - entry.center.y - y0 })), { x: dx, y: dy }];
1014
+ const times = smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command2.pacing, () => ( "even")));
1015
+ for (const axis of ["x", "y"]) {
1016
+ const base = add ? 0 : axis === "x" ? x0 : y0;
1017
+ for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
1018
+ seg(axis, base + leg.to, leg.ease, leg.start, leg.end, { from: base + leg.from, ...add ? { blend: "add" } : {} });
1019
+ }
1020
+ break;
1021
+ }
965
1022
  if (command2.blend === "add") {
966
1023
  seg("x", dx, e, start, end, { from: 0, blend: "add" });
967
1024
  seg("y", dy, e, start, end, { from: 0, blend: "add" });
@@ -1059,7 +1116,7 @@ var MOTION_DRAW_EFFECT_ID = "~draw";
1059
1116
  var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
1060
1117
  var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
1061
1118
  function applyMotionControlValues(scene, values) {
1062
- if (!values || !_optionalChain([scene, 'access', _27 => _27.controls, 'optionalAccess', _28 => _28.length])) return scene;
1119
+ if (!values || !_optionalChain([scene, 'access', _31 => _31.controls, 'optionalAccess', _32 => _32.length])) return scene;
1063
1120
  const map = /* @__PURE__ */ new Map();
1064
1121
  for (const control of scene.controls) {
1065
1122
  const value = values[control.name];
@@ -1105,7 +1162,7 @@ function shapeIn(entry, shape) {
1105
1162
  }
1106
1163
  function shapeAt(entry, timeline, nodes, time) {
1107
1164
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
1108
- if (!_optionalChain([track, 'optionalAccess', _29 => _29.length])) return null;
1165
+ if (!_optionalChain([track, 'optionalAccess', _33 => _33.length])) return null;
1109
1166
  const s = activeSegment(track, time);
1110
1167
  const fromId = String(s ? s.from : track[0].from);
1111
1168
  if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
@@ -1128,8 +1185,8 @@ function motionFollowRoute(entry, path) {
1128
1185
  }
1129
1186
  function followAt(entry, timeline, nodes, time) {
1130
1187
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
1131
- const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _30 => _30[0]])));
1132
- if (!_optionalChain([s, 'optionalAccess', _31 => _31.path])) return null;
1188
+ const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _34 => _34[0]])));
1189
+ if (!_optionalChain([s, 'optionalAccess', _35 => _35.path])) return null;
1133
1190
  const route = motionFollowRoute(entry, nodes.get(s.path));
1134
1191
  const progress = Number(trackValue(track, time));
1135
1192
  if (!route || !(progress >= 0)) return null;
@@ -1189,7 +1246,7 @@ function motionFrameAt(scene, time, options = {}) {
1189
1246
  if (out.visible === void 0) delete out.visible;
1190
1247
  }
1191
1248
  const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
1192
- if (effectTracks.length && _optionalChain([out, 'access', _32 => _32.effects, 'optionalAccess', _33 => _33.length])) {
1249
+ if (effectTracks.length && _optionalChain([out, 'access', _36 => _36.effects, 'optionalAccess', _37 => _37.length])) {
1193
1250
  out = {
1194
1251
  ...out,
1195
1252
  effects: out.effects.map((effect) => {
@@ -1302,7 +1359,7 @@ function motionPath(scene, id, options = {}) {
1302
1359
  const r = (n) => Math.round(n * 100) / 100;
1303
1360
  const centreAt = (t) => {
1304
1361
  const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
1305
- const b = _optionalChain([node, 'optionalAccess', _34 => _34.bounds]);
1362
+ const b = _optionalChain([node, 'optionalAccess', _38 => _38.bounds]);
1306
1363
  return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
1307
1364
  };
1308
1365
  const points = [];
@@ -1342,14 +1399,14 @@ function motionStageSvg(scene, time, options = {}) {
1342
1399
  const open = current.indexOf(">") + 1;
1343
1400
  const close = current.lastIndexOf("</svg>");
1344
1401
  const body = current.slice(open, close);
1345
- const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _35 => _35.exec, 'call', _36 => _36(body), 'optionalAccess', _37 => _37[0]]), () => ( "")) : "";
1402
+ const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _39 => _39.exec, 'call', _40 => _40(body), 'optionalAccess', _41 => _41[0]]), () => ( "")) : "";
1346
1403
  return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
1347
1404
  }
1348
1405
 
1349
1406
  // src/animation-editor/check.ts
1350
1407
  var MOTION_MIN_CHANGE_MS = 120;
1351
1408
  var NUMERIC_PARAMS = (node, effectId) => {
1352
- const effect = _optionalChain([node, 'access', _38 => _38.effects, 'optionalAccess', _39 => _39.find, 'call', _40 => _40((e) => e.id === effectId)]);
1409
+ const effect = _optionalChain([node, 'access', _42 => _42.effects, 'optionalAccess', _43 => _43.find, 'call', _44 => _44((e) => e.id === effectId)]);
1353
1410
  if (!effect) return null;
1354
1411
  return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
1355
1412
  };
@@ -1511,7 +1568,7 @@ function checkMotionScene(scene) {
1511
1568
  if (!shot.at) return;
1512
1569
  const timing = timeline.shots[i];
1513
1570
  if (timing.cue === void 0) {
1514
- 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', _41 => _41.narration, 'optionalAccess', _42 => _42.words, 'access', _43 => _43.length]), () => ( 0))} words (indexes from 0)`;
1571
+ 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', _45 => _45.narration, 'optionalAccess', _46 => _46.words, 'access', _47 => _47.length]), () => ( 0))} words (indexes from 0)`;
1515
1572
  issues.push(motionIssue("unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
1516
1573
  } else if (timing.missedBy !== void 0) {
1517
1574
  const late = Math.round(timing.missedBy);
@@ -1544,7 +1601,7 @@ function checkMotionScene(scene) {
1544
1601
  const cam = frame.camera;
1545
1602
  const docIndex = indexMotionNodes(frame.document.nodes);
1546
1603
  for (const id of command2.targets) {
1547
- const b = _optionalChain([docIndex, 'access', _44 => _44.get, 'call', _45 => _45(id), 'optionalAccess', _46 => _46.bounds]);
1604
+ const b = _optionalChain([docIndex, 'access', _48 => _48.get, 'call', _49 => _49(id), 'optionalAccess', _50 => _50.bounds]);
1548
1605
  if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
1549
1606
  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;
1550
1607
  if (outside) {
@@ -1750,9 +1807,9 @@ function applyMotionEdits(scene, edits) {
1750
1807
  let next = scene;
1751
1808
  for (let i = 0; i < list.length; i++) {
1752
1809
  const edit = list[i];
1753
- const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _47 => _47.op])}): ` : "";
1810
+ const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _51 => _51.op])}): ` : "";
1754
1811
  if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
1755
- return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _48 => _48.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
1812
+ return { ok: false, error: `${prefix}Unknown op ${namedWithSuggestion(String(_optionalChain([edit, 'optionalAccess', _52 => _52.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
1756
1813
  try {
1757
1814
  next = applyOne(next, edit);
1758
1815
  } catch (error) {
@@ -1912,7 +1969,7 @@ function toFlairSvgMotion(scene, options = {}) {
1912
1969
  const wrapper = freshId(`${id}--follow`);
1913
1970
  const centre = freshId(`${id}--follow-centre`);
1914
1971
  const c = entry.center;
1915
- const at = _optionalChain([motionNodeOffset, 'call', _49 => _49(entry, timeline, 0, nodes), 'optionalAccess', _50 => _50.follow]);
1972
+ const at = _optionalChain([motionNodeOffset, 'call', _53 => _53(entry, timeline, 0, nodes), 'optionalAccess', _54 => _54.follow]);
1916
1973
  const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
1917
1974
  (wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
1918
1975
  follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
@@ -1972,7 +2029,7 @@ function toFlairSvgMotion(scene, options = {}) {
1972
2029
  exact: () => false,
1973
2030
  value: (t) => {
1974
2031
  const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
1975
- const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _51 => _51(frame.document.nodes), 'access', _52 => _52.get, 'call', _53 => _53(id), 'optionalAccess', _54 => _54.node]));
2032
+ const now = _chunkYJLCBA7Vcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _55 => _55(frame.document.nodes), 'access', _56 => _56.get, 'call', _57 => _57(id), 'optionalAccess', _58 => _58.node]));
1976
2033
  if (!now || now.type !== "path") return "";
1977
2034
  const bezier = _chunkO2UH7LZEcjs.transformBezierPath.call(void 0, _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, now, _chunkYJLCBA7Vcjs.IDENTITY_MATRIX, { effects: false }), inverse);
1978
2035
  return _chunkO2UH7LZEcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
@@ -1993,8 +2050,8 @@ function toFlairSvgMotion(scene, options = {}) {
1993
2050
  ...delay > 0 ? { delay: round2(delay) } : {},
1994
2051
  ms: round2(ms),
1995
2052
  ease: written,
1996
- ..._optionalChain([segment, 'optionalAccess', _55 => _55.behavior]) ? { behavior: segment.behavior } : {},
1997
- ..._optionalChain([segment, 'optionalAccess', _56 => _56.steps]) ? { strobe: segment.steps } : {}
2053
+ ..._optionalChain([segment, 'optionalAccess', _59 => _59.behavior]) ? { behavior: segment.behavior } : {},
2054
+ ..._optionalChain([segment, 'optionalAccess', _60 => _60.steps]) ? { strobe: segment.steps } : {}
1998
2055
  };
1999
2056
  if (channel.kind === "view") animate.push({ ...base, view: to });
2000
2057
  else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
@@ -2083,7 +2140,7 @@ function toFlairSvgMotion(scene, options = {}) {
2083
2140
  let svg = _chunkYJLCBA7Vcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
2084
2141
  if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
2085
2142
  let motion = { svg, animate };
2086
- if (_optionalChain([scene, 'access', _57 => _57.controls, 'optionalAccess', _58 => _58.length])) {
2143
+ if (_optionalChain([scene, 'access', _61 => _61.controls, 'optionalAccess', _62 => _62.length])) {
2087
2144
  const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
2088
2145
  const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
2089
2146
  svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
@@ -2105,7 +2162,7 @@ function toFlairVectorEffect(scene, options = {}) {
2105
2162
  tags: _nullishCoalesce(options.tags, () => ( [])),
2106
2163
  motion: out.motion,
2107
2164
  hold: out.hold,
2108
- ..._optionalChain([scene, 'access', _59 => _59.presets, 'optionalAccess', _60 => _60.length]) ? { presets: scene.presets } : {},
2165
+ ..._optionalChain([scene, 'access', _63 => _63.presets, 'optionalAccess', _64 => _64.length]) ? { presets: scene.presets } : {},
2109
2166
  ...out.trigger ? { trigger: out.trigger } : {}
2110
2167
  };
2111
2168
  }
@@ -2149,7 +2206,7 @@ function resolvePlaceholders(motion, notes) {
2149
2206
  const filled = text.replace(PLACEHOLDER, (_, name) => {
2150
2207
  const d = declared.get(name);
2151
2208
  if (!d) unknown.add(name);
2152
- return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _61 => _61.value]), () => ( ""))).replace(/"/g, '\\"');
2209
+ return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _65 => _65.value]), () => ( ""))).replace(/"/g, '\\"');
2153
2210
  });
2154
2211
  for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
2155
2212
  return { motion: JSON.parse(filled), controls };
@@ -2203,7 +2260,7 @@ function commandsFor(anim, nodes, entered, notes) {
2203
2260
  if (anim.along) {
2204
2261
  const path = nodes.get(anim.along);
2205
2262
  if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
2206
- else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _62 => _62.at, 'optionalAccess', _63 => _63[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _64 => _64.at, 'optionalAccess', _65 => _65[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2263
+ else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _66 => _66.at, 'optionalAccess', _67 => _67[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _68 => _68.at, 'optionalAccess', _69 => _69[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2207
2264
  }
2208
2265
  for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
2209
2266
  if (attr === "opacity") {
@@ -2214,7 +2271,7 @@ function commandsFor(anim, nodes, entered, notes) {
2214
2271
  out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
2215
2272
  } else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
2216
2273
  } else if (attr === "fill" || attr === "stroke") {
2217
- if (_optionalChain([behavior, 'optionalAccess', _66 => _66.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2274
+ if (_optionalChain([behavior, 'optionalAccess', _70 => _70.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2218
2275
  else {
2219
2276
  if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
2220
2277
  out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
@@ -2497,7 +2554,7 @@ function toLottie(scene, options = {}) {
2497
2554
  const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
2498
2555
  const geometryAt = (t) => {
2499
2556
  if (!shapeSegments.length) return _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
2500
- const now = _optionalChain([indexMotionNodes, 'call', _67 => _67(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _68 => _68.get, 'call', _69 => _69(path.id), 'optionalAccess', _70 => _70.node]);
2557
+ const now = _optionalChain([indexMotionNodes, 'call', _71 => _71(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _72 => _72.get, 'call', _73 => _73(path.id), 'optionalAccess', _74 => _74.node]);
2501
2558
  return now && now.type === "path" ? _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, _chunkYJLCBA7Vcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkYJLCBA7Vcjs.vectorPathWorldBezier.call(void 0, path);
2502
2559
  };
2503
2560
  const rest = lottieContours(_chunkO2UH7LZEcjs.toBezierPath.call(void 0, geometryAt(0)), round2);
@@ -2543,7 +2600,7 @@ function toLottie(scene, options = {}) {
2543
2600
  lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
2544
2601
  ml: 4
2545
2602
  });
2546
- if (_optionalChain([path, 'access', _71 => _71.strokeDasharray, 'optionalAccess', _72 => _72.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
2603
+ if (_optionalChain([path, 'access', _75 => _75.strokeDasharray, 'optionalAccess', _76 => _76.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
2547
2604
  if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
2548
2605
  }
2549
2606
  const fill = paintOf(path.fill, "fill", path.id);
@@ -2694,7 +2751,7 @@ var AnimationEditorController = (_class = class {
2694
2751
  time: p.time,
2695
2752
  playing: p.playing,
2696
2753
  loop: p.loop,
2697
- currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _73 => _73(timeline, p.time), 'optionalAccess', _74 => _74.id]), () => ( null)),
2754
+ currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _77 => _77(timeline, p.time), 'optionalAccess', _78 => _78.id]), () => ( null)),
2698
2755
  selection: this.selection,
2699
2756
  readOnly: this.readOnly,
2700
2757
  error: this.error,
@@ -2733,7 +2790,7 @@ var AnimationEditorController = (_class = class {
2733
2790
  this.applying = false;
2734
2791
  }
2735
2792
  this.notify();
2736
- _optionalChain([this, 'access', _75 => _75.onChange, 'optionalCall', _76 => _76(scene)]);
2793
+ _optionalChain([this, 'access', _79 => _79.onChange, 'optionalCall', _80 => _80(scene)]);
2737
2794
  }
2738
2795
  commit(label, next) {
2739
2796
  const before = this.scene;
@@ -2937,7 +2994,7 @@ var MOTION_COMMAND_SCHEMA = {
2937
2994
  distance: { type: "number", description: "For slide: document units (default 40)." }
2938
2995
  }),
2939
2996
  command("draw", "Draws strokes on (or off) to a fraction of their length.", { to: FRACTION("Fraction drawn at the end (default 1)."), from: FRACTION("Fraction drawn at the start (default: what is drawn now).") }),
2940
- command("move", "Moves targets by an offset or so their centre lands on a point.", { blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
2997
+ command("move", "Moves targets by an offset or so their centre lands on a point.", { via: { type: "array", items: POINT("A point the centre passes through."), minItems: 1, maxItems: 64, description: 'Waypoints (document units) the centre passes through on the way to "to" or "by", smoothly (velocity carries through each) and without overshooting any. Default length 700 ms + 400 per waypoint.' }, pacing: { type: "string", enum: ["even", "equal"], description: "With via: even (default) keeps the speed steady along the path; equal gives each stretch the same time." }, blend: BLEND("replace"), by: POINT("Offset in document units."), to: POINT("Point (document coordinates) for the centre.") }),
2941
2998
  command("rotate", "Turns targets about their centre (degrees, clockwise).", { blend: BLEND("replace"), by: { type: "number", description: "Degrees to turn by." }, to: { type: "number", description: "Angle to turn to, in degrees from rest." } }),
2942
2999
  command("scale", "Scales targets about their centre (1 = rest size).", { blend: BLEND("replace"), to: { description: "A factor, or { x, y } factors.", anyOf: [{ type: "number" }, POINT("Factors per axis.")] }, geometric: { type: "boolean", description: "Grow by a steady factor, which reads as an even zoom (default false)." } }, ["to"]),
2943
3000
  command("fade", "Changes opacity.", { to: FRACTION("Opacity at the end (0\u20131).") }, ["to"]),
@@ -3255,9 +3312,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
3255
3312
  handler: ({ from = 0, to, limit = 200 }) => {
3256
3313
  const s = scene();
3257
3314
  const timeline = compileMotionScene(s);
3258
- const words = _nullishCoalesce(_optionalChain([s, 'access', _77 => _77.narration, 'optionalAccess', _78 => _78.words]), () => ( []));
3315
+ const words = _nullishCoalesce(_optionalChain([s, 'access', _81 => _81.narration, 'optionalAccess', _82 => _82.words]), () => ( []));
3259
3316
  const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
3260
- const shotAt = (ms) => _optionalChain([timeline, 'access', _79 => _79.shots, 'access', _80 => _80.find, 'call', _81 => _81((x) => ms >= x.start && ms < x.end), 'optionalAccess', _82 => _82.id]);
3317
+ const shotAt = (ms) => _optionalChain([timeline, 'access', _83 => _83.shots, 'access', _84 => _84.find, 'call', _85 => _85((x) => ms >= x.start && ms < x.end), 'optionalAccess', _86 => _86.id]);
3261
3318
  const beats = [];
3262
3319
  if (s.beat && s.beat.bpm > 0) {
3263
3320
  const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
@@ -3445,7 +3502,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
3445
3502
  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"]),
3446
3503
  annotations: { title: "Add commands to a shot", ...WRITE },
3447
3504
  handler: ({ shot, commands, at }) => {
3448
- const before = _nullishCoalesce(_optionalChain([scene, 'call', _83 => _83(), 'access', _84 => _84.shots, 'access', _85 => _85.find, 'call', _86 => _86((s) => s.id === shot), 'optionalAccess', _87 => _87.run, 'access', _88 => _88.length]), () => ( 0));
3505
+ const before = _nullishCoalesce(_optionalChain([scene, 'call', _87 => _87(), 'access', _88 => _88.shots, 'access', _89 => _89.find, 'call', _90 => _90((s) => s.id === shot), 'optionalAccess', _91 => _91.run, 'access', _92 => _92.length]), () => ( 0));
3449
3506
  const first = _nullishCoalesce(at, () => ( before));
3450
3507
  return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
3451
3508
  const shots = describeMotionShots(s);
@@ -3607,6 +3664,7 @@ Commands
3607
3664
  - enter (fade, pop, grow, slide, draw) and exit (fade, shrink, slide, undraw) bring things in and out.
3608
3665
  - 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.
3609
3666
  - 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.
3667
+ - move takes "via" waypoints for a curved, smooth path that passes exactly through each point (steady speed by default); use it instead of chaining moves, which stop at each point.
3610
3668
  - enter also has zoom (settles from larger) and rise (rises a short way, overshooting a touch); pop and zoom take a starting "scale".
3611
3669
  - morph turns a shape into another node's shape (keep the target hidden); match does the same for a whole group, part by part (Smart Animate: draw the end state as a second, hidden group whose parts share names with the first); follow moves along a path node (with "rotate", moves made meanwhile turn with the path).
3612
3670
  - Emphasis draws the eye and returns to rest: pulse (swell), shake (side to side, or "axis": "vertical"), teeter (rock), wave (bob, no settling), wiggle (seeded wander; the same seed wanders the same way) and color-pulse (tint and back).
@@ -3632,7 +3690,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
3632
3690
  var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
3633
3691
  var NODES = /* @__PURE__ */ new Set(["into", "path"]);
3634
3692
  function branch(type) {
3635
- return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _89 => _89.properties, 'optionalAccess', _90 => _90.type, 'optionalAccess', _91 => _91.const]) === type);
3693
+ return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _93 => _93.properties, 'optionalAccess', _94 => _94.type, 'optionalAccess', _95 => _95.const]) === type);
3636
3694
  }
3637
3695
  function unitOf(type, name) {
3638
3696
  if (name === "duration" || name === "delay" || name === "stagger") return "ms";
@@ -3667,7 +3725,7 @@ function kindOf(name, schema) {
3667
3725
  }
3668
3726
  function motionCommandFields(type) {
3669
3727
  const schema = branch(type);
3670
- if (!_optionalChain([schema, 'optionalAccess', _92 => _92.properties])) return [];
3728
+ if (!_optionalChain([schema, 'optionalAccess', _96 => _96.properties])) return [];
3671
3729
  const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
3672
3730
  const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
3673
3731
  const kind = kindOf(name, s);
@@ -3724,7 +3782,7 @@ function defaultMotionCommand(type, targets, scene) {
3724
3782
  if (type === "wait") return { type: "wait", duration: 500 };
3725
3783
  if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
3726
3784
  const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
3727
- const other = (pred) => _optionalChain([nodes, 'access', _93 => _93.find, 'call', _94 => _94((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _95 => _95.node, 'access', _96 => _96.id]);
3785
+ const other = (pred) => _optionalChain([nodes, 'access', _97 => _97.find, 'call', _98 => _98((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _99 => _99.node, 'access', _100 => _100.id]);
3728
3786
  const base = { targets: [...targets] };
3729
3787
  switch (type) {
3730
3788
  case "scale":
@@ -3751,8 +3809,8 @@ function defaultMotionCommand(type, targets, scene) {
3751
3809
  }
3752
3810
  case "effect": {
3753
3811
  for (const id of targets) {
3754
- const node = _optionalChain([nodes, 'access', _97 => _97.find, 'call', _98 => _98((e) => e.node.id === id), 'optionalAccess', _99 => _99.node]);
3755
- for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _100 => _100.effects]), () => ( []))) {
3812
+ const node = _optionalChain([nodes, 'access', _101 => _101.find, 'call', _102 => _102((e) => e.node.id === id), 'optionalAccess', _103 => _103.node]);
3813
+ for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _104 => _104.effects]), () => ( []))) {
3756
3814
  const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
3757
3815
  if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
3758
3816
  }
@@ -3777,11 +3835,11 @@ function motionCommandRows(scene, shotId) {
3777
3835
  return scene.shots[index].run.map((command2, i) => {
3778
3836
  const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
3779
3837
  const primitive = motionFlairPrimitive(command2);
3780
- return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _101 => _101.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _102 => _102.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
3838
+ return { index: i, command: command2, summary: motionCommandSummary(command2), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _105 => _105.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _106 => _106.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
3781
3839
  });
3782
3840
  }
3783
3841
  function duplicateMotionCommandEdit(scene, shot, command2) {
3784
- const run = _nullishCoalesce(_optionalChain([scene, 'access', _103 => _103.shots, 'access', _104 => _104.find, 'call', _105 => _105((s) => s.id === shot), 'optionalAccess', _106 => _106.run]), () => ( []));
3842
+ const run = _nullishCoalesce(_optionalChain([scene, 'access', _107 => _107.shots, 'access', _108 => _108.find, 'call', _109 => _109((s) => s.id === shot), 'optionalAccess', _110 => _110.run]), () => ( []));
3785
3843
  return { op: "add_commands", shot, commands: run[command2] ? [structuredClone(run[command2])] : [], at: command2 + 1 };
3786
3844
  }
3787
3845
  var MOTION_EASE_CHOICES = [
@@ -3866,7 +3924,7 @@ function motionCueFromKey(key) {
3866
3924
  function motionCueChoices(scene, limit = 256) {
3867
3925
  const choices = [];
3868
3926
  const s = (ms) => `${(ms / 1e3).toFixed(2)} s`;
3869
- const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _107 => _107.narration, 'optionalAccess', _108 => _108.words, 'access', _109 => _109.map, 'call', _110 => _110((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
3927
+ const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _111 => _111.narration, 'optionalAccess', _112 => _112.words, 'access', _113 => _113.map, 'call', _114 => _114((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
3870
3928
  if (scene.beat && scene.beat.bpm > 0) {
3871
3929
  for (let beat = 0; choices.length < limit; beat++) {
3872
3930
  const time = motionBeatTime(scene.beat, beat);
@@ -3876,7 +3934,7 @@ function motionCueChoices(scene, limit = 256) {
3876
3934
  choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
3877
3935
  }
3878
3936
  }
3879
- _optionalChain([scene, 'access', _111 => _111.narration, 'optionalAccess', _112 => _112.words, 'access', _113 => _113.forEach, 'call', _114 => _114((w, i) => {
3937
+ _optionalChain([scene, 'access', _115 => _115.narration, 'optionalAccess', _116 => _116.words, 'access', _117 => _117.forEach, 'call', _118 => _118((w, i) => {
3880
3938
  if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
3881
3939
  })]);
3882
3940
  return choices;
@@ -3885,7 +3943,7 @@ function motionShotCueTime(scene, cue) {
3885
3943
  return cue ? motionCueTime(scene, cue) : void 0;
3886
3944
  }
3887
3945
  function formatMotionNarration(narration) {
3888
- return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _115 => _115.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
3946
+ return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _119 => _119.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
3889
3947
  }
3890
3948
  function parseMotionNarration(text) {
3891
3949
  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -4020,5 +4078,7 @@ function parseMotionNarration(text) {
4020
4078
 
4021
4079
 
4022
4080
 
4023
- 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_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_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.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; 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.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.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.suggestName = suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox;
4081
+
4082
+
4083
+ 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_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_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.applyMotionEdits = applyMotionEdits; exports.checkMotionScene = checkMotionScene; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.fitMotionRect = fitMotionRect; exports.fitMotionScene = fitMotionScene; exports.fitMotionSceneEdits = fitMotionSceneEdits; exports.flairAtLeast = flairAtLeast; exports.flairCurveFor = flairCurveFor; exports.flairEaseFor = flairEaseFor; exports.formatMotionNarration = formatMotionNarration; exports.freshShotId = freshShotId; exports.fromFlairSvgMotion = fromFlairSvgMotion; exports.fromFlairVectorEffect = fromFlairVectorEffect; exports.highlightMotionSvg = highlightMotionSvg; exports.indexMotionNodes = indexMotionNodes; exports.interpolateMotionValue = interpolateMotionValue; exports.isMotionCommand = isMotionCommand; exports.isMotionShot = isMotionShot; exports.matchMotionNodes = matchMotionNodes; exports.motionAddTrackKey = motionAddTrackKey; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionClipAttrs = motionClipAttrs; exports.motionCommandDuration = motionCommandDuration; exports.motionCommandFields = motionCommandFields; exports.motionCommandRepeat = motionCommandRepeat; exports.motionCommandRows = motionCommandRows; exports.motionCommandSummary = motionCommandSummary; exports.motionCueChoices = motionCueChoices; exports.motionCueFromKey = motionCueFromKey; exports.motionCueKey = motionCueKey; exports.motionCueTime = motionCueTime; exports.motionCycleDuration = motionCycleDuration; 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.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.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.resolveMotionCamera = resolveMotionCamera; 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;
4024
4084
  //# sourceMappingURL=index.cjs.map