@pixerate/editor 0.229.0 → 0.230.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/animation-editor/camera-tools.d.cts +10 -0
  2. package/dist/animation-editor/camera-tools.d.ts +10 -0
  3. package/dist/animation-editor/camera.d.cts +67 -0
  4. package/dist/animation-editor/camera.d.ts +67 -0
  5. package/dist/animation-editor/compile.d.cts +4 -0
  6. package/dist/animation-editor/compile.d.ts +4 -0
  7. package/dist/animation-editor/controller.d.cts +34 -2
  8. package/dist/animation-editor/controller.d.ts +34 -2
  9. package/dist/animation-editor/effect-tools.d.cts +2 -1
  10. package/dist/animation-editor/effect-tools.d.ts +2 -1
  11. package/dist/animation-editor/evaluate.d.cts +9 -0
  12. package/dist/animation-editor/evaluate.d.ts +9 -0
  13. package/dist/animation-editor/flair.d.cts +8 -0
  14. package/dist/animation-editor/flair.d.ts +8 -0
  15. package/dist/animation-editor/index.cjs +603 -217
  16. package/dist/animation-editor/index.d.cts +2 -0
  17. package/dist/animation-editor/index.d.ts +2 -0
  18. package/dist/animation-editor/index.js +454 -68
  19. package/dist/animation-editor/issues.d.cts +16 -0
  20. package/dist/animation-editor/issues.d.ts +16 -0
  21. package/dist/animation-editor/tools.d.cts +1 -1
  22. package/dist/animation-editor/tools.d.ts +1 -1
  23. package/dist/animation-editor/types.d.cts +21 -3
  24. package/dist/animation-editor/types.d.ts +21 -3
  25. package/dist/canvas/index.cjs +7 -7
  26. package/dist/canvas/index.js +1 -1
  27. package/dist/{chunk-IGPEBXUD.cjs → chunk-A57ZQDNN.cjs} +7 -7
  28. package/dist/{chunk-K5GXW5TR.cjs → chunk-C73U5UI3.cjs} +14 -14
  29. package/dist/{chunk-EBDZWIOP.cjs → chunk-ERJA5CGT.cjs} +5 -1
  30. package/dist/{chunk-LPTFDCJO.js → chunk-ONNNNGNS.js} +1 -1
  31. package/dist/{chunk-5MQOBTNP.cjs → chunk-OPSK22DL.cjs} +80 -9
  32. package/dist/{chunk-PB6JV62G.js → chunk-SBPGIZQN.js} +1 -1
  33. package/dist/{chunk-UGYUGZE2.js → chunk-TCZ2J7PR.js} +71 -0
  34. package/dist/{chunk-W4KFNAWC.js → chunk-TYCJGFCF.js} +5 -1
  35. package/dist/effects/helpers.d.cts +35 -1
  36. package/dist/effects/helpers.d.ts +35 -1
  37. package/dist/effects/index.cjs +60 -44
  38. package/dist/effects/index.js +18 -2
  39. package/dist/effects/types.d.cts +15 -0
  40. package/dist/effects/types.d.ts +15 -0
  41. package/dist/image-editor/index.cjs +13 -13
  42. package/dist/image-editor/index.js +1 -1
  43. package/dist/paint-editor/index.cjs +7 -7
  44. package/dist/paint-editor/index.js +2 -2
  45. package/dist/vector/index.cjs +6 -6
  46. package/dist/vector/index.js +1 -1
  47. package/dist/video-editor/index.cjs +318 -318
  48. package/dist/video-editor/index.js +4 -4
  49. package/package.json +1 -1
  50. package/skills/pixerate-animation-editor/SKILL.md +28 -1
  51. package/skills/pixerate-animation-motion-graphics/SKILL.md +3 -0
  52. package/skills/pixerate-video-editor/SKILL.md +16 -1
  53. package/skills/pixerate-video-montage/SKILL.md +2 -1
@@ -8,7 +8,7 @@ var _chunkGXLZZVR5cjs = require('../chunk-GXLZZVR5.cjs');
8
8
 
9
9
 
10
10
 
11
- var _chunkEBDZWIOPcjs = require('../chunk-EBDZWIOP.cjs');
11
+ var _chunkERJA5CGTcjs = require('../chunk-ERJA5CGT.cjs');
12
12
 
13
13
 
14
14
 
@@ -48,7 +48,13 @@ require('../chunk-NM3G4VQT.cjs');
48
48
 
49
49
 
50
50
 
51
- var _chunk5MQOBTNPcjs = require('../chunk-5MQOBTNP.cjs');
51
+
52
+
53
+
54
+
55
+
56
+
57
+ var _chunkOPSK22DLcjs = require('../chunk-OPSK22DL.cjs');
52
58
  require('../chunk-WOFXZ3XU.cjs');
53
59
  require('../chunk-PQ3H2AAN.cjs');
54
60
  require('../chunk-YQGCPL5X.cjs');
@@ -98,6 +104,7 @@ require('../chunk-IPJ3TEYR.cjs');
98
104
 
99
105
  // src/animation-editor/types.ts
100
106
  var MOTION_TRIGGERS = ["click", "hover", "press", "scroll"];
107
+ var motionCameraFramed = (camera) => typeof camera.frame === "string" || typeof camera.x === "number";
101
108
  var MOTION_TEXT_UNITS = ["letter", "word", "line"];
102
109
  var MOTION_CASCADES = ["forward", "backward", "center", "edges", "random"];
103
110
  var MOTION_DRIVEN_PROPERTIES = ["x", "y", "rotation", "scaleX", "scaleY", "opacity"];
@@ -190,7 +197,8 @@ ${problems.map((p) => `- ${p}`).join("\n")}`);
190
197
  };
191
198
  var SCENE_KEYS = ["version", "name", "description", "artwork", "shots", "clips", "drivers", "motionBlur", "loop", "trigger", "fps", "steps", "beat", "narration", "target", "controls", "presets"];
192
199
  var SHOT_KEYS = ["id", "label", "camera", "at", "run", "hold", "speed"];
193
- var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric"];
200
+ var CAMERA_KEYS = ["x", "y", "width", "height", "frame", "padding", "ease", "ms", "geometric", "in", "during"];
201
+ var CAMERA_MOVE_KEYS = ["move", "ms", "preset", "values"];
194
202
  var BASE_KEYS = ["type", "targets", "duration", "delay", "stagger", "with", "ease", "note", "repeat", "repeatMode", "steps", "split", "cascade", "source"];
195
203
  var DRAW_ORDER_KEYS = ["order", "pace", "align", "sortBy", "origin"];
196
204
  var COMMAND_KEYS = {
@@ -220,14 +228,14 @@ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
220
228
  var isNum = (v) => typeof v === "number" && Number.isFinite(v);
221
229
  var isPoint = (v) => isObject(v) && isNum(v.x) && isNum(v.y);
222
230
  function unknownKeys(value, known, where, problems) {
223
- for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, key, known)}.`);
231
+ for (const key of Object.keys(value)) if (!known.includes(key)) problems.push(`${where}: unknown field ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, key, known)}.`);
224
232
  }
225
233
  function commandShapeProblems(command3, where) {
226
234
  const problems = [];
227
235
  if (!isObject(command3)) return [`${where} must be an object.`];
228
236
  const type = command3.type;
229
237
  if (typeof type !== "string" || !MOTION_COMMAND_TYPES.includes(type)) {
230
- return [`${where}: unknown type ${typeof type === "string" ? _chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
238
+ return [`${where}: unknown type ${typeof type === "string" ? _chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES) : String(type)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`];
231
239
  }
232
240
  unknownKeys(command3, COMMAND_KEYS[type], `${where} (${type})`, problems);
233
241
  const p = (msg) => problems.push(`${where} (${type}): ${msg}`);
@@ -279,7 +287,7 @@ function commandShapeProblems(command3, where) {
279
287
  case "exit": {
280
288
  const styles = type === "enter" ? MOTION_ENTER_STYLES : MOTION_EXIT_STYLES;
281
289
  if (command3.style !== void 0 && !(typeof command3.style === "string" && styles.includes(command3.style)))
282
- p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, command3.style, styles)})` : ""}.`);
290
+ p(`"style" must be one of ${styles.join(", ")}${typeof command3.style === "string" ? ` (got ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, command3.style, styles)})` : ""}.`);
283
291
  if (command3.direction !== void 0 && !MOTION_DIRECTIONS.includes(command3.direction)) p(`"direction" must be one of ${MOTION_DIRECTIONS.join(", ")}.`);
284
292
  optionalNumber("distance");
285
293
  if (command3.scale !== void 0 && !(isNum(command3.scale) && command3.scale >= 0)) p(`"scale" must be a number \u2265 0 (the starting scale for pop and zoom).`);
@@ -432,7 +440,25 @@ function shotShapeProblems(shot, where) {
432
440
  const isRect = ["x", "y", "width", "height"].every((k) => isNum(c[k]));
433
441
  if (typeof c.frame === "string") {
434
442
  if (c.padding !== void 0 && !isNum(c.padding)) problems.push(`${name} camera: "padding" must be a number.`);
435
- } else if (!isRect) problems.push(`${name} camera: give { x, y, width, height } or { frame: "<node id>" }.`);
443
+ } else if (!isRect && (c.in === void 0 && c.during === void 0 || ["x", "y", "width", "height", "padding"].some((k) => c[k] !== void 0)))
444
+ problems.push(`${name} camera: give { x, y, width, height } or { frame: "<node id>" }, or only a move ("in" or "during") to keep the framing.`);
445
+ for (const field of ["in", "during"]) {
446
+ const m = c[field];
447
+ if (m === void 0) continue;
448
+ if (typeof m === "string") {
449
+ if (!m) problems.push(`${name} camera: "${field}" must name a camera move.`);
450
+ continue;
451
+ }
452
+ if (!isObject(m) || typeof m.move !== "string" || !m.move) {
453
+ problems.push(`${name} camera: "${field}" is a camera move's id, or { "move": id, "ms"?, "preset"?, "values"? }.`);
454
+ continue;
455
+ }
456
+ unknownKeys(m, CAMERA_MOVE_KEYS, `${name} camera ${field}`, problems);
457
+ if (m.ms !== void 0 && (field === "during" || !(isNum(m.ms) && m.ms >= 0)))
458
+ problems.push(field === "during" ? `${name} camera: a move while the shot holds plays across the shot's "hold"; set the hold instead of "during.ms".` : `${name} camera: "in.ms" must be a number \u2265 0.`);
459
+ if (m.preset !== void 0 && typeof m.preset !== "string") problems.push(`${name} camera: "${field}.preset" is a preset's name.`);
460
+ if (m.values !== void 0 && !isObject(m.values)) problems.push(`${name} camera: "${field}.values" is an object of the move's control values.`);
461
+ }
436
462
  if (c.ease !== void 0 && !_chunkDWJJI6RTcjs.isAnimationEasing.call(void 0, c.ease)) problems.push(`${name} camera: "ease" is not an easing.`);
437
463
  if (c.ms !== void 0 && !(isNum(c.ms) && c.ms >= 0)) problems.push(`${name} camera: "ms" must be a number \u2265 0.`);
438
464
  if (c.geometric !== void 0 && typeof c.geometric !== "boolean") problems.push(`${name} camera: "geometric" must be true or false.`);
@@ -1027,12 +1053,17 @@ function compileMotionScene(scene) {
1027
1053
  const start = t;
1028
1054
  let cursor = start;
1029
1055
  const f = motionShotTimeScale(shot);
1056
+ const moveIn = shot.camera ? _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, shot.camera.in) : void 0;
1057
+ const moveDuring = shot.camera ? _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, shot.camera.during) : void 0;
1058
+ let playsIn = false;
1030
1059
  if (shot.camera) {
1031
- const rect = resolveMotionCamera(shot.camera, scene);
1032
- if (rect && rect.width > 0 && rect.height > 0) {
1033
- const ms2 = index === 0 ? 0 : (_nullishCoalesce(shot.camera.ms, () => ( MOTION_CAMERA_MS))) * f;
1060
+ const framed = motionCameraFramed(shot.camera);
1061
+ const rect = framed ? resolveMotionCamera(shot.camera, scene) : null;
1062
+ if (rect && rect.width > 0 && rect.height > 0 || !framed && moveIn) {
1063
+ const ms2 = index === 0 ? 0 : (_nullishCoalesce(_nullishCoalesce(_optionalChain([moveIn, 'optionalAccess', _37 => _37.ms]), () => ( shot.camera.ms)), () => ( MOTION_CAMERA_MS))) * f;
1034
1064
  cameraMoves.push({ shot: shot.id, start, end: start + ms2, to: rect, ease: _nullishCoalesce(shot.camera.ease, () => ( MOTION_EASE_IN_OUT)), geometric: shot.camera.geometric === true });
1035
1065
  cursor = start + ms2;
1066
+ playsIn = !!moveIn && index > 0;
1036
1067
  }
1037
1068
  }
1038
1069
  const commandsStart = cursor;
@@ -1042,16 +1073,28 @@ function compileMotionScene(scene) {
1042
1073
  const base = command3.with === "previous" && i > 0 ? prevStart : runEnd;
1043
1074
  const begin = base + (command3.type === "wait" ? 0 : (_nullishCoalesce(command3.delay, () => ( 0))) * f);
1044
1075
  const split = command3.type === "wait" ? null : motionCommandSlots(nodes, command3);
1045
- const slots = _nullishCoalesce(_optionalChain([split, 'optionalAccess', _37 => _37.slots]), () => ( []));
1076
+ const slots = _nullishCoalesce(_optionalChain([split, 'optionalAccess', _38 => _38.slots]), () => ( []));
1046
1077
  const durations = command3.type === "wait" ? [command3.duration * f] : slots.map((s) => motionCommandDuration(command3, scene, s.id) * f);
1047
- const stagger = (_nullishCoalesce(_optionalChain([split, 'optionalAccess', _38 => _38.stagger]), () => ( 0))) * f;
1048
- const end2 = durations.reduce((m, d, k) => Math.max(m, begin + (_nullishCoalesce(_optionalChain([slots, 'access', _39 => _39[k], 'optionalAccess', _40 => _40.slot]), () => ( k))) * stagger + d), begin);
1078
+ const stagger = (_nullishCoalesce(_optionalChain([split, 'optionalAccess', _39 => _39.stagger]), () => ( 0))) * f;
1079
+ const end2 = durations.reduce((m, d, k) => Math.max(m, begin + (_nullishCoalesce(_optionalChain([slots, 'access', _40 => _40[k], 'optionalAccess', _41 => _41.slot]), () => ( k))) * stagger + d), begin);
1049
1080
  commands.push({ shot: shot.id, shotIndex: index, command: i, type: command3.type, start: begin, end: end2, duration: _nullishCoalesce(durations[0], () => ( 0)) });
1050
1081
  prevStart = begin;
1051
1082
  runEnd = Math.max(runEnd, end2);
1052
1083
  });
1053
1084
  const end = runEnd + (_nullishCoalesce(shot.hold, () => ( MOTION_DEFAULT_HOLD))) * f;
1054
- shots.push({ id: shot.id, index, ...shot.label ? { label: shot.label } : {}, start, commandsStart, commandsEnd: runEnd, end, ...cue !== void 0 ? { cue } : {}, ...missedBy !== void 0 ? { missedBy } : {} });
1085
+ shots.push({
1086
+ id: shot.id,
1087
+ index,
1088
+ ...shot.label ? { label: shot.label } : {},
1089
+ start,
1090
+ commandsStart,
1091
+ commandsEnd: runEnd,
1092
+ end,
1093
+ ...cue !== void 0 ? { cue } : {},
1094
+ ...missedBy !== void 0 ? { missedBy } : {},
1095
+ ...playsIn ? { cameraIn: moveIn.move } : {},
1096
+ ...moveDuring ? { cameraDuring: moveDuring.move } : {}
1097
+ });
1055
1098
  t = end;
1056
1099
  });
1057
1100
  const tracks = /* @__PURE__ */ new Map();
@@ -1073,7 +1116,11 @@ function compileMotionScene(scene) {
1073
1116
  jobs.push({
1074
1117
  start: move.start,
1075
1118
  order: order++,
1076
- run: () => push({ node: "", property: "camera", start: move.start, end: move.end, from: valueAt("", "camera", move.start), to: [move.to.x, move.to.y, move.to.width, move.to.height], ease: move.ease, shot: move.shot, command: -1, ...move.geometric ? { geometric: true } : {} })
1119
+ run: () => {
1120
+ const from = valueAt("", "camera", move.start);
1121
+ const to = move.to ? [move.to.x, move.to.y, move.to.width, move.to.height] : from;
1122
+ push({ node: "", property: "camera", start: move.start, end: move.end, from, to, ease: move.ease, shot: move.shot, command: -1, ...move.geometric ? { geometric: true } : {} });
1123
+ }
1077
1124
  });
1078
1125
  }
1079
1126
  for (const timing of commands) {
@@ -1149,11 +1196,11 @@ function compileMotionScene(scene) {
1149
1196
  const at = nodes.get(p.id);
1150
1197
  let first = { x: 0, y: 0 };
1151
1198
  try {
1152
- const m = _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _41 => _41.parentWorld]), () => ( _chunkBQE3Y6ZOcjs.IDENTITY_MATRIX)), { effects: false })[0];
1199
+ const m = _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, p, _nullishCoalesce(_optionalChain([at, 'optionalAccess', _42 => _42.parentWorld]), () => ( _chunkBQE3Y6ZOcjs.IDENTITY_MATRIX)), { effects: false })[0];
1153
1200
  if (m && m.type === "M") first = { x: m.x, y: m.y };
1154
1201
  } catch (e3) {
1155
1202
  }
1156
- return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _42 => _42.parentWorld]))), first };
1203
+ return { id: p.id, len: Math.max(1e-6, motionPathLength(p, _optionalChain([at, 'optionalAccess', _43 => _43.parentWorld]))), first };
1157
1204
  });
1158
1205
  if (!list.length) return null;
1159
1206
  const span = Math.max(0, e - s);
@@ -1182,7 +1229,7 @@ function compileMotionScene(scene) {
1182
1229
  const style = _nullishCoalesce(command3.style, () => ( "fade"));
1183
1230
  const opacity = rest("opacity");
1184
1231
  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;
1185
- for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _43 => _43.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
1232
+ for (const p of ["clipRect", "clipCircle"]) if (p !== _optionalChain([reveal, 'optionalAccess', _44 => _44.property]) && tracks.has(motionTrackKey(node, p))) seg(p, rest(p), "linear", start, start);
1186
1233
  if (reveal) {
1187
1234
  seg("opacity", opacity, "linear", start, start);
1188
1235
  seg(reveal.property, reveal.to, _nullishCoalesce(ease, () => ( MOTION_EASE_OUT)), start, end, { from: reveal.from });
@@ -1258,21 +1305,21 @@ function compileMotionScene(scene) {
1258
1305
  }
1259
1306
  case "move": {
1260
1307
  const e = _nullishCoalesce(ease, () => ( MOTION_EASE_IN_OUT));
1261
- let dx = _nullishCoalesce(_optionalChain([command3, 'access', _44 => _44.by, 'optionalAccess', _45 => _45.x]), () => ( 0));
1262
- let dy = _nullishCoalesce(_optionalChain([command3, 'access', _46 => _46.by, 'optionalAccess', _47 => _47.y]), () => ( 0));
1308
+ let dx = _nullishCoalesce(_optionalChain([command3, 'access', _45 => _45.by, 'optionalAccess', _46 => _46.x]), () => ( 0));
1309
+ let dy = _nullishCoalesce(_optionalChain([command3, 'access', _47 => _47.by, 'optionalAccess', _48 => _48.y]), () => ( 0));
1263
1310
  if (command3.to) {
1264
1311
  const inv = _chunkBQE3Y6ZOcjs.invertMatrix.call(void 0, entry.parentWorld);
1265
1312
  const target = _chunkBQE3Y6ZOcjs.applyMatrix.call(void 0, inv, command3.to);
1266
1313
  dx = target.x - (entry.center.x + num2("x"));
1267
1314
  dy = target.y - (entry.center.y + num2("y"));
1268
1315
  }
1269
- if (_optionalChain([command3, 'access', _48 => _48.via, 'optionalAccess', _49 => _49.length])) {
1316
+ if (_optionalChain([command3, 'access', _49 => _49.via, 'optionalAccess', _50 => _50.length])) {
1270
1317
  const inv = _chunkBQE3Y6ZOcjs.invertMatrix.call(void 0, entry.parentWorld);
1271
1318
  const x0 = num2("x");
1272
1319
  const y0 = num2("y");
1273
1320
  const add = command3.blend === "add";
1274
1321
  const offsets = [{ x: 0, y: 0 }, ...command3.via.map((p) => _chunkBQE3Y6ZOcjs.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 }];
1275
- const times = _optionalChain([command3, 'access', _50 => _50.times, 'optionalAccess', _51 => _51.length]) === command3.via.length ? [start, ...command3.times.map((f) => start + f * (end - start)), end] : smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
1322
+ const times = _optionalChain([command3, 'access', _51 => _51.times, 'optionalAccess', _52 => _52.length]) === command3.via.length ? [start, ...command3.times.map((f) => start + f * (end - start)), end] : smoothMotionTimes(offsets, start, end - start, _nullishCoalesce(command3.pacing, () => ( "even")));
1276
1323
  for (const axis of ["x", "y"]) {
1277
1324
  const base = add ? 0 : axis === "x" ? x0 : y0;
1278
1325
  for (const leg of smoothMotionLegs(times, offsets.map((o) => o[axis])))
@@ -1364,7 +1411,7 @@ function compileMotionScene(scene) {
1364
1411
  for (const track of tracks.values()) track.sort((a, b) => a.start - b.start);
1365
1412
  segments.sort((a, b) => a.start - b.start);
1366
1413
  const duration = shots.length ? shots[shots.length - 1].end : 0;
1367
- 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))])) } : {} };
1414
+ const timeline = { duration, shots, commands, segments, tracks, ..._optionalChain([scene, 'access', _53 => _53.drivers, 'optionalAccess', _54 => _54.length]) ? { drivers: scene.drivers, restOpacity: new Map([...nodes].map(([id, e]) => [id, _nullishCoalesce(e.node.opacity, () => ( 1))])) } : {} };
1368
1415
  timelineCache.set(scene, timeline);
1369
1416
  return timeline;
1370
1417
  }
@@ -1372,12 +1419,166 @@ function motionShotAt(timeline, time) {
1372
1419
  return _nullishCoalesce(timeline.shots.find((s) => time < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
1373
1420
  }
1374
1421
 
1422
+ // src/animation-editor/camera.ts
1423
+ var windowCache = /* @__PURE__ */ new WeakMap();
1424
+ function motionShotCameraMove(shot, role) {
1425
+ return _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'optionalAccess', _55 => _55.camera, 'optionalAccess', _56 => _56[role === "transition" ? "in" : "during"]]));
1426
+ }
1427
+ var motionCameraStage = (scene) => ({ width: scene.artwork.width, height: scene.artwork.height });
1428
+ var effectsPlayCamera = (provider) => !!provider && provider.capabilities.supportsCamera === true && typeof provider.cameraView === "function";
1429
+ async function motionCameraMoves(provider, role) {
1430
+ if (!effectsPlayCamera(provider)) return [];
1431
+ const all = await provider.list({ kind: "camera" });
1432
+ return all.filter((e) => e.kind === "camera" && e.camera && (!role || e.camera.role === role));
1433
+ }
1434
+ function motionCameraWindows(scene, provider) {
1435
+ if (!effectsPlayCamera(provider)) return [];
1436
+ if (!scene.shots.some((s) => s.camera && (s.camera.in !== void 0 || s.camera.during !== void 0))) return [];
1437
+ const timeline = compileMotionScene(scene);
1438
+ let byProvider = windowCache.get(timeline);
1439
+ if (!byProvider) windowCache.set(timeline, byProvider = /* @__PURE__ */ new WeakMap());
1440
+ const cached = byProvider.get(provider);
1441
+ if (cached) return cached;
1442
+ const stage = motionCameraStage(scene);
1443
+ const full = { x: 0, y: 0, width: stage.width, height: stage.height };
1444
+ const track = timeline.tracks.get(motionTrackKey("", "camera"));
1445
+ const boxView = (t) => {
1446
+ const b = trackValue(track, t);
1447
+ return _chunkOPSK22DLcjs.cameraViewOfBox.call(void 0, Array.isArray(b) ? { x: b[0], y: b[1], width: b[2], height: b[3] } : full, stage);
1448
+ };
1449
+ const view = (move, values, from, to, u, ms2) => {
1450
+ try {
1451
+ return provider.cameraView(move, { from, to, u, ms: ms2, stage }, values);
1452
+ } catch (e4) {
1453
+ return null;
1454
+ }
1455
+ };
1456
+ const windows = [];
1457
+ let carry = null;
1458
+ for (const timing of timeline.shots) {
1459
+ const shot = scene.shots[timing.index];
1460
+ const eases = timing.commandsStart > timing.start && !!_optionalChain([track, 'optionalAccess', _57 => _57.some, 'call', _58 => _58((seg) => seg.shot === timing.id)]);
1461
+ const framed = !!_optionalChain([track, 'optionalAccess', _59 => _59.some, 'call', _60 => _60((seg) => seg.shot === timing.id)]);
1462
+ if (timing.cameraIn && timing.commandsStart > timing.start) {
1463
+ const spec = _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'access', _61 => _61.camera, 'optionalAccess', _62 => _62.in]));
1464
+ const from = _nullishCoalesce(carry, () => ( boxView(timing.start)));
1465
+ const to = boxView(timing.commandsStart);
1466
+ if (view(spec.move, spec.values, from, to, 0, timing.commandsStart - timing.start)) {
1467
+ windows.push({ shot: timing.id, kind: "in", move: spec.move, ...spec.values ? { values: spec.values } : {}, start: timing.start, end: timing.commandsStart, from, to, after: null });
1468
+ carry = null;
1469
+ }
1470
+ } else if (carry && eases) {
1471
+ windows.push({ shot: timing.id, kind: "ease", start: timing.start, end: timing.commandsStart, from: carry, to: boxView(timing.commandsStart), after: null });
1472
+ carry = null;
1473
+ } else if (framed) carry = null;
1474
+ if (timing.cameraDuring && timing.end > timing.commandsEnd) {
1475
+ const spec = _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'access', _63 => _63.camera, 'optionalAccess', _64 => _64.during]));
1476
+ const from = _nullishCoalesce(carry, () => ( boxView(timing.commandsEnd)));
1477
+ const ms2 = timing.end - timing.commandsEnd;
1478
+ const last = view(spec.move, spec.values, from, from, 1, ms2);
1479
+ if (last) {
1480
+ windows.push({ shot: timing.id, kind: "during", move: spec.move, ...spec.values ? { values: spec.values } : {}, start: timing.commandsEnd, end: timing.end, from, to: from, after: last });
1481
+ carry = last;
1482
+ }
1483
+ }
1484
+ }
1485
+ byProvider.set(provider, windows);
1486
+ return windows;
1487
+ }
1488
+ var lerp = (a, b, t) => a + (b - a) * t;
1489
+ var smooth = (t) => t * t * (3 - 2 * t);
1490
+ function easeViews(from, to, u, stage) {
1491
+ const k = smooth(Math.min(1, Math.max(0, u)));
1492
+ const a = _chunkOPSK22DLcjs.cameraBoxOfView.call(void 0, from, stage);
1493
+ const b = _chunkOPSK22DLcjs.cameraBoxOfView.call(void 0, to, stage);
1494
+ const zoom = from.zoom * Math.pow(to.zoom / from.zoom, k);
1495
+ const cx = lerp(a.x + a.width / 2, b.x + b.width / 2, k);
1496
+ const cy = lerp(a.y + a.height / 2, b.y + b.height / 2, k);
1497
+ const view = { zoom, scrollX: stage.width / (2 * zoom) - cx, scrollY: stage.height / (2 * zoom) - cy };
1498
+ for (const key of ["tilt", "turn", "roll"]) if (from[key] || to[key]) view[key] = lerp(_nullishCoalesce(from[key], () => ( 0)), _nullishCoalesce(to[key], () => ( 0)), k);
1499
+ return view;
1500
+ }
1501
+ function motionCameraViewAt(scene, time, provider) {
1502
+ const windows = motionCameraWindows(scene, provider);
1503
+ if (!windows.length || !effectsPlayCamera(provider)) return null;
1504
+ const stage = motionCameraStage(scene);
1505
+ let before;
1506
+ for (const w of windows) {
1507
+ if (w.start > time) break;
1508
+ if (time < w.end || time === w.end && w === windows[windows.length - 1] && w.after) {
1509
+ const u = w.end > w.start ? (time - w.start) / (w.end - w.start) : 1;
1510
+ if (w.kind === "ease") return easeViews(w.from, w.to, u, stage);
1511
+ try {
1512
+ return provider.cameraView(w.move, { from: w.from, to: w.to, u: Math.min(1, Math.max(0, u)), ms: w.end - w.start, stage }, w.values);
1513
+ } catch (e5) {
1514
+ return null;
1515
+ }
1516
+ }
1517
+ before = w;
1518
+ }
1519
+ if (!_optionalChain([before, 'optionalAccess', _65 => _65.after])) return null;
1520
+ const track = compileMotionScene(scene).tracks.get(motionTrackKey("", "camera"));
1521
+ const retaken = _optionalChain([track, 'optionalAccess', _66 => _66.some, 'call', _67 => _67((seg) => seg.start >= before.end && seg.start <= time)]);
1522
+ return retaken ? null : before.after;
1523
+ }
1524
+ function motionCameraBox(view, scene) {
1525
+ return _chunkOPSK22DLcjs.cameraBoxOfView.call(void 0, view, motionCameraStage(scene));
1526
+ }
1527
+ function motionCameraTransform(view, width) {
1528
+ if (!view || !view.tilt && !view.turn) return "";
1529
+ const distance = (_nullishCoalesce(view.perspective, () => ( 2))) * width;
1530
+ return `perspective(${Math.round(distance)}px)${view.tilt ? ` rotateX(${round(view.tilt)}deg)` : ""}${view.turn ? ` rotateY(${round(-view.turn)}deg)` : ""}`;
1531
+ }
1532
+ var round = (n) => Math.round(n * 1e3) / 1e3;
1533
+ function withCameraViewEffects(svg, view, box, idPrefix = "vg-") {
1534
+ if (!view || !view.roll && !(view.blur && view.blur > 0)) return svg;
1535
+ const open = svg.match(/<svg\b[^>]*>/);
1536
+ const close = svg.lastIndexOf("</svg>");
1537
+ if (!open || close < 0) return svg;
1538
+ const startBody = open.index + open[0].length;
1539
+ const attrs = [];
1540
+ let defs = "";
1541
+ if (view.roll) attrs.push(`transform="rotate(${round(view.roll)} ${round(box.x + box.width / 2)} ${round(box.y + box.height / 2)})"`);
1542
+ if (view.blur && view.blur > 0) {
1543
+ const s = view.blur / view.zoom / 2;
1544
+ const a = (_nullishCoalesce(view.blurAngle, () => ( 0))) * Math.PI / 180;
1545
+ const [sx, sy] = view.blurAngle === void 0 ? [s, s] : [Math.abs(Math.cos(a)) * s, Math.abs(Math.sin(a)) * s];
1546
+ const id = `${idPrefix}camera-blur`;
1547
+ defs = `<defs><filter id="${id}" x="-20%" y="-20%" width="140%" height="140%"><feGaussianBlur stdDeviation="${round(sx)} ${round(sy)}"/></filter></defs>`;
1548
+ attrs.push(`filter="url(#${id})"`);
1549
+ }
1550
+ return `${svg.slice(0, startBody)}${defs}<g ${attrs.join(" ")}>${svg.slice(startBody, close)}</g>${svg.slice(close)}`;
1551
+ }
1552
+ async function checkMotionCameraMoves(scene, provider) {
1553
+ const issues = [];
1554
+ const named = scene.shots.filter((s) => s.camera && (s.camera.in !== void 0 || s.camera.during !== void 0));
1555
+ if (!named.length) return issues;
1556
+ if (!effectsPlayCamera(provider)) {
1557
+ const ids = named.map((s) => `"${s.id}"`).join(", ");
1558
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "camera-move-not-played", `Shots ${ids} name camera moves, but ${provider ? `${provider.name} has no camera moves` : "no effects provider is set"}, so the camera eases between framings instead; set a provider with camera moves to play them.`));
1559
+ return issues;
1560
+ }
1561
+ for (const shot of named) {
1562
+ for (const [field, role] of [["in", "transition"], ["during", "hold"]]) {
1563
+ const spec = shot.camera[field];
1564
+ if (spec === void 0) continue;
1565
+ try {
1566
+ await _chunkOPSK22DLcjs.resolveCameraMoveSpec.call(void 0, provider, spec, role);
1567
+ } catch (error) {
1568
+ const code = error.code === "invalid_values" || /preset/.test(error.message) ? "camera-move-values" : "camera-move-unknown";
1569
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, code, error.message, { shot: shot.id }));
1570
+ }
1571
+ }
1572
+ }
1573
+ return issues;
1574
+ }
1575
+
1375
1576
  // src/animation-editor/evaluate.ts
1376
1577
  var MOTION_DRAW_EFFECT_ID = "~draw";
1377
1578
  var TRANSFORM_PROPS = ["x", "y", "rotation", "scaleX", "scaleY", "follow"];
1378
1579
  var tidy = (v) => Math.round(v * 1e6) / 1e6 || 0;
1379
1580
  function applyMotionControlValues(scene, values) {
1380
- if (!values || !_optionalChain([scene, 'access', _54 => _54.controls, 'optionalAccess', _55 => _55.length])) return scene;
1581
+ if (!values || !_optionalChain([scene, 'access', _68 => _68.controls, 'optionalAccess', _69 => _69.length])) return scene;
1381
1582
  const map = /* @__PURE__ */ new Map();
1382
1583
  for (const control of scene.controls) {
1383
1584
  const value = values[control.name];
@@ -1424,7 +1625,7 @@ function shapeIn(entry, shape) {
1424
1625
  }
1425
1626
  function shapeAt(entry, timeline, nodes, time) {
1426
1627
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "shape"));
1427
- if (!_optionalChain([track, 'optionalAccess', _56 => _56.length])) return null;
1628
+ if (!_optionalChain([track, 'optionalAccess', _70 => _70.length])) return null;
1428
1629
  const s = activeSegment(track, time);
1429
1630
  const fromId = String(s ? s.from : track[0].from);
1430
1631
  if (!s) return fromId === entry.node.id ? null : nodes.get(fromId) ? shapeIn(entry, nodes.get(fromId)) : null;
@@ -1441,14 +1642,14 @@ function motionFollowRoute(entry, path) {
1441
1642
  if (!path || path.node.type !== "path") return null;
1442
1643
  try {
1443
1644
  return _chunkGF2RBSDMcjs.transformBezierPath.call(void 0, _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, path.node, path.parentWorld, { effects: false }), _chunkBQE3Y6ZOcjs.invertMatrix.call(void 0, entry.parentWorld));
1444
- } catch (e4) {
1645
+ } catch (e6) {
1445
1646
  return null;
1446
1647
  }
1447
1648
  }
1448
1649
  function followAt(entry, timeline, nodes, time) {
1449
1650
  const track = timeline.tracks.get(motionTrackKey(entry.node.id, "follow"));
1450
- const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _57 => _57[0]])));
1451
- if (!_optionalChain([s, 'optionalAccess', _58 => _58.path])) return null;
1651
+ const s = _nullishCoalesce(activeSegment(track, time), () => ( _optionalChain([track, 'optionalAccess', _71 => _71[0]])));
1652
+ if (!_optionalChain([s, 'optionalAccess', _72 => _72.path])) return null;
1452
1653
  const route = motionFollowRoute(entry, nodes.get(s.path));
1453
1654
  const progress = Number(trackValue(track, time));
1454
1655
  if (!route || !(progress >= 0)) return null;
@@ -1456,7 +1657,7 @@ function followAt(entry, timeline, nodes, time) {
1456
1657
  const at = _chunkGF2RBSDMcjs.bezierPathPointAtLength.call(void 0, route, Math.min(1, Math.max(0, progress)) * _chunkGF2RBSDMcjs.bezierPathLength.call(void 0, route));
1457
1658
  if (!at) return null;
1458
1659
  return { x: at.point[0], y: at.point[1], angle: s.rotate ? at.angle * 180 / Math.PI : 0 };
1459
- } catch (e5) {
1660
+ } catch (e7) {
1460
1661
  return null;
1461
1662
  }
1462
1663
  }
@@ -1466,7 +1667,7 @@ function motionNodeOffset(entry, timeline, time, nodes = indexMotionNodes([entry
1466
1667
  const layered = withMotionLayers(timeline, entry.node.id, p, typeof v === "number" ? v : rest, time, raw);
1467
1668
  return p === "follow" ? layered : applyMotionDrivers(timeline, entry.node.id, p, layered, time, raw);
1468
1669
  };
1469
- const driven = _optionalChain([timeline, 'access', _59 => _59.drivers, 'optionalAccess', _60 => _60.some, 'call', _61 => _61((d) => d.target === entry.node.id && d.property !== "opacity")]);
1670
+ const driven = _optionalChain([timeline, 'access', _73 => _73.drivers, 'optionalAccess', _74 => _74.some, 'call', _75 => _75((d) => d.target === entry.node.id && d.property !== "opacity")]);
1470
1671
  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;
1471
1672
  const dx = read("x", 0);
1472
1673
  const dy = read("y", 0);
@@ -1510,7 +1711,7 @@ function motionFrameAt(scene, time, options = {}) {
1510
1711
  if (out.visible === void 0) delete out.visible;
1511
1712
  }
1512
1713
  const effectTracks = [...timeline.tracks.keys()].filter((k) => k.startsWith(`${id}\0effect:`));
1513
- if (effectTracks.length && _optionalChain([out, 'access', _62 => _62.effects, 'optionalAccess', _63 => _63.length])) {
1714
+ if (effectTracks.length && _optionalChain([out, 'access', _76 => _76.effects, 'optionalAccess', _77 => _77.length])) {
1514
1715
  out = {
1515
1716
  ...out,
1516
1717
  effects: out.effects.map((effect) => {
@@ -1550,7 +1751,7 @@ function motionFrameAt(scene, time, options = {}) {
1550
1751
  return p;
1551
1752
  });
1552
1753
  }
1553
- 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");
1754
+ const opacity = _optionalChain([timeline, 'access', _78 => _78.drivers, 'optionalAccess', _79 => _79.some, 'call', _80 => _80((d) => d.target === id && d.property === "opacity")]) ? motionPropertyValue(timeline, id, "opacity", time) : value(id, "opacity");
1554
1755
  if (typeof opacity === "number") {
1555
1756
  const o = Math.min(1, Math.max(0, tidy(opacity)));
1556
1757
  out = { ...out, opacity: o };
@@ -1565,8 +1766,9 @@ function motionFrameAt(scene, time, options = {}) {
1565
1766
  };
1566
1767
  const document = { ...s.artwork, nodes: s.artwork.nodes.map(visit) };
1567
1768
  const cam = trackValue(timeline.tracks.get(motionTrackKey("", "camera")), time);
1568
- const box = Array.isArray(cam) ? cam : [0, 0, s.artwork.width, s.artwork.height];
1569
- return { time, document, camera: { x: tidy(box[0]), y: tidy(box[1]), width: tidy(box[2]), height: tidy(box[3]) }, clips };
1769
+ const view = motionCameraViewAt(s, time, options.effects);
1770
+ const box = view ? (({ x, y, width, height }) => [x, y, width, height])(motionCameraBox(view, s)) : Array.isArray(cam) ? cam : [0, 0, s.artwork.width, s.artwork.height];
1771
+ return { time, document, camera: { x: tidy(box[0]), y: tidy(box[1]), width: tidy(box[2]), height: tidy(box[3]) }, ...view ? { view } : {}, clips };
1570
1772
  }
1571
1773
  function motionClipAttrs(clip) {
1572
1774
  const { shape: _shape, ...attrs } = clip;
@@ -1578,7 +1780,7 @@ function motionFrameToSvg(scene, time, options = {}) {
1578
1780
  const wrap = { ...options.wrap };
1579
1781
  for (const [id, clips] of Object.entries(frame.clips))
1580
1782
  wrap[id] = [..._nullishCoalesce(wrap[id], () => ( [])), ...clips.map((clip, i) => ({ clip: { id: `${prefix}reveal-${id}-${i}`, shape: clip.shape, attrs: motionClipAttrs(clip) } }))];
1581
- return withViewBox(_chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera);
1783
+ return withCameraViewEffects(withViewBox(_chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, frame.document, { ...options, wrap }), frame.camera), frame.view, frame.camera, prefix);
1582
1784
  }
1583
1785
  function withViewBox(svg, box) {
1584
1786
  const f = (n) => String(Math.round(n * 1e3) / 1e3);
@@ -1623,7 +1825,7 @@ function motionPath(scene, id, options = {}) {
1623
1825
  const r = (n) => Math.round(n * 100) / 100;
1624
1826
  const centreAt = (t) => {
1625
1827
  const node = indexMotionNodes(motionFrameAtCache(scene, t)).get(id);
1626
- const b = _optionalChain([node, 'optionalAccess', _67 => _67.bounds]);
1828
+ const b = _optionalChain([node, 'optionalAccess', _81 => _81.bounds]);
1627
1829
  return b ? { t: r(t), x: r(b.x + b.width / 2), y: r(b.y + b.height / 2) } : null;
1628
1830
  };
1629
1831
  const points = [];
@@ -1657,8 +1859,8 @@ function motionBlurTimes(scene, time, blur = {}) {
1657
1859
  const b = indexMotionNodes(motionFrameAt(scene, time + span / 2).document.nodes);
1658
1860
  let travel = 0;
1659
1861
  for (const id of ids) {
1660
- const p = _optionalChain([a, 'access', _68 => _68.get, 'call', _69 => _69(id), 'optionalAccess', _70 => _70.bounds]);
1661
- const q = _optionalChain([b, 'access', _71 => _71.get, 'call', _72 => _72(id), 'optionalAccess', _73 => _73.bounds]);
1862
+ const p = _optionalChain([a, 'access', _82 => _82.get, 'call', _83 => _83(id), 'optionalAccess', _84 => _84.bounds]);
1863
+ const q = _optionalChain([b, 'access', _85 => _85.get, 'call', _86 => _86(id), 'optionalAccess', _87 => _87.bounds]);
1662
1864
  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));
1663
1865
  }
1664
1866
  const n = Math.min(most, Math.ceil(travel / 1.5));
@@ -1670,7 +1872,7 @@ function averagedFrames(scene, times, options, prefix) {
1670
1872
  return `<g data-motion-blur="${n}" style="isolation:isolate">${times.map((t, k) => {
1671
1873
  const own = `${prefix}blur${k}-`;
1672
1874
  const frame = motionFrameToSvg(scene, t, { ...options, idPrefix: own, background: false });
1673
- const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _74 => _74.exec, 'call', _75 => _75(frame), 'optionalAccess', _76 => _76[1]]), () => ( ""));
1875
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _88 => _88.exec, 'call', _89 => _89(frame), 'optionalAccess', _90 => _90[1]]), () => ( ""));
1674
1876
  const inner = k === n - 1 ? innerSvg(frame) : innerSvg(frame).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1675
1877
  return `<svg viewBox="${view}" preserveAspectRatio="none" style="mix-blend-mode:plus-lighter" opacity="${Math.round(1e4 / n) / 1e4}">${inner}</svg>`;
1676
1878
  }).join("")}</g>`;
@@ -1685,7 +1887,7 @@ function motionStageSvg(scene, time, options = {}) {
1685
1887
  if (blurTimes.length > 1) {
1686
1888
  const open2 = current.indexOf(">") + 1;
1687
1889
  const body2 = current.slice(open2, current.lastIndexOf("</svg>"));
1688
- const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _77 => _77.exec, 'call', _78 => _78(body2), 'optionalAccess', _79 => _79[0]]), () => ( "")) : "";
1890
+ const bg2 = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _91 => _91.exec, 'call', _92 => _92(body2), 'optionalAccess', _93 => _93[0]]), () => ( "")) : "";
1689
1891
  current = `${current.slice(0, open2)}${bg2}${averagedFrames(scene, blurTimes, svgOptions, prefix)}</svg>`;
1690
1892
  }
1691
1893
  if (!onionSkin && !motionPaths) return current;
@@ -1694,13 +1896,13 @@ function motionStageSvg(scene, time, options = {}) {
1694
1896
  const inner = innerSvg(motionFrameToSvg(scene, g.time, { ...svgOptions, idPrefix: own, background: false })).replace(new RegExp(` id="(?!${own.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1695
1897
  return `<g data-onion="${g.offset < 0 ? "before" : "after"}" opacity="${g.opacity}">${inner}</g>`;
1696
1898
  }) : [];
1697
- const camera = motionFrameAt(scene, time).camera;
1899
+ const camera = motionFrameAt(scene, time, { effects: svgOptions.effects }).camera;
1698
1900
  const ids = motionPaths === true ? motionMovingIds(scene) : motionPaths ? [...motionPaths] : [];
1699
1901
  const paths = ids.length ? motionPathsSvg(ids.map((id) => motionPath(scene, id)), camera, motionPathColor) : "";
1700
1902
  const open = current.indexOf(">") + 1;
1701
1903
  const close = current.lastIndexOf("</svg>");
1702
1904
  const body = current.slice(open, close);
1703
- const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _80 => _80.exec, 'call', _81 => _81(body), 'optionalAccess', _82 => _82[0]]), () => ( "")) : "";
1905
+ const bg = svgOptions.background !== false && scene.artwork.background ? _nullishCoalesce(_optionalChain([/^\s*<rect[^>]*\/>/, 'access', _94 => _94.exec, 'call', _95 => _95(body), 'optionalAccess', _96 => _96[0]]), () => ( "")) : "";
1704
1906
  return `${current.slice(0, open)}${bg}${ghosts.join("")}${body.slice(bg.length)}${paths}</svg>`;
1705
1907
  }
1706
1908
  function motionContactSheetSvg(scene, times, options = {}) {
@@ -1719,7 +1921,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1719
1921
  const x = gap + i % cols * (w + gap);
1720
1922
  const y = gap + Math.floor(i / cols) * (h + label + gap);
1721
1923
  const frame = motionStageSvg(scene, t, { ...frameOptions, idPrefix: `${prefix}f${i}-` });
1722
- const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _83 => _83.exec, 'call', _84 => _84(frame), 'optionalAccess', _85 => _85[1]]), () => ( `0 0 ${w} ${h}`));
1924
+ const view = _nullishCoalesce(_optionalChain([/viewBox="([^"]*)"/, 'access', _97 => _97.exec, 'call', _98 => _98(frame), 'optionalAccess', _99 => _99[1]]), () => ( `0 0 ${w} ${h}`));
1723
1925
  const inner = innerSvg(frame).replace(new RegExp(` id="(?!${`${prefix}f${i}-`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})[^"]*"`, "g"), "");
1724
1926
  const shot = _nullishCoalesce(timeline.shots.find((s) => t >= s.start && t < s.end), () => ( timeline.shots[timeline.shots.length - 1]));
1725
1927
  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>` : "";
@@ -1731,7 +1933,7 @@ function motionContactSheetSvg(scene, times, options = {}) {
1731
1933
  // src/animation-editor/check.ts
1732
1934
  var MOTION_MIN_CHANGE_MS = 120;
1733
1935
  var NUMERIC_PARAMS = (node, effectId) => {
1734
- const effect = _optionalChain([node, 'access', _86 => _86.effects, 'optionalAccess', _87 => _87.find, 'call', _88 => _88((e) => e.id === effectId)]);
1936
+ const effect = _optionalChain([node, 'access', _100 => _100.effects, 'optionalAccess', _101 => _101.find, 'call', _102 => _102((e) => e.id === effectId)]);
1735
1937
  if (!effect) return null;
1736
1938
  return Object.entries(effect.params).filter(([, v]) => typeof v === "number").map(([k]) => k);
1737
1939
  };
@@ -1774,96 +1976,97 @@ function checkMotionScene(scene) {
1774
1976
  const ids = [...nodes.keys()];
1775
1977
  const timeline = compileMotionScene(scene);
1776
1978
  const artAspect = scene.artwork.width / scene.artwork.height;
1777
- if (!scene.shots.length) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "no-shots", "The scene has no shots yet; add one with a list of commands."));
1979
+ if (!scene.shots.length) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "no-shots", "The scene has no shots yet; add one with a list of commands."));
1778
1980
  const seen = /* @__PURE__ */ new Set();
1779
1981
  for (const shot of scene.shots) {
1780
- if (seen.has(shot.id)) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "duplicate-shot-id", `Shot id "${shot.id}" is used twice; give each shot its own id.`, { shot: shot.id }));
1982
+ if (seen.has(shot.id)) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "duplicate-shot-id", `Shot id "${shot.id}" is used twice; give each shot its own id.`, { shot: shot.id }));
1781
1983
  seen.add(shot.id);
1782
1984
  }
1783
1985
  const known = (id, code, what, where) => {
1784
1986
  if (nodes.has(id)) return true;
1785
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, code, `There is no ${what} ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, ids)} in the artwork${ids.length ? "" : " (it has no nodes yet)"}.`, { ...where, ids: [id] }));
1987
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, code, `There is no ${what} ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, ids)} in the artwork${ids.length ? "" : " (it has no nodes yet)"}.`, { ...where, ids: [id] }));
1786
1988
  return false;
1787
1989
  };
1788
1990
  scene.shots.forEach((shot, shotIndex2) => {
1789
1991
  if (shot.camera && "frame" in shot.camera && typeof shot.camera.frame === "string") known(shot.camera.frame, "unknown-frame", "node to frame", { shot: shot.id });
1790
- else if (shot.camera) {
1992
+ else if (shot.camera && motionCameraFramed(shot.camera)) {
1791
1993
  const c = shot.camera;
1792
- if (!(c.width > 0 && c.height > 0)) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "invalid-camera", `The camera needs a positive width and height (got ${c.width} \xD7 ${c.height}).`, { shot: shot.id }));
1994
+ if (!(c.width > 0 && c.height > 0)) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "invalid-camera", `The camera needs a positive width and height (got ${c.width} \xD7 ${c.height}).`, { shot: shot.id }));
1793
1995
  else if (Math.abs(c.width / c.height / artAspect - 1) > 0.02)
1794
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "camera-aspect", `The camera is ${c.width} \xD7 ${c.height}, a different shape from the ${scene.artwork.width} \xD7 ${scene.artwork.height} artwork, so it shows bands at the sides; frame a node instead to match.`, { shot: shot.id }));
1996
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "camera-aspect", `The camera is ${c.width} \xD7 ${c.height}, a different shape from the ${scene.artwork.width} \xD7 ${scene.artwork.height} artwork, so it shows bands at the sides; frame a node instead to match.`, { shot: shot.id }));
1795
1997
  }
1796
- if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
1998
+ if (shotIndex2 === 0 && _optionalChain([shot, 'access', _103 => _103.camera, 'optionalAccess', _104 => _104.in]) !== void 0) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "camera-move-first-shot", 'The first shot cuts to its framing (there is none before it to move from), so its camera "in" does not play; put the move on the next shot, or use a "during" move here.', { shot: shot.id }));
1999
+ if (!shot.run.length && !shot.camera && shotIndex2 > 0) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "empty-shot", "This shot only holds; add commands or a camera move, or remove it.", { shot: shot.id }));
1797
2000
  shot.run.forEach((command3, i) => {
1798
2001
  const where = { shot: shot.id, command: i };
1799
2002
  if (command3.type === "wait") return;
1800
2003
  const targets = command3.targets.filter((id) => known(id, "unknown-target", "node", where));
1801
2004
  const timing = timeline.commands.find((c) => c.shot === shot.id && c.command === i);
1802
2005
  if (timing && timing.duration > 0 && timing.duration < MOTION_MIN_CHANGE_MS)
1803
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "too-fast", `This ${command3.type} lasts ${timing.duration} ms, too quick to follow; make it at least ${MOTION_MIN_CHANGE_MS} ms.`, { ...where, measured: timing.duration, needed: MOTION_MIN_CHANGE_MS, unit: "ms", ids: targets }));
2006
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "too-fast", `This ${command3.type} lasts ${timing.duration} ms, too quick to follow; make it at least ${MOTION_MIN_CHANGE_MS} ms.`, { ...where, measured: timing.duration, needed: MOTION_MIN_CHANGE_MS, unit: "ms", ids: targets }));
1804
2007
  if (command3.duration !== void 0 && command3.ease !== void 0) {
1805
2008
  const ease = _chunkDWJJI6RTcjs.resolveEasing.call(void 0, command3.ease);
1806
2009
  if (ease !== "hold" && ease.type === "spring") {
1807
2010
  const settle = _chunkDWJJI6RTcjs.springSettleMs.call(void 0, ease);
1808
2011
  if (command3.duration < settle * 0.9)
1809
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "spring-cut-short", `This ${command3.type}'s spring takes ${settle} ms to settle but lasts ${command3.duration} ms, so it jumps to its end; leave "duration" out (the spring sets it) or make it at least ${settle} ms.`, { ...where, measured: command3.duration, needed: settle, unit: "ms", ids: targets }));
2012
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "spring-cut-short", `This ${command3.type}'s spring takes ${settle} ms to settle but lasts ${command3.duration} ms, so it jumps to its end; leave "duration" out (the spring sets it) or make it at least ${settle} ms.`, { ...where, measured: command3.duration, needed: settle, unit: "ms", ids: targets }));
1810
2013
  }
1811
2014
  }
1812
2015
  if (command3.type === "follow" && known(command3.path, "unknown-path", "path", where) && nodes.get(command3.path).node.type !== "path")
1813
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
2016
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "not-a-path", `"${command3.path}" is a group; follow a single path node.`, { ...where, ids: [command3.path] }));
1814
2017
  if (command3.type === "morph") known(command3.into, "unknown-shape", "shape", where);
1815
2018
  if (command3.type !== "play" && command3.split) {
1816
2019
  for (const id of targets)
1817
2020
  if (!motionTextLayout(nodes, id))
1818
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "split-not-text", `"${id}" is not a group of letter paths, so "split": "${command3.split}" animates it as a whole; convert the text to outlines and group the letters (get_text_layout shows how they read).`, { ...where, ids: [id] }));
2021
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "split-not-text", `"${id}" is not a group of letter paths, so "split": "${command3.split}" animates it as a whole; convert the text to outlines and group the letters (get_text_layout shows how they read).`, { ...where, ids: [id] }));
1819
2022
  }
1820
- if (command3.type === "play" && !_optionalChain([scene, 'access', _89 => _89.clips, 'optionalAccess', _90 => _90[command3.clip]]))
1821
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-clip", `There is no clip ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
2023
+ if (command3.type === "play" && !_optionalChain([scene, 'access', _105 => _105.clips, 'optionalAccess', _106 => _106[command3.clip]]))
2024
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-clip", `There is no clip ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, command3.clip, Object.keys(_nullishCoalesce(scene.clips, () => ( {}))))}; define it with set_animation_clip.`, where));
1822
2025
  if (command3.type === "match" && known(command3.into, "unknown-shape", "group", where)) {
1823
2026
  const into = nodes.get(command3.into);
1824
2027
  for (const id of targets) {
1825
2028
  const entry = nodes.get(id);
1826
2029
  if (id === command3.into || into.ancestors.includes(id) || entry.ancestors.includes(command3.into)) {
1827
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "match-self", `"${id}" cannot match "${command3.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command3.into] }));
2030
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "match-self", `"${id}" cannot match "${command3.into}": one is the other or holds it. Match two separate groups (the second usually hidden).`, { ...where, ids: [id, command3.into] }));
1828
2031
  continue;
1829
2032
  }
1830
2033
  const m = matchMotionNodes(entry.node, into.node);
1831
2034
  if (m.unpairedInto.length)
1832
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command3.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
2035
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "match-unpaired", `${m.unpairedInto.map((x) => `"${x}"`).join(", ")} in "${command3.into}" ${m.unpairedInto.length > 1 ? "have" : "has"} no partner in "${id}", so ${m.unpairedInto.length > 1 ? "they do" : "it does"} not appear; add a part with the same name or id to "${id}" (it can start hidden or tiny).`, { ...where, ids: m.unpairedInto }));
1833
2036
  }
1834
2037
  }
1835
2038
  const style = command3.type === "enter" || command3.type === "exit" ? command3.style : void 0;
1836
2039
  if (style === "wipe" || style === "iris" || style === "split") {
1837
2040
  for (const id of targets)
1838
2041
  if (!motionRevealPadding(nodes.get(id)))
1839
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command3.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
2042
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "reveal-no-box", `"${id}" has no width or height (a straight line), so a ${style} cannot clip it and it fades instead; use style "${command3.type === "enter" ? "draw" : "undraw"}" for a line.`, { ...where, ids: [id] }));
1840
2043
  }
1841
2044
  if (command3.type === "style") {
1842
2045
  for (const key of ["fill", "stroke"]) {
1843
2046
  const color = command3[key];
1844
2047
  if (color === void 0) continue;
1845
2048
  if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) {
1846
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
2049
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "invalid-color", `${key} "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1847
2050
  continue;
1848
2051
  }
1849
2052
  for (const id of targets) {
1850
2053
  const node = nodes.get(id).node;
1851
2054
  const paths = node.type === "path" ? [node] : _chunkBQE3Y6ZOcjs.collectPathNodes.call(void 0, node);
1852
2055
  if (paths.some((p) => p[key] !== void 0 && p[key] !== null && typeof p[key] !== "string"))
1853
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
2056
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient ${key}; it switches to ${color} at the end instead of blending.`, { ...where, ids: [id] }));
1854
2057
  }
1855
2058
  }
1856
2059
  }
1857
2060
  if (command3.type === "color-pulse") {
1858
2061
  const key = _nullishCoalesce(command3.paint, () => ( "fill"));
1859
2062
  const color = _nullishCoalesce(command3.color, () => ( "#f59e0b"));
1860
- if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
2063
+ if (_chunkA6QWKBJPcjs.normalizeTokenColor.call(void 0, color) === null) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "invalid-color", `color "${color}" is not a colour this editor reads; use hex ("#0ea5e9"), rgb() or rgba().`, where));
1861
2064
  else
1862
2065
  for (const id of targets) {
1863
2066
  const node = nodes.get(id).node;
1864
2067
  const paths = node.type === "path" ? [node] : _chunkBQE3Y6ZOcjs.collectPathNodes.call(void 0, node);
1865
2068
  if (paths.some((p) => typeof p[key] !== "string"))
1866
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient or no ${key}, so a colour pulse cannot tint it; give it a solid ${key} or pulse the ${key === "fill" ? "stroke" : "fill"}.`, { ...where, ids: [id] }));
2069
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "paint-not-color", `"${id}" has a gradient or no ${key}, so a colour pulse cannot tint it; give it a solid ${key} or pulse the ${key === "fill" ? "stroke" : "fill"}.`, { ...where, ids: [id] }));
1867
2070
  }
1868
2071
  }
1869
2072
  if (command3.type === "effect") {
@@ -1872,9 +2075,9 @@ function checkMotionScene(scene) {
1872
2075
  const params = NUMERIC_PARAMS(node, command3.effect);
1873
2076
  const effects = (_nullishCoalesce(node.effects, () => ( []))).map((e) => e.id);
1874
2077
  if (!params)
1875
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-effect", `"${id}" has no effect ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
2078
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-effect", `"${id}" has no effect ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, command3.effect, effects)}${effects.length ? `; its effects are ${effects.map((e) => `"${e}"`).join(", ")}` : "; it has no live effects"}.`, { ...where, ids: [id] }));
1876
2079
  else if (!params.includes(command3.param))
1877
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
2080
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-effect-param", `Effect "${command3.effect}" has no numeric parameter ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, command3.param, params)}; use one of ${params.join(", ")}.`, { ...where, ids: [id] }));
1878
2081
  }
1879
2082
  }
1880
2083
  if (timing) {
@@ -1883,10 +2086,10 @@ function checkMotionScene(scene) {
1883
2086
  const before = Math.max(0, timing.start - 0.5);
1884
2087
  const visible = timing.start > 0 ? visibleAt(timeline, id, before, node) : node.visible !== false;
1885
2088
  if (command3.type === "enter" && visible && timing.start > 0)
1886
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
2089
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "enter-visible", `"${id}" is already showing when it enters, so it blinks out first; remove the enter or exit it earlier.`, { ...where, ids: [id] }));
1887
2090
  const probe = command3.type === "exit" ? timing.start + 0.5 : (timing.start + timing.end) / 2;
1888
2091
  if (command3.type !== "enter" && command3.type !== "draw" && !visibleAt(timeline, id, probe, node))
1889
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
2092
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "exit-hidden", `"${id}" is hidden when this ${command3.type} starts, so it is not seen; enter it first.`, { ...where, ids: [id] }));
1890
2093
  }
1891
2094
  }
1892
2095
  });
@@ -1894,7 +2097,7 @@ function checkMotionScene(scene) {
1894
2097
  const drivers = _nullishCoalesce(scene.drivers, () => ( []));
1895
2098
  drivers.forEach((d, i) => {
1896
2099
  for (const id of [d.target, d.source.node])
1897
- if (!nodes.has(id)) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-target", `Driver ${i + 1} names ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
2100
+ if (!nodes.has(id)) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-target", `Driver ${i + 1} names ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have.`, { ids: [id] }));
1898
2101
  });
1899
2102
  {
1900
2103
  const key = (n, p) => `${n}.${p}`;
@@ -1911,20 +2114,20 @@ function checkMotionScene(scene) {
1911
2114
  return false;
1912
2115
  };
1913
2116
  for (const k of edges.keys()) if (visit(k, [])) break;
1914
- if (loop.length) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
2117
+ if (loop.length) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "driver-cycle", `Drivers follow each other round in a loop (${loop.join(" \u2190 ")}); remove one of them.`, { ids: [...new Set(loop.map((k) => k.split(".")[0]))] }));
1915
2118
  }
1916
2119
  for (const [name, clip] of Object.entries(_nullishCoalesce(scene.clips, () => ( {}))))
1917
2120
  for (const command3 of clip.run)
1918
2121
  if (command3.type !== "wait") {
1919
2122
  for (const id of command3.targets)
1920
- if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-target", `Clip "${name}" names ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
2123
+ if (id !== MOTION_CLIP_TARGET && !nodes.has(id)) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-target", `Clip "${name}" names ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, [...nodes.keys()])}, which the artwork does not have; use "$" for the node the clip is played on.`, { ids: [id] }));
1921
2124
  }
1922
2125
  if (scene.trigger) {
1923
- if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
2126
+ if ((_nullishCoalesce(scene.loop, () => ( "none"))) !== "none") issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "trigger-loop", `The scene plays on ${scene.trigger}, so its "${scene.loop}" loop does not apply; set loop to "none" or remove the trigger.`, {}));
1924
2127
  if (scene.trigger === "click") {
1925
- if (scene.shots.length === 1) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
2128
+ if (scene.shots.length === 1) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "click-one-shot", "The scene plays on click but has one shot, so every click replays it from the start; split it into shots (each click plays the next one).", { shot: scene.shots[0].id }));
1926
2129
  scene.shots.forEach((shot, i) => {
1927
- if (i > 0 && shot.at) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
2130
+ if (i > 0 && shot.at) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "click-cue", `Shot "${shot.id}" is cued, but on click a shot starts when it is clicked to; remove its "at" or the trigger.`, { shot: shot.id }));
1928
2131
  });
1929
2132
  }
1930
2133
  }
@@ -1932,11 +2135,11 @@ function checkMotionScene(scene) {
1932
2135
  if (!shot.at) return;
1933
2136
  const timing = timeline.shots[i];
1934
2137
  if (timing.cue === void 0) {
1935
- 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)`;
1936
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
2138
+ 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', _107 => _107.narration, 'optionalAccess', _108 => _108.words, 'access', _109 => _109.length]), () => ( 0))} words (indexes from 0)`;
2139
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-cue", `Shot "${shot.id}" is cued to ${what}.`, { shot: shot.id }));
1937
2140
  } else if (timing.missedBy !== void 0) {
1938
2141
  const late = Math.round(timing.missedBy);
1939
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "cue-missed", `Shot "${shot.id}" is cued at ${Math.round(timing.cue)} ms but starts ${late} ms late, because the shot before runs until ${Math.round(timing.start)} ms; shorten that shot (its hold, durations or speed) or cue this one later.`, { shot: shot.id, measured: late, needed: 0, unit: "ms" }));
2142
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "cue-missed", `Shot "${shot.id}" is cued at ${Math.round(timing.cue)} ms but starts ${late} ms late, because the shot before runs until ${Math.round(timing.start)} ms; shorten that shot (its hold, durations or speed) or cue this one later.`, { shot: shot.id, measured: late, needed: 0, unit: "ms" }));
1940
2143
  }
1941
2144
  });
1942
2145
  for (const [key, track] of timeline.tracks) {
@@ -1948,7 +2151,7 @@ function checkMotionScene(scene) {
1948
2151
  const property = key.split("\0")[1];
1949
2152
  if (!a.node) continue;
1950
2153
  issues.push(
1951
- _chunkEBDZWIOPcjs.motionIssue.call(void 0, "overlap", `"${a.node}" ${property} is changed by two commands at once (shot "${a.shot}" command ${a.command + 1} and shot "${b.shot}" command ${b.command + 1}); the later one takes over. Start it after the first ends, or use with: "after".`, {
2154
+ _chunkERJA5CGTcjs.motionIssue.call(void 0, "overlap", `"${a.node}" ${property} is changed by two commands at once (shot "${a.shot}" command ${a.command + 1} and shot "${b.shot}" command ${b.command + 1}); the later one takes over. Start it after the first ends, or use with: "after".`, {
1952
2155
  shot: b.shot,
1953
2156
  command: b.command,
1954
2157
  ids: [a.node]
@@ -1965,26 +2168,26 @@ function checkMotionScene(scene) {
1965
2168
  const cam = frame.camera;
1966
2169
  const docIndex = indexMotionNodes(frame.document.nodes);
1967
2170
  for (const id of command3.targets) {
1968
- const b = _optionalChain([docIndex, 'access', _94 => _94.get, 'call', _95 => _95(id), 'optionalAccess', _96 => _96.bounds]);
2171
+ const b = _optionalChain([docIndex, 'access', _110 => _110.get, 'call', _111 => _111(id), 'optionalAccess', _112 => _112.bounds]);
1969
2172
  if (!b || reported.has(id) || !visibleAt(timeline, id, timing.end, nodes.get(id).node)) continue;
1970
2173
  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;
1971
2174
  if (outside) {
1972
2175
  reported.add(id);
1973
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "out-of-frame", `"${id}" is outside the camera when this ${command3.type} ends, so it is not seen; move it into frame or move the camera.`, { shot: timing.shot, command: timing.command, ids: [id] }));
2176
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "out-of-frame", `"${id}" is outside the camera when this ${command3.type} ends, so it is not seen; move it into frame or move the camera.`, { shot: timing.shot, command: timing.command, ids: [id] }));
1974
2177
  }
1975
2178
  }
1976
2179
  }
1977
2180
  if (scene.controls) {
1978
2181
  for (const control of scene.controls) {
1979
2182
  if (!usesColor(scene, control.default))
1980
- issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "unknown-control-color", `Control "${control.name}" stands for ${control.default}, which the scene never uses; set its default to a colour in the artwork.`));
2183
+ issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "unknown-control-color", `Control "${control.name}" stands for ${control.default}, which the scene never uses; set its default to a colour in the artwork.`));
1981
2184
  }
1982
2185
  }
1983
2186
  if (scene.target && scene.shots.length) {
1984
2187
  const seconds = Math.round(timeline.duration / 100) / 10;
1985
2188
  const [min, max] = scene.target;
1986
- if (seconds > max) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "scene-too-long", `The scene runs ${seconds} s, past its ${max} s target; shorten holds or durations, or fit it (fit_animation).`, { measured: seconds, needed: max, unit: "s" }));
1987
- if (seconds < min) issues.push(_chunkEBDZWIOPcjs.motionIssue.call(void 0, "scene-too-short", `The scene runs ${seconds} s, under its ${min} s target; hold longer, add shots, or fit it (fit_animation).`, { measured: seconds, needed: min, unit: "s" }));
2189
+ if (seconds > max) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "scene-too-long", `The scene runs ${seconds} s, past its ${max} s target; shorten holds or durations, or fit it (fit_animation).`, { measured: seconds, needed: max, unit: "s" }));
2190
+ if (seconds < min) issues.push(_chunkERJA5CGTcjs.motionIssue.call(void 0, "scene-too-short", `The scene runs ${seconds} s, under its ${min} s target; hold longer, add shots, or fit it (fit_animation).`, { measured: seconds, needed: min, unit: "s" }));
1988
2191
  }
1989
2192
  return issues;
1990
2193
  }
@@ -2013,7 +2216,7 @@ var fail = (message) => {
2013
2216
  };
2014
2217
  function shotIndex(scene, id) {
2015
2218
  const i = scene.shots.findIndex((s) => s.id === id);
2016
- if (i < 0) fail(`There is no shot ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, scene.shots.map((s) => s.id))}; the shots are ${scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
2219
+ if (i < 0) fail(`There is no shot ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, scene.shots.map((s) => s.id))}; the shots are ${scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
2017
2220
  return i;
2018
2221
  }
2019
2222
  function position(at, length, what) {
@@ -2071,7 +2274,7 @@ function applyOne(scene, edit) {
2071
2274
  if (typeof edit.name !== "string" || !edit.name) fail('Give the clip a "name".');
2072
2275
  const clips = { ..._nullishCoalesce(scene.clips, () => ( {})) };
2073
2276
  if (edit.clip === null) {
2074
- if (!clips[edit.name]) fail(`There is no clip ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, edit.name, Object.keys(clips))} to delete.`);
2277
+ if (!clips[edit.name]) fail(`There is no clip ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, edit.name, Object.keys(clips))} to delete.`);
2075
2278
  const playing = scene.shots.filter((s) => s.run.some((c) => c.type === "play" && c.clip === edit.name)).map((s) => `"${s.id}"`);
2076
2279
  if (playing.length) fail(`Clip "${edit.name}" is played in shot${playing.length > 1 ? "s" : ""} ${playing.join(", ")}; remove those play commands first.`);
2077
2280
  delete clips[edit.name];
@@ -2177,7 +2380,7 @@ function applyOne(scene, edit) {
2177
2380
  const names = new Set(edit.controls.map((c) => c.name));
2178
2381
  for (const preset2 of _nullishCoalesce(next.presets, () => ( [])))
2179
2382
  for (const key of Object.keys(preset2.values))
2180
- if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, key, names)}, which is not a control.`);
2383
+ if (!names.has(key)) fail(`Preset "${preset2.name}" sets ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, key, names)}, which is not a control.`);
2181
2384
  return next;
2182
2385
  }
2183
2386
  case "replace_scene":
@@ -2185,11 +2388,11 @@ function applyOne(scene, edit) {
2185
2388
  }
2186
2389
  }
2187
2390
  function errorKeys(issues) {
2188
- return new Set(issues.filter((i) => i.severity === "error").map(_chunkEBDZWIOPcjs.motionIssueKey));
2391
+ return new Set(issues.filter((i) => i.severity === "error").map(_chunkERJA5CGTcjs.motionIssueKey));
2189
2392
  }
2190
2393
  function editHints(before, after) {
2191
- const old = new Set(before.map(_chunkEBDZWIOPcjs.motionIssueKey));
2192
- return after.filter((i) => i.code === "overlap" && !old.has(_chunkEBDZWIOPcjs.motionIssueKey.call(void 0, i))).map(_chunkEBDZWIOPcjs.motionIssueLine);
2394
+ const old = new Set(before.map(_chunkERJA5CGTcjs.motionIssueKey));
2395
+ return after.filter((i) => i.code === "overlap" && !old.has(_chunkERJA5CGTcjs.motionIssueKey.call(void 0, i))).map(_chunkERJA5CGTcjs.motionIssueLine);
2193
2396
  }
2194
2397
  function applyMotionEdits(scene, edits) {
2195
2398
  const list = Array.isArray(edits) ? edits : [edits];
@@ -2197,9 +2400,9 @@ function applyMotionEdits(scene, edits) {
2197
2400
  let next = scene;
2198
2401
  for (let i = 0; i < list.length; i++) {
2199
2402
  const edit = list[i];
2200
- const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _97 => _97.op])}): ` : "";
2403
+ const prefix = list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _113 => _113.op])}): ` : "";
2201
2404
  if (!edit || !MOTION_EDIT_OPS.includes(edit.op))
2202
- return { ok: false, error: `${prefix}Unknown op ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, String(_optionalChain([edit, 'optionalAccess', _98 => _98.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
2405
+ return { ok: false, error: `${prefix}Unknown op ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, String(_optionalChain([edit, 'optionalAccess', _114 => _114.op])), MOTION_EDIT_OPS)}. Nothing was changed.` };
2203
2406
  try {
2204
2407
  next = applyOne(next, edit);
2205
2408
  } catch (error) {
@@ -2211,8 +2414,8 @@ function applyMotionEdits(scene, edits) {
2211
2414
  }
2212
2415
  const issues = checkMotionScene(next);
2213
2416
  const had = errorKeys(before);
2214
- const added = issues.filter((i) => i.severity === "error" && !had.has(_chunkEBDZWIOPcjs.motionIssueKey.call(void 0, i)));
2215
- if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(_chunkEBDZWIOPcjs.motionIssueLine).join(" ")}` };
2417
+ const added = issues.filter((i) => i.severity === "error" && !had.has(_chunkERJA5CGTcjs.motionIssueKey.call(void 0, i)));
2418
+ if (added.length) return { ok: false, error: `Nothing was changed: ${added.map(_chunkERJA5CGTcjs.motionIssueLine).join(" ")}` };
2216
2419
  return { ok: true, scene: next, issues, hints: editHints(before, issues) };
2217
2420
  }
2218
2421
  var REF = /^\$(\d+|last)((?:\.[A-Za-z_]\w*|\[\d+\])+)$/;
@@ -2221,7 +2424,7 @@ function resolveMotionEditRefs(scene, edits) {
2221
2424
  const resolved = [];
2222
2425
  let next = scene;
2223
2426
  for (let i = 0; i < edits.length; i++) {
2224
- const where = `op ${i + 1} (${_optionalChain([edits, 'access', _99 => _99[i], 'optionalAccess', _100 => _100.op])})`;
2427
+ const where = `op ${i + 1} (${_optionalChain([edits, 'access', _115 => _115[i], 'optionalAccess', _116 => _116.op])})`;
2225
2428
  let problem = null;
2226
2429
  const walk = (v) => {
2227
2430
  if (typeof v === "string") {
@@ -2254,9 +2457,9 @@ function resolveMotionEditRefs(scene, edits) {
2254
2457
  resolved.push(edit);
2255
2458
  const out = { op: edit.op };
2256
2459
  if (edit.op === "insert_shots") out.shots = edit.shots.map((s) => s.id);
2257
- 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;
2460
+ if ("shot" in edit && typeof edit.shot === "string") out.shot = edit.op === "update_shot" && _optionalChain([edit, 'access', _117 => _117.set, 'optionalAccess', _118 => _118.id]) ? edit.set.id : edit.shot;
2258
2461
  if (edit.op === "add_commands") {
2259
- 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));
2462
+ const at = _nullishCoalesce(_nullishCoalesce(edit.at, () => ( _optionalChain([before, 'access', _119 => _119.shots, 'access', _120 => _120.find, 'call', _121 => _121((s) => s.id === edit.shot), 'optionalAccess', _122 => _122.run, 'access', _123 => _123.length]))), () => ( 0));
2260
2463
  out.indexes = edit.commands.map((_, k) => at + k);
2261
2464
  }
2262
2465
  if (edit.op === "move_command") out.indexes = [edit.to];
@@ -2275,7 +2478,7 @@ function fitMotionScene(scene, ms2, options = {}) {
2275
2478
  if (!(Number.isFinite(ms2) && ms2 > 0)) throw new Error("Give the length to fit as a number of milliseconds above 0.");
2276
2479
  const ids = scene.shots.map((s) => s.id);
2277
2480
  const keep = new Set(_nullishCoalesce(options.keep, () => ( [])));
2278
- for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, ids)} to keep.`);
2481
+ for (const id of keep) if (!ids.includes(id)) throw new Error(`There is no shot ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, ids)} to keep.`);
2279
2482
  const timeline = compileMotionScene(scene);
2280
2483
  let kept = 0;
2281
2484
  let rest = 0;
@@ -2303,7 +2506,7 @@ var COLOR_GAP = 80;
2303
2506
  var MAX_VIA = 64;
2304
2507
  function motionNodePose(scene, id, time) {
2305
2508
  const entry = indexMotionNodes(scene.artwork.nodes).get(id);
2306
- if (!entry) throw new Error(`There is no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, [...indexMotionNodes(scene.artwork.nodes).keys()])} in the artwork.`);
2509
+ if (!entry) throw new Error(`There is no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, [...indexMotionNodes(scene.artwork.nodes).keys()])} in the artwork.`);
2307
2510
  const timeline = compileMotionScene(scene);
2308
2511
  const drawn = indexMotionNodes(motionFrameAt(scene, time).document.nodes).get(id);
2309
2512
  const centre = _chunkBQE3Y6ZOcjs.applyMatrix.call(void 0, entry.parentWorld, { x: entry.center.x + motionPropertyValue(timeline, id, "x", time), y: entry.center.y + motionPropertyValue(timeline, id, "y", time) });
@@ -2321,7 +2524,7 @@ function motionNodePose(scene, id, time) {
2321
2524
  ...typeof fill === "string" && fill !== "transparent" ? { fill } : {},
2322
2525
  ...typeof stroke === "string" && stroke !== "transparent" ? { stroke } : {},
2323
2526
  ...typeof width === "number" ? { strokeWidth: width } : {},
2324
- bounds: _nullishCoalesce(_optionalChain([drawn, 'optionalAccess', _108 => _108.bounds]), () => ( null))
2527
+ bounds: _nullishCoalesce(_optionalChain([drawn, 'optionalAccess', _124 => _124.bounds]), () => ( null))
2325
2528
  };
2326
2529
  }
2327
2530
  function simplifyTimedSamples(times, values, tol) {
@@ -2356,7 +2559,7 @@ function simplifyTimedSamples(times, values, tol) {
2356
2559
  keep.forEach((k, i) => k && out.push(i));
2357
2560
  return out;
2358
2561
  }
2359
- var round = (n, places = 2) => Math.round(n * 10 ** places) / 10 ** places || 0;
2562
+ var round2 = (n, places = 2) => Math.round(n * 10 ** places) / 10 ** places || 0;
2360
2563
  var ms = (n) => Math.max(0, Math.round(n));
2361
2564
  function motionTakeProblems(scene, take) {
2362
2565
  const problems = [];
@@ -2366,7 +2569,7 @@ function motionTakeProblems(scene, take) {
2366
2569
  take.samples.forEach((s, i) => {
2367
2570
  const where = `Sample ${i + 1}`;
2368
2571
  if (!s || typeof s !== "object") return problems.push(`${where} must be an object.`);
2369
- if (typeof s.node !== "string" || !nodes.has(s.node)) problems.push(`${where}: the artwork has no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, String(s.node), [...nodes.keys()])}; get_animation lists the element ids.`);
2572
+ if (typeof s.node !== "string" || !nodes.has(s.node)) problems.push(`${where}: the artwork has no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, String(s.node), [...nodes.keys()])}; get_animation lists the element ids.`);
2370
2573
  if (!num2(s.t) || s.t < 0) problems.push(`${where}: "t" must be ms from the start of the take, \u2265 0.`);
2371
2574
  if (s.x === void 0 !== (s.y === void 0)) problems.push(`${where}: give "x" and "y" together (the centre, document units).`);
2372
2575
  for (const k of ["x", "y", "scaleX", "scaleY", "rotation", "opacity", "strokeWidth"]) if (s[k] !== void 0 && !num2(s[k])) problems.push(`${where}: "${k}" must be a number.`);
@@ -2416,15 +2619,15 @@ function channelCommands(node, channel, pose, samples, tol, kept) {
2416
2619
  const base = { targets, duration: ms(duration), ease, ...extra };
2417
2620
  switch (channel) {
2418
2621
  case "move":
2419
- return { type: "move", ...base, to: { x: round(to[0]), y: round(to[1]) } };
2622
+ return { type: "move", ...base, to: { x: round2(to[0]), y: round2(to[1]) } };
2420
2623
  case "scale":
2421
- return { type: "scale", ...base, to: Math.abs(to[0] - to[1]) < 1e-4 ? round(to[0], 4) : { x: round(to[0], 4), y: round(to[1], 4) } };
2624
+ return { type: "scale", ...base, to: Math.abs(to[0] - to[1]) < 1e-4 ? round2(to[0], 4) : { x: round2(to[0], 4), y: round2(to[1], 4) } };
2422
2625
  case "rotation":
2423
- return { type: "rotate", ...base, to: round(to[0]) };
2626
+ return { type: "rotate", ...base, to: round2(to[0]) };
2424
2627
  case "opacity":
2425
- return { type: "fade", ...base, to: round(to[0], 4) };
2628
+ return { type: "fade", ...base, to: round2(to[0], 4) };
2426
2629
  default:
2427
- return { type: "style", ...base, strokeWidth: round(to[0]) };
2630
+ return { type: "style", ...base, strokeWidth: round2(to[0]) };
2428
2631
  }
2429
2632
  };
2430
2633
  if (differs(list[0].v, rest)) {
@@ -2444,10 +2647,10 @@ function channelCommands(node, channel, pose, samples, tol, kept) {
2444
2647
  const span = end.t - first.t;
2445
2648
  const via = [];
2446
2649
  for (const k of keep.slice(1, -1)) {
2447
- const f = round((list[k].t - first.t) / span, 6);
2448
- if (f > (_nullishCoalesce(_optionalChain([via, 'access', _109 => _109.at, 'call', _110 => _110(-1), 'optionalAccess', _111 => _111.f]), () => ( 0))) && f < 1) via.push({ s: list[k], f });
2650
+ const f = round2((list[k].t - first.t) / span, 6);
2651
+ if (f > (_nullishCoalesce(_optionalChain([via, 'access', _125 => _125.at, 'call', _126 => _126(-1), 'optionalAccess', _127 => _127.f]), () => ( 0))) && f < 1) via.push({ s: list[k], f });
2449
2652
  }
2450
- const extra = via.length ? { via: via.map(({ s }) => ({ x: round(s.v[0]), y: round(s.v[1]) })), times: via.map(({ f }) => f) } : {};
2653
+ const extra = via.length ? { via: via.map(({ s }) => ({ x: round2(s.v[0]), y: round2(s.v[1]) })), times: via.map(({ f }) => f) } : {};
2451
2654
  out.push({ start: first.t, command: make(end.v, span, "linear", extra) });
2452
2655
  kept.n += via.length + 2;
2453
2656
  return out;
@@ -2551,7 +2754,7 @@ function toFlairSvgMotion(scene, options = {}) {
2551
2754
  const behaviors = _nullishCoalesce(options.behaviors, () => ( flairAtLeast(flair, "0.38")));
2552
2755
  const springs = flairAtLeast(flair, "0.39");
2553
2756
  const strobes = flairAtLeast(flair, "0.39");
2554
- const writeEase = (ease) => typeof ease === "string" || "spring" in ease ? ease : ease.map(round3);
2757
+ const writeEase = (ease) => typeof ease === "string" || "spring" in ease ? ease : ease.map(round4);
2555
2758
  const easeOf2 = (segment) => {
2556
2759
  const resolved = _chunkDWJJI6RTcjs.resolveEasing.call(void 0, segment.ease);
2557
2760
  if (resolved !== "hold" && resolved.type === "spring") {
@@ -2564,8 +2767,8 @@ function toFlairSvgMotion(scene, options = {}) {
2564
2767
  return back && curves ? flairCurveFor(back, curves) : void 0;
2565
2768
  };
2566
2769
  const plays = (s) => (!s.behavior || behaviors) && (!s.steps || strobes) && !s.geometric;
2567
- const round3 = (n) => Math.round(n * 10 ** precision) / 10 ** precision;
2568
- const f = (n) => String(round3(n));
2770
+ const round4 = (n) => Math.round(n * 10 ** precision) / 10 ** precision;
2771
+ const f = (n) => String(round4(n));
2569
2772
  const timeline = compileMotionScene(scene);
2570
2773
  const nodes = indexMotionNodes(scene.artwork.nodes);
2571
2774
  const notes = [];
@@ -2623,7 +2826,7 @@ function toFlairSvgMotion(scene, options = {}) {
2623
2826
  const wrapper = freshId(`${id}--follow`);
2624
2827
  const centre = freshId(`${id}--follow-centre`);
2625
2828
  const c = entry.center;
2626
- const at = _optionalChain([motionNodeOffset, 'call', _112 => _112(entry, timeline, 0, nodes), 'optionalAccess', _113 => _113.follow]);
2829
+ const at = _optionalChain([motionNodeOffset, 'call', _128 => _128(entry, timeline, 0, nodes), 'optionalAccess', _129 => _129.follow]);
2627
2830
  const placed = at ? `translate(${f(at.x)} ${f(at.y)})${at.angle ? ` rotate(${f(at.angle)})` : ""}` : void 0;
2628
2831
  (wrap[id] ??= []).push({ id: wrapper, ...placed ? { transform: placed } : {} }, { id: centre, transform: `translate(${f(-c.x)} ${f(-c.y)})` });
2629
2832
  follows.push({ id, wrapper, routes: ids, segments: followSegments.filter((seg) => seg.path && ids.has(seg.path)) });
@@ -2631,7 +2834,7 @@ function toFlairSvgMotion(scene, options = {}) {
2631
2834
  }
2632
2835
  const opacitySources = sourcesOf(id, ["opacity"]);
2633
2836
  if (timeline.tracks.has(motionTrackKey(id, "opacity")) || opacitySources.length)
2634
- channels.push({ id, kind: "attr", attr: "opacity", segments: [...track(id, "opacity"), ...opacitySources], exact: (s) => plays(s) && !drivenBy.has(s), value: (t) => round3(motionPropertyValue(timeline, id, "opacity", t)) });
2837
+ channels.push({ id, kind: "attr", attr: "opacity", segments: [...track(id, "opacity"), ...opacitySources], exact: (s) => plays(s) && !drivenBy.has(s), value: (t) => round4(motionPropertyValue(timeline, id, "opacity", t)) });
2635
2838
  const followed = follows.some((x) => x.id === id);
2636
2839
  const transformSegments = [...TRANSFORM_PROPS2.flatMap((p) => followed && p === "follow" ? [] : [...track(id, p), ..._nullishCoalesce(timeline.tracks.get(motionAddTrackKey(id, p)), () => ( []))]), ...sourcesOf(id, ["x", "y", "rotation", "scaleX", "scaleY"])];
2637
2840
  if (transformSegments.length) {
@@ -2664,11 +2867,11 @@ function toFlairSvgMotion(scene, options = {}) {
2664
2867
  paint("fill", "fill");
2665
2868
  paint("stroke", "stroke");
2666
2869
  const width = owner(path, "strokeWidth");
2667
- if (width) channels.push({ id: path.id, kind: "attr", attr: "stroke-width", segments: [...track(width, "strokeWidth")], exact: () => true, value: (t) => round3(Number(trackValue(track(width, "strokeWidth"), t))) });
2870
+ if (width) channels.push({ id: path.id, kind: "attr", attr: "stroke-width", segments: [...track(width, "strokeWidth")], exact: () => true, value: (t) => round4(Number(trackValue(track(width, "strokeWidth"), t))) });
2668
2871
  const fade = owner(path, "fillOpacity");
2669
- if (fade) channels.push({ id: path.id, kind: "attr", attr: "fill-opacity", segments: [...track(fade, "fillOpacity")], exact: () => true, value: (t) => round3(Number(trackValue(track(fade, "fillOpacity"), t))) });
2872
+ if (fade) channels.push({ id: path.id, kind: "attr", attr: "fill-opacity", segments: [...track(fade, "fillOpacity")], exact: () => true, value: (t) => round4(Number(trackValue(track(fade, "fillOpacity"), t))) });
2670
2873
  const draw = owner(path, "drawEnd");
2671
- if (draw) channels.push({ id: path.id, kind: "draw", segments: [...track(draw, "drawEnd")], exact: () => true, value: (t) => round3(Math.min(1, Math.max(0, Number(trackValue(track(draw, "drawEnd"), t))))) });
2874
+ if (draw) channels.push({ id: path.id, kind: "draw", segments: [...track(draw, "drawEnd")], exact: () => true, value: (t) => round4(Math.min(1, Math.max(0, Number(trackValue(track(draw, "drawEnd"), t))))) });
2672
2875
  if (owner(path, "drawStart")) notes.push(`"${path.id}": drawing from a start other than 0 is not exported; Flair draws from the start of the path.`);
2673
2876
  }
2674
2877
  const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
@@ -2684,7 +2887,7 @@ function toFlairSvgMotion(scene, options = {}) {
2684
2887
  exact: () => false,
2685
2888
  value: (t) => {
2686
2889
  const frame = motionFrameAt(scene, t, { draw: false, offsets: false });
2687
- const now = _chunkBQE3Y6ZOcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _114 => _114(frame.document.nodes), 'access', _115 => _115.get, 'call', _116 => _116(id), 'optionalAccess', _117 => _117.node]));
2890
+ const now = _chunkBQE3Y6ZOcjs.expandVectorAppearance.call(void 0, _optionalChain([indexMotionNodes, 'call', _130 => _130(frame.document.nodes), 'access', _131 => _131.get, 'call', _132 => _132(id), 'optionalAccess', _133 => _133.node]));
2688
2891
  if (!now || now.type !== "path") return "";
2689
2892
  const bezier = _chunkGF2RBSDMcjs.transformBezierPath.call(void 0, _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, now, _chunkBQE3Y6ZOcjs.IDENTITY_MATRIX, { effects: false }), inverse);
2690
2893
  return _chunkGF2RBSDMcjs.bezierPathToSvg.call(void 0, bezier, { precision: Math.min(precision, 2) });
@@ -2694,7 +2897,26 @@ function toFlairSvgMotion(scene, options = {}) {
2694
2897
  }
2695
2898
  }
2696
2899
  const camera = track("", "camera");
2697
- if (camera.length) channels.push({ id: "", kind: "view", segments: [...camera], exact: () => true, overshoot: true, value: (t) => trackValue(camera, t).map(round3) });
2900
+ const windows = motionCameraWindows(scene, options.effects);
2901
+ const moveSegments = windows.map((w) => ({ node: "", property: "camera", start: w.start, end: w.end, from: [], to: [], ease: "linear", shot: w.shot, command: -1 }));
2902
+ const sampledMove = new WeakSet(moveSegments);
2903
+ const cameraValue = windows.length ? (t) => {
2904
+ const box = motionFrameAt(scene, t, { draw: false, offsets: false, effects: options.effects }).camera;
2905
+ return [box.x, box.y, box.width, box.height].map(round4);
2906
+ } : (t) => trackValue(camera, t).map(round4);
2907
+ if (camera.length || windows.length) channels.push({ id: "", kind: "view", segments: [...camera, ...moveSegments].sort((a, b) => a.start - b.start), exact: (seg) => !sampledMove.has(seg), overshoot: true, value: cameraValue });
2908
+ const cameraTag = (t) => {
2909
+ const w = windows.find((x) => t >= x.start - 1e-6 && t < x.end - 1e-6 && x.move);
2910
+ if (w) return `${w.move}@${w.shot}`;
2911
+ const seg = camera.find((x) => t >= x.start - 1e-6 && t < Math.max(x.end, x.start + 1e-3));
2912
+ const shot = seg ? scene.shots.find((x) => x.id === seg.shot) : void 0;
2913
+ const move = _optionalChain([_chunkOPSK22DLcjs.cameraMoveParts.call(void 0, _optionalChain([shot, 'optionalAccess', _134 => _134.camera, 'optionalAccess', _135 => _135.in])), 'optionalAccess', _136 => _136.move]);
2914
+ return move && shot ? `${move}@${shot.id}` : void 0;
2915
+ };
2916
+ const unplayed = scene.shots.filter((x) => x.camera && (x.camera.in !== void 0 || x.camera.during !== void 0) && !windows.some((w) => w.shot === x.id));
2917
+ if (unplayed.length)
2918
+ notes.push(`The camera moves of ${unplayed.map((x) => `"${x.id}"`).join(", ")} are written as eased framings, tagged with the move's id${options.effects ? " (the effects provider cannot play them)" : "; pass an effects provider with camera moves (options.effects) to sample them exactly"}.`);
2919
+ if (windows.length) notes.push("Camera moves are written as framings (the view box): their tilt, turn, roll and motion blur are not carried over to Flair.");
2698
2920
  const animate = [];
2699
2921
  let sampled = 0;
2700
2922
  const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
@@ -2702,12 +2924,16 @@ function toFlairSvgMotion(scene, options = {}) {
2702
2924
  const written = writeEase(ease);
2703
2925
  const base = {
2704
2926
  ...channel.id ? { id: channel.id } : {},
2705
- ...delay > 0 ? { delay: round3(delay) } : {},
2706
- ms: round3(ms2),
2927
+ ...delay > 0 ? { delay: round4(delay) } : {},
2928
+ ms: round4(ms2),
2707
2929
  ease: written,
2708
- ..._optionalChain([segment, 'optionalAccess', _118 => _118.behavior]) ? { behavior: segment.behavior } : {},
2709
- ..._optionalChain([segment, 'optionalAccess', _119 => _119.steps]) ? { strobe: segment.steps } : {}
2930
+ ..._optionalChain([segment, 'optionalAccess', _137 => _137.behavior]) ? { behavior: segment.behavior } : {},
2931
+ ..._optionalChain([segment, 'optionalAccess', _138 => _138.steps]) ? { strobe: segment.steps } : {}
2710
2932
  };
2933
+ if (channel.kind === "view") {
2934
+ const tag2 = cameraTag(delay);
2935
+ if (tag2) base.tag = tag2;
2936
+ }
2711
2937
  if (channel.kind === "view") animate.push({ ...base, view: to });
2712
2938
  else if (channel.kind === "draw") animate.push({ ...base, draw: [from, to] });
2713
2939
  else if (channel.kind === "attrs") {
@@ -2745,6 +2971,16 @@ function toFlairSvgMotion(scene, options = {}) {
2745
2971
  const t0 = a + (b - a) * (k - 1) / n;
2746
2972
  const t1 = a + (b - a) * k / n;
2747
2973
  const next = channel.value(t1);
2974
+ const jump = channel.kind === "view" && active.some((x) => sampledMove.has(x)) ? viewJump(channel.value, t0, t1) : void 0;
2975
+ if (jump) {
2976
+ const [before, after] = [channel.value(jump - 1e-3), channel.value(jump)];
2977
+ emit(channel, t0, jump - t0, prev, before, "linear");
2978
+ emit(channel, jump, 0, before, after, "linear");
2979
+ if (!same(after, next)) emit(channel, jump, t1 - jump, after, next, "linear");
2980
+ sampled += 2;
2981
+ prev = next;
2982
+ continue;
2983
+ }
2748
2984
  if (!same(prev, next)) {
2749
2985
  emit(channel, t0, t1 - t0, prev, next, "linear");
2750
2986
  sampled++;
@@ -2757,11 +2993,11 @@ function toFlairSvgMotion(scene, options = {}) {
2757
2993
  const starts = follow.segments.map((seg) => seg.start);
2758
2994
  for (const seg of follow.segments) {
2759
2995
  const along = { id: follow.wrapper, along: follow.routes.get(seg.path), ...seg.rotate ? { orient: true } : {} };
2760
- const progress = (t) => round3(Math.min(1, Math.max(0, Number(segmentValue(seg, t)))));
2996
+ const progress = (t) => round4(Math.min(1, Math.max(0, Number(segmentValue(seg, t)))));
2761
2997
  const curve = seg.end > seg.start ? plays(seg) ? easeOf2(seg) : void 0 : "linear";
2762
2998
  if (curve && !(overshoots(curve) && seg.rotate)) {
2763
2999
  const ends = seg.reverse ? [Number(seg.to), Number(seg.from)] : [Number(seg.from), Number(seg.to)];
2764
- animate.push({ ...along, ...seg.start > 0 ? { delay: round3(seg.start) } : {}, ms: round3(seg.end - seg.start), ease: writeEase(curve), ...seg.steps ? { strobe: seg.steps } : {}, at: [round3(ends[0]), round3(ends[1])] });
3000
+ animate.push({ ...along, ...seg.start > 0 ? { delay: round4(seg.start) } : {}, ms: round4(seg.end - seg.start), ease: writeEase(curve), ...seg.steps ? { strobe: seg.steps } : {}, at: [round4(ends[0]), round4(ends[1])] });
2765
3001
  continue;
2766
3002
  }
2767
3003
  const until = Math.min(seg.end, ...starts.filter((t) => t > seg.start));
@@ -2769,7 +3005,7 @@ function toFlairSvgMotion(scene, options = {}) {
2769
3005
  for (let k = 1; k <= n; k++) {
2770
3006
  const t0 = seg.start + (until - seg.start) * (k - 1) / n;
2771
3007
  const t1 = seg.start + (until - seg.start) * k / n;
2772
- animate.push({ ...along, ...t0 > 0 ? { delay: round3(t0) } : {}, ms: round3(t1 - t0), ease: "linear", at: [progress(t0), progress(t1)] });
3008
+ animate.push({ ...along, ...t0 > 0 ? { delay: round4(t0) } : {}, ms: round4(t1 - t0), ease: "linear", at: [progress(t0), progress(t1)] });
2773
3009
  sampled++;
2774
3010
  }
2775
3011
  }
@@ -2784,7 +3020,7 @@ function toFlairSvgMotion(scene, options = {}) {
2784
3020
  timeline.shots.forEach((shot, i) => {
2785
3021
  if (shot.start <= at + 1e-6) step = i;
2786
3022
  });
2787
- const delay = round3(at - timeline.shots[step].start);
3023
+ const delay = round4(at - timeline.shots[step].start);
2788
3024
  delete a.delay;
2789
3025
  if (delay > 0) a.delay = delay;
2790
3026
  a.step = step + 1;
@@ -2796,7 +3032,7 @@ function toFlairSvgMotion(scene, options = {}) {
2796
3032
  let svg = _chunkBQE3Y6ZOcjs.vectorDocumentToSvg.call(void 0, { ...scene.artwork, nodes: _chunkBQE3Y6ZOcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) }, { pretty: false, precision, wrap });
2797
3033
  if (routes.length) svg = svg.replace(/^(<svg[^>]*>)/, `$1<defs>${routes.join("")}</defs>`);
2798
3034
  let motion = { svg, animate };
2799
- if (_optionalChain([scene, 'access', _120 => _120.controls, 'optionalAccess', _121 => _121.length])) {
3035
+ if (_optionalChain([scene, 'access', _139 => _139.controls, 'optionalAccess', _140 => _140.length])) {
2800
3036
  const declarations = scene.controls.map((c) => `{{${c.name}: color default=${c.default.toUpperCase()}${c.label ? ` label='${c.label.replace(/'/g, "\u2019")}'` : ""}}}`).join(" ");
2801
3037
  const swap = (text) => scene.controls.reduce((s, c) => s.replace(new RegExp(`${c.default}(?![0-9a-fA-F])`, "gi"), `{{${c.name}}}`), text);
2802
3038
  svg = svg.replace(/^(<svg[^>]*>)/, `$1<!-- ${declarations} -->`);
@@ -2804,7 +3040,7 @@ function toFlairSvgMotion(scene, options = {}) {
2804
3040
  svg = svg.slice(0, header) + swap(svg.slice(header));
2805
3041
  motion = { svg, animate: animate.map((a) => a.attrs ? { ...a, attrs: Object.fromEntries(Object.entries(a.attrs).map(([k, [x, y]]) => [k, [typeof x === "string" ? swap(x) : x, typeof y === "string" ? swap(y) : y]])) } : a) };
2806
3042
  }
2807
- return { motion, duration: timeline.duration, hold: Math.max(0, round3(timeline.duration - lastChange)), sampled, notes: [...new Set(notes)], ...trigger ? { trigger } : {} };
3043
+ return { motion, duration: timeline.duration, hold: Math.max(0, round4(timeline.duration - lastChange)), sampled, notes: [...new Set(notes)], ...trigger ? { trigger } : {} };
2808
3044
  }
2809
3045
  var kebab = (text) => text.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "animation";
2810
3046
  function toFlairVectorEffect(scene, options = {}) {
@@ -2818,7 +3054,7 @@ function toFlairVectorEffect(scene, options = {}) {
2818
3054
  tags: _nullishCoalesce(options.tags, () => ( [])),
2819
3055
  motion: out.motion,
2820
3056
  hold: out.hold,
2821
- ..._optionalChain([scene, 'access', _122 => _122.presets, 'optionalAccess', _123 => _123.length]) ? { presets: scene.presets } : {},
3057
+ ..._optionalChain([scene, 'access', _141 => _141.presets, 'optionalAccess', _142 => _142.length]) ? { presets: scene.presets } : {},
2822
3058
  ...out.trigger ? { trigger: out.trigger } : {}
2823
3059
  };
2824
3060
  }
@@ -2836,6 +3072,20 @@ function toFlairEffectDocument(scene, options = {}) {
2836
3072
  presets: _nullishCoalesce(scene.presets, () => ( []))
2837
3073
  };
2838
3074
  }
3075
+ function viewJump(value, t0, t1) {
3076
+ const box = (t) => value(t);
3077
+ const apart = (a2, b2) => Math.hypot(a2[0] + a2[2] / 2 - b2[0] - b2[2] / 2, a2[1] + a2[3] / 2 - b2[1] - b2[3] / 2, a2[2] - b2[2]);
3078
+ let lo = t0;
3079
+ let hi = t1;
3080
+ for (let i = 0; i < 40 && hi - lo > 1e-4; i++) {
3081
+ const mid = (lo + hi) / 2;
3082
+ if (apart(box(lo), box(mid)) >= apart(box(mid), box(hi))) hi = mid;
3083
+ else lo = mid;
3084
+ }
3085
+ const a = box(lo);
3086
+ const b = box(hi);
3087
+ return apart(a, b) > Math.min(a[2], b[2]) / 20 ? hi : void 0;
3088
+ }
2839
3089
 
2840
3090
  // src/animation-editor/flair-import.ts
2841
3091
  var PLACEHOLDER = /\{\{\s*([A-Za-z_]\w*)\s*(?::\s*([A-Za-z0-9]*)([^}]*))?\}\}/g;
@@ -2862,7 +3112,7 @@ function resolvePlaceholders(motion, notes) {
2862
3112
  const filled = text.replace(PLACEHOLDER, (_, name) => {
2863
3113
  const d = declared.get(name);
2864
3114
  if (!d) unknown.add(name);
2865
- return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _124 => _124.value]), () => ( ""))).replace(/"/g, '\\"');
3115
+ return (_nullishCoalesce(_optionalChain([d, 'optionalAccess', _143 => _143.value]), () => ( ""))).replace(/"/g, '\\"');
2866
3116
  });
2867
3117
  for (const name of unknown) notes.push(`Placeholder "{{${name}}}" has no declaration, so it was left empty.`);
2868
3118
  return { motion: JSON.parse(filled), controls };
@@ -2916,7 +3166,7 @@ function commandsFor(anim, nodes, entered, notes) {
2916
3166
  if (anim.along) {
2917
3167
  const path = nodes.get(anim.along);
2918
3168
  if (!path || path.node.type !== "path") notes.push(`${where} follows "${anim.along}", which is not a path in the artwork; the follow was skipped.`);
2919
- else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _125 => _125.at, 'optionalAccess', _126 => _126[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _127 => _127.at, 'optionalAccess', _128 => _128[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
3169
+ else out.push({ type: "follow", targets, path: anim.along, from: _nullishCoalesce(_optionalChain([anim, 'access', _144 => _144.at, 'optionalAccess', _145 => _145[0]]), () => ( 0)), to: _nullishCoalesce(_optionalChain([anim, 'access', _146 => _146.at, 'optionalAccess', _147 => _147[1]]), () => ( 1)), ...anim.orient ? { rotate: true } : {}, ...timing, ...ease(MOTION_EASE_IN_OUT) });
2920
3170
  }
2921
3171
  for (const [attr, [a, b]] of Object.entries(_nullishCoalesce(anim.attrs, () => ( {})))) {
2922
3172
  if (attr === "opacity") {
@@ -2927,7 +3177,7 @@ function commandsFor(anim, nodes, entered, notes) {
2927
3177
  out.push({ type: "enter", targets, style: "fade", ...timing, ...ease(MOTION_EASE_OUT) });
2928
3178
  } else out.push({ type: "fade", targets, to: Math.min(1, Math.max(0, to)), ...timing, ...ease(MOTION_EASE_IN_OUT) });
2929
3179
  } else if (attr === "fill" || attr === "stroke") {
2930
- if (_optionalChain([behavior, 'optionalAccess', _129 => _129.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
3180
+ if (_optionalChain([behavior, 'optionalAccess', _148 => _148.type]) === "pulse") out.push({ type: "color-pulse", targets, color: String(b), paint: attr, count: _nullishCoalesce(behavior.count, () => ( 1)), ...timing, ...ease("linear") });
2931
3181
  else {
2932
3182
  if (behavior) notes.push(`${where}: a ${attr} ${behavior.type} became a plain colour change.`);
2933
3183
  out.push({ type: "style", targets, [attr]: String(b), ...timing, ...ease(MOTION_EASE_IN_OUT) });
@@ -3050,7 +3300,7 @@ function rgba(color) {
3050
3300
  const n = (i) => parseInt(hex.slice(i, i + 2), 16) / 255;
3051
3301
  return [n(1), n(3), n(5), hex.length >= 9 ? parseInt(hex.slice(7, 9), 16) / 255 : 1];
3052
3302
  }
3053
- function lottieContours(path, round3) {
3303
+ function lottieContours(path, round4) {
3054
3304
  const out = [];
3055
3305
  let cur = null;
3056
3306
  let px = 0;
@@ -3091,7 +3341,7 @@ function lottieContours(path, round3) {
3091
3341
  }
3092
3342
  }
3093
3343
  if (cur) out.push(cur);
3094
- return out.map((c) => ({ c: c.c, v: c.v.map((p) => p.map(round3)), i: c.i.map((p) => p.map(round3)), o: c.o.map((p) => p.map(round3)) }));
3344
+ return out.map((c) => ({ c: c.c, v: c.v.map((p) => p.map(round4)), i: c.i.map((p) => p.map(round4)), o: c.o.map((p) => p.map(round4)) }));
3095
3345
  }
3096
3346
  function staticParts(m) {
3097
3347
  const sx = Math.hypot(m[0], m[1]);
@@ -3103,8 +3353,8 @@ function staticParts(m) {
3103
3353
  function toLottie(scene, options = {}) {
3104
3354
  const fps = _nullishCoalesce(_nullishCoalesce(options.fps, () => ( scene.fps)), () => ( 30));
3105
3355
  const precision = _nullishCoalesce(options.precision, () => ( 3));
3106
- const round3 = (n) => Math.round(n * 10 ** precision) / 10 ** precision;
3107
- const frame = (ms2) => round3(ms2 * fps / 1e3);
3356
+ const round4 = (n) => Math.round(n * 10 ** precision) / 10 ** precision;
3357
+ const frame = (ms2) => round4(ms2 * fps / 1e3);
3108
3358
  const timeline = compileMotionScene(scene);
3109
3359
  const nodes = indexMotionNodes(scene.artwork.nodes);
3110
3360
  const notes = [];
@@ -3121,16 +3371,16 @@ function toLottie(scene, options = {}) {
3121
3371
  return [e.x1, e.y1, e.x2, e.y2];
3122
3372
  };
3123
3373
  const animate = (segments, value, exact = true) => {
3124
- const rest = value(0).map(round3);
3374
+ const rest = value(0).map(round4);
3125
3375
  if (!segments.length) return { a: 0, k: rest.length === 1 ? rest[0] : rest };
3126
3376
  const keys = [];
3127
3377
  const key = (t, v, ease) => {
3128
- const k = { t: frame(t), s: v.map(round3) };
3378
+ const k = { t: frame(t), s: v.map(round4) };
3129
3379
  if (ease === "hold") k.h = 1;
3130
3380
  else {
3131
3381
  const [x1, y1, x2, y2] = ease === "linear" || !ease ? [0, 0, 1, 1] : ease;
3132
- k.o = { x: [round3(x1)], y: [round3(y1)] };
3133
- k.i = { x: [round3(x2)], y: [round3(y2)] };
3382
+ k.o = { x: [round4(x1)], y: [round4(y1)] };
3383
+ k.i = { x: [round4(x2)], y: [round4(y2)] };
3134
3384
  }
3135
3385
  if (keys.length && keys[keys.length - 1].t === k.t) keys[keys.length - 1] = k;
3136
3386
  else keys.push(k);
@@ -3178,7 +3428,7 @@ function toLottie(scene, options = {}) {
3178
3428
  const poseTransform = (entry) => {
3179
3429
  const id = entry.node.id;
3180
3430
  const tr = STATIC_TR();
3181
- const c = [entry.center.x, entry.center.y].map(round3);
3431
+ const c = [entry.center.x, entry.center.y].map(round4);
3182
3432
  const own = (p) => track(id, p);
3183
3433
  const sources = motionDriverSources(timeline, id, ["x", "y", "rotation", "scaleX", "scaleY"]);
3184
3434
  const layered = ["x", "y", "rotation", "scaleX", "scaleY"].some((p) => layers(id, p).length) || sources.length > 0;
@@ -3189,7 +3439,7 @@ function toLottie(scene, options = {}) {
3189
3439
  tr.p = animate(mixed ? [...own("x"), ...own("y"), ...own("follow"), ...layers(id, "x"), ...layers(id, "y"), ...sources] : [...own("x"), ...own("y")], (t) => poseAt(entry, t).p, !mixed);
3190
3440
  tr.r = animate(mixed ? [...own("rotation"), ...own("follow"), ...layers(id, "rotation"), ...sources] : own("rotation"), (t) => [poseAt(entry, t).r], !mixed);
3191
3441
  tr.s = animate(mixed ? [...own("scaleX"), ...own("scaleY"), ...layers(id, "scaleX"), ...layers(id, "scaleY"), ...sources] : [...own("scaleX"), ...own("scaleY")], (t) => poseAt(entry, t).s, !mixed);
3192
- if (tr.p.a === 0) tr.p = { a: 0, k: poseAt(entry, 0).p.map(round3) };
3442
+ if (tr.p.a === 0) tr.p = { a: 0, k: poseAt(entry, 0).p.map(round4) };
3193
3443
  }
3194
3444
  const opacitySources = motionDriverSources(timeline, id, ["opacity"]);
3195
3445
  if (opacitySources.length) {
@@ -3198,7 +3448,7 @@ function toLottie(scene, options = {}) {
3198
3448
  }
3199
3449
  const opacity = own("opacity");
3200
3450
  const rest = _nullishCoalesce(entry.node.opacity, () => ( 1));
3201
- tr.o = opacity.length ? animate(opacity, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(opacity, t), () => ( rest))))) * 100]) : { a: 0, k: round3(rest * 100) };
3451
+ tr.o = opacity.length ? animate(opacity, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(opacity, t), () => ( rest))))) * 100]) : { a: 0, k: round4(rest * 100) };
3202
3452
  return tr;
3203
3453
  };
3204
3454
  const owner = (path, p) => {
@@ -3217,10 +3467,10 @@ function toLottie(scene, options = {}) {
3217
3467
  const shapeSegments = [...timeline.tracks.entries()].filter(([k]) => k.startsWith(`${path.id}\0`) && (k.endsWith("\0shape") || k.includes("\0effect:"))).flatMap(([, v]) => v);
3218
3468
  const geometryAt = (t) => {
3219
3469
  if (!shapeSegments.length) return _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, path);
3220
- const now = _optionalChain([indexMotionNodes, 'call', _130 => _130(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _131 => _131.get, 'call', _132 => _132(path.id), 'optionalAccess', _133 => _133.node]);
3470
+ const now = _optionalChain([indexMotionNodes, 'call', _149 => _149(motionFrameAt(scene, t, { draw: false, offsets: false }).document.nodes), 'access', _150 => _150.get, 'call', _151 => _151(path.id), 'optionalAccess', _152 => _152.node]);
3221
3471
  return now && now.type === "path" ? _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, _chunkBQE3Y6ZOcjs.expandVectorAppearances.call(void 0, [now])[0]) : _chunkBQE3Y6ZOcjs.vectorPathWorldBezier.call(void 0, path);
3222
3472
  };
3223
- const rest = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(0)), round3);
3473
+ const rest = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(0)), round4);
3224
3474
  rest.forEach((contour, n) => {
3225
3475
  let ks = { a: 0, k: contour };
3226
3476
  if (shapeSegments.length) {
@@ -3229,7 +3479,7 @@ function toLottie(scene, options = {}) {
3229
3479
  const count = Math.max(1, Math.ceil(end * fps / 1e3));
3230
3480
  for (let k = 0; k <= count && fits; k++) {
3231
3481
  const t = end * k / count;
3232
- const c = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(t)), round3)[n];
3482
+ const c = lottieContours(_chunkGF2RBSDMcjs.toBezierPath.call(void 0, geometryAt(t)), round4)[n];
3233
3483
  if (!c || c.v.length !== contour.v.length || c.c !== contour.c) fits = false;
3234
3484
  else keys.push({ t: frame(t), s: [c], ...k < count ? { o: { x: [0], y: [0] }, i: { x: [1], y: [1] } } : {} });
3235
3485
  }
@@ -3258,14 +3508,14 @@ function toLottie(scene, options = {}) {
3258
3508
  items.push({
3259
3509
  ty: "st",
3260
3510
  nm: "Stroke",
3261
- c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( stroke)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(stroke, () => ( [0, 0, 0, 1]))).map(round3) },
3511
+ c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( stroke)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(stroke, () => ( [0, 0, 0, 1]))).map(round4) },
3262
3512
  o: { a: 0, k: 100 },
3263
- w: widthFrom ? animate(track(widthFrom, "strokeWidth"), (t) => [Math.max(0, Number(_nullishCoalesce(_nullishCoalesce(trackValue(track(widthFrom, "strokeWidth"), t), () => ( path.strokeWidth)), () => ( 1))))]) : { a: 0, k: round3(_nullishCoalesce(path.strokeWidth, () => ( 1))) },
3513
+ w: widthFrom ? animate(track(widthFrom, "strokeWidth"), (t) => [Math.max(0, Number(_nullishCoalesce(_nullishCoalesce(trackValue(track(widthFrom, "strokeWidth"), t), () => ( path.strokeWidth)), () => ( 1))))]) : { a: 0, k: round4(_nullishCoalesce(path.strokeWidth, () => ( 1))) },
3264
3514
  lc: path.strokeLinecap === "round" ? 2 : path.strokeLinecap === "square" ? 3 : 1,
3265
3515
  lj: path.strokeLinejoin === "round" ? 2 : path.strokeLinejoin === "bevel" ? 3 : 1,
3266
3516
  ml: 4
3267
3517
  });
3268
- if (_optionalChain([path, 'access', _134 => _134.strokeDasharray, 'optionalAccess', _135 => _135.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
3518
+ if (_optionalChain([path, 'access', _153 => _153.strokeDasharray, 'optionalAccess', _154 => _154.length])) notes.push(`"${path.id}": its dashes are not exported; the stroke is solid.`);
3269
3519
  if (path.strokeAlign && path.strokeAlign !== "center") notes.push(`"${path.id}": its stroke is drawn centred (Lottie has no inside or outside strokes).`);
3270
3520
  }
3271
3521
  const fill = paintOf(path.fill, "fill", path.id);
@@ -3275,7 +3525,7 @@ function toLottie(scene, options = {}) {
3275
3525
  items.push({
3276
3526
  ty: "fl",
3277
3527
  nm: "Fill",
3278
- c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( fill)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(fill, () => ( [0, 0, 0, 1]))).map(round3) },
3528
+ c: colour2.length ? animate(colour2, (t) => _nullishCoalesce(_nullishCoalesce(rgba(trackValue(colour2, t)), () => ( fill)), () => ( [0, 0, 0, 1]))) : { a: 0, k: (_nullishCoalesce(fill, () => ( [0, 0, 0, 1]))).map(round4) },
3279
3529
  o: fade.length ? animate(fade, (t) => [Math.min(1, Math.max(0, Number(_nullishCoalesce(trackValue(fade, t), () => ( 1))))) * 100]) : { a: 0, k: 100 },
3280
3530
  r: path.fillRule === "evenodd" ? 2 : 1
3281
3531
  });
@@ -3301,9 +3551,9 @@ function toLottie(scene, options = {}) {
3301
3551
  const parts = staticParts(m);
3302
3552
  if (!parts) notes.push(`"${node.id}": its transform skews, which is not exported; it is drawn without the skew.`);
3303
3553
  else {
3304
- innerTr.p = { a: 0, k: parts.p.map(round3) };
3305
- innerTr.s = { a: 0, k: parts.s.map(round3) };
3306
- innerTr.r = { a: 0, k: round3(parts.r) };
3554
+ innerTr.p = { a: 0, k: parts.p.map(round4) };
3555
+ innerTr.s = { a: 0, k: parts.s.map(round4) };
3556
+ innerTr.r = { a: 0, k: round4(parts.r) };
3307
3557
  }
3308
3558
  }
3309
3559
  }
@@ -3313,7 +3563,7 @@ function toLottie(scene, options = {}) {
3313
3563
  const artwork = { ...scene.artwork, nodes: _chunkBQE3Y6ZOcjs.expandVectorAppearances.call(void 0, scene.artwork.nodes) };
3314
3564
  const content = shown(artwork.nodes).reverse().map(nodeGroup);
3315
3565
  if (artwork.background && rgba(artwork.background))
3316
- 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(round3) }, o: { a: 0, k: 100 }, r: 1 }, STATIC_TR()] });
3566
+ 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(round4) }, o: { a: 0, k: 100 }, r: 1 }, STATIC_TR()] });
3317
3567
  const camera = track("", "camera");
3318
3568
  const root = STATIC_TR();
3319
3569
  if (camera.length) {
@@ -3359,7 +3609,7 @@ var kids = (el, name) => el ? Array.from(el.children).filter((c) => c.localName
3359
3609
  var kid = (el, name) => _nullishCoalesce(kids(el, name)[0], () => ( null));
3360
3610
  var deep = (el, name) => el ? Array.from(el.getElementsByTagNameNS("*", name)) : [];
3361
3611
  var num = (el, attr, fallback = 0) => {
3362
- const v = _optionalChain([el, 'optionalAccess', _136 => _136.getAttribute, 'call', _137 => _137(attr)]);
3612
+ const v = _optionalChain([el, 'optionalAccess', _155 => _155.getAttribute, 'call', _156 => _156(attr)]);
3363
3613
  const n = v === null || v === void 0 ? NaN : Number(v);
3364
3614
  return Number.isFinite(n) ? n : fallback;
3365
3615
  };
@@ -3467,8 +3717,8 @@ function placement(xfrm, map) {
3467
3717
  const ext = kid(xfrm, "ext");
3468
3718
  const [x, y, w, h] = map(num(off, "x"), num(off, "y"), num(ext, "cx"), num(ext, "cy"));
3469
3719
  const rot = num(xfrm, "rot") / 6e4 * (Math.PI / 180);
3470
- const fx = _optionalChain([xfrm, 'optionalAccess', _138 => _138.getAttribute, 'call', _139 => _139("flipH")]) === "1" ? -1 : 1;
3471
- const fy = _optionalChain([xfrm, 'optionalAccess', _140 => _140.getAttribute, 'call', _141 => _141("flipV")]) === "1" ? -1 : 1;
3720
+ const fx = _optionalChain([xfrm, 'optionalAccess', _157 => _157.getAttribute, 'call', _158 => _158("flipH")]) === "1" ? -1 : 1;
3721
+ const fy = _optionalChain([xfrm, 'optionalAccess', _159 => _159.getAttribute, 'call', _160 => _160("flipV")]) === "1" ? -1 : 1;
3472
3722
  const cx = x + w / 2;
3473
3723
  const cy = y + h / 2;
3474
3724
  const cos = Math.cos(rot);
@@ -3495,7 +3745,7 @@ function shapes(ctx, tree, map) {
3495
3745
  const nv = el.firstElementChild;
3496
3746
  const cNvPr = kid(nv, "cNvPr");
3497
3747
  const spid = num(cNvPr, "id", -1);
3498
- const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _142 => _142.getAttribute, 'call', _143 => _143("name")]), () => ( ""));
3748
+ const name = _nullishCoalesce(_optionalChain([cNvPr, 'optionalAccess', _161 => _161.getAttribute, 'call', _162 => _162("name")]), () => ( ""));
3499
3749
  if (el.localName === "grpSp") {
3500
3750
  const xfrm = kid(kid(el, "grpSpPr"), "xfrm");
3501
3751
  const off = kid(xfrm, "off");
@@ -3516,7 +3766,7 @@ function shapes(ctx, tree, map) {
3516
3766
  if (el.localName !== "sp" && el.localName !== "cxnSp") continue;
3517
3767
  const spPr = kid(el, "spPr");
3518
3768
  const { w, h, transform } = placement(kid(spPr, "xfrm"), map);
3519
- const prst = _optionalChain([kid, 'call', _144 => _144(spPr, "prstGeom"), 'optionalAccess', _145 => _145.getAttribute, 'call', _146 => _146("prst")]);
3769
+ const prst = _optionalChain([kid, 'call', _163 => _163(spPr, "prstGeom"), 'optionalAccess', _164 => _164.getAttribute, 'call', _165 => _165("prst")]);
3520
3770
  const cust = kid(spPr, "custGeom");
3521
3771
  let subpaths = cust ? custom(cust, w, h) : prst ? preset(prst, w, h) : null;
3522
3772
  if (!subpaths) {
@@ -3630,13 +3880,13 @@ function command(ctx, ctn, scene, artwork, target, hidden) {
3630
3880
  }
3631
3881
  if (cls === "path") {
3632
3882
  const motion = deep(ctn, "animMotion")[0];
3633
- const d = _optionalChain([motion, 'optionalAccess', _147 => _147.getAttribute, 'call', _148 => _148("path")]);
3883
+ const d = _optionalChain([motion, 'optionalAccess', _166 => _166.getAttribute, 'call', _167 => _167("path")]);
3634
3884
  if (!d) return null;
3635
3885
  const entry = artwork.flatMap(function all(n) {
3636
3886
  return n.type === "group" ? [n, ...n.children.flatMap(all)] : [n];
3637
3887
  }).find((n) => n.id === target);
3638
- const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _149 => _149.transform]), () => ( [1, 0, 0, 1, 0, 0]));
3639
- const p = _optionalChain([entry, 'optionalAccess', _150 => _150.type]) === "path" ? _optionalChain([entry, 'access', _151 => _151.subpaths, 'access', _152 => _152[0], 'optionalAccess', _153 => _153.anchors]) : void 0;
3888
+ const t = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _168 => _168.transform]), () => ( [1, 0, 0, 1, 0, 0]));
3889
+ const p = _optionalChain([entry, 'optionalAccess', _169 => _169.type]) === "path" ? _optionalChain([entry, 'access', _170 => _170.subpaths, 'access', _171 => _171[0], 'optionalAccess', _172 => _172.anchors]) : void 0;
3640
3890
  const xs = (_nullishCoalesce(p, () => ( []))).map((a) => a.x);
3641
3891
  const ys = (_nullishCoalesce(p, () => ( []))).map((a) => a.y);
3642
3892
  const lx = xs.length ? (Math.min(...xs) + Math.max(...xs)) / 2 : 0;
@@ -3688,9 +3938,9 @@ async function fromPptxAnimation(data, options = {}) {
3688
3938
  if (!path.includes("theme/")) continue;
3689
3939
  const theme = await xml(ctx, path);
3690
3940
  const scheme = deep(theme, "clrScheme")[0];
3691
- for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _154 => _154.children]), () => ( [])))) {
3941
+ for (const c of Array.from(_nullishCoalesce(_optionalChain([scheme, 'optionalAccess', _173 => _173.children]), () => ( [])))) {
3692
3942
  const v = c.firstElementChild;
3693
- const hex = _optionalChain([v, 'optionalAccess', _155 => _155.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _156 => _156.getAttribute, 'call', _157 => _157("lastClr")]);
3943
+ const hex = _optionalChain([v, 'optionalAccess', _174 => _174.localName]) === "srgbClr" ? v.getAttribute("val") : _optionalChain([v, 'optionalAccess', _175 => _175.getAttribute, 'call', _176 => _176("lastClr")]);
3694
3944
  if (hex) ctx.theme.set(c.localName, `#${hex.toLowerCase()}`);
3695
3945
  }
3696
3946
  break;
@@ -3808,7 +4058,7 @@ function withoutMotionEffect(scene, instance) {
3808
4058
  const shots = [];
3809
4059
  for (const shot of scene.shots) {
3810
4060
  const run = shot.run.filter((c, i) => {
3811
- const mine = _optionalChain([sourceOf, 'call', _158 => _158(c), 'optionalAccess', _159 => _159.instance]) === instance;
4061
+ const mine = _optionalChain([sourceOf, 'call', _177 => _177(c), 'optionalAccess', _178 => _178.instance]) === instance;
3812
4062
  if (mine && !place) place = { shot: shot.id, index: i };
3813
4063
  return !mine;
3814
4064
  });
@@ -3828,7 +4078,7 @@ var AnimationEditorController = (_class = class {
3828
4078
 
3829
4079
 
3830
4080
  /** The effects provider slot (see `setEffectsProvider`). */
3831
- __init() {this.effects = new (0, _chunk5MQOBTNPcjs.EffectsSlot)()}
4081
+ __init() {this.effects = new (0, _chunkOPSK22DLcjs.EffectsSlot)()}
3832
4082
 
3833
4083
 
3834
4084
  __init2() {this.selection = null}
@@ -3895,7 +4145,7 @@ var AnimationEditorController = (_class = class {
3895
4145
  time: p.time,
3896
4146
  playing: p.playing,
3897
4147
  loop: p.loop,
3898
- currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _160 => _160(timeline, p.time), 'optionalAccess', _161 => _161.id]), () => ( null)),
4148
+ currentShot: _nullishCoalesce(_optionalChain([motionShotAt, 'call', _179 => _179(timeline, p.time), 'optionalAccess', _180 => _180.id]), () => ( null)),
3899
4149
  selection: this.selection,
3900
4150
  readOnly: this.readOnly,
3901
4151
  error: this.error,
@@ -3943,7 +4193,7 @@ var AnimationEditorController = (_class = class {
3943
4193
  this.applying = false;
3944
4194
  }
3945
4195
  this.notify();
3946
- _optionalChain([this, 'access', _162 => _162.onChange, 'optionalCall', _163 => _163(scene)]);
4196
+ _optionalChain([this, 'access', _181 => _181.onChange, 'optionalCall', _182 => _182(scene)]);
3947
4197
  }
3948
4198
  commit(label, next, merge) {
3949
4199
  const before = this.scene;
@@ -4013,7 +4263,7 @@ var AnimationEditorController = (_class = class {
4013
4263
  try {
4014
4264
  plan = await work();
4015
4265
  } catch (error) {
4016
- if (_chunk5MQOBTNPcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
4266
+ if (_chunkOPSK22DLcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
4017
4267
  throw error;
4018
4268
  }
4019
4269
  const r = this.apply({ op: "replace_scene", scene: plan.scene }, plan.label, { merge });
@@ -4024,11 +4274,11 @@ var AnimationEditorController = (_class = class {
4024
4274
  }
4025
4275
  async describeFor(effect, kinds) {
4026
4276
  const provider = this.effects.require();
4027
- if (!provider.applyVectorEffect) throw new (0, _chunk5MQOBTNPcjs.EffectUnsupportedError)(`${provider.name} has no vector or motion effects.`);
4277
+ if (!provider.applyVectorEffect) throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`${provider.name} has no vector or motion effects.`);
4028
4278
  const d = await provider.describe(effect);
4029
4279
  if (!kinds.includes(d.kind)) {
4030
4280
  const hint = d.kind === "motion" ? "apply it to nodes with apply_effect" : d.kind === "vector" ? "add it with add_vector_effect" : "it draws pixels, which scenes cannot hold";
4031
- throw new (0, _chunk5MQOBTNPcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.kind} effect: ${hint}.`, d.id);
4281
+ throw new (0, _chunkOPSK22DLcjs.EffectUnsupportedError)(`"${d.id}" (${d.name}) is a ${d.kind} effect: ${hint}.`, d.id);
4032
4282
  }
4033
4283
  return d;
4034
4284
  }
@@ -4049,7 +4299,7 @@ var AnimationEditorController = (_class = class {
4049
4299
  return this.effectEdit(async () => {
4050
4300
  this.knownNodes(targets);
4051
4301
  const d = await this.describeFor(effect, ["motion"]);
4052
- const values = _chunk5MQOBTNPcjs.resolveEffectValues.call(void 0, d, options.values);
4302
+ const values = _chunkOPSK22DLcjs.resolveEffectValues.call(void 0, d, options.values);
4053
4303
  const instance = _nullishCoalesce(options.instance, () => ( nextMotionEffectInstance(this.scene)));
4054
4304
  const motion = await this.effects.require().applyVectorEffect(d.id, { svg: motionArtworkSvg(this.scene.artwork), nodeIds: [...targets] }, values);
4055
4305
  const source = { instance, effect: d.id, provider: this.effects.require().id, name: d.name, values };
@@ -4071,7 +4321,7 @@ var AnimationEditorController = (_class = class {
4071
4321
  addVectorEffect(effect, options = {}) {
4072
4322
  return this.effectEdit(async () => {
4073
4323
  const d = await this.describeFor(effect, ["vector"]);
4074
- const values = _chunk5MQOBTNPcjs.resolveEffectValues.call(void 0, d, options.values);
4324
+ const values = _chunkOPSK22DLcjs.resolveEffectValues.call(void 0, d, options.values);
4075
4325
  const instance = _nullishCoalesce(options.instance, () => ( nextMotionEffectInstance(this.scene)));
4076
4326
  const motion = await this.effects.require().applyVectorEffect(d.id, motionArtworkSvg(this.scene.artwork), values);
4077
4327
  const source = { instance, effect: d.id, provider: this.effects.require().id, name: d.name, values };
@@ -4095,7 +4345,7 @@ var AnimationEditorController = (_class = class {
4095
4345
  else if (k in d.controls.properties) base[k] = d.defaults[k];
4096
4346
  else throw new Error(`"${k}" is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ")}.`);
4097
4347
  }
4098
- const merged = { ...base, ..._chunk5MQOBTNPcjs.resolveEffectValues.call(void 0, { ...d, defaults: base }, given) };
4348
+ const merged = { ...base, ..._chunkOPSK22DLcjs.resolveEffectValues.call(void 0, { ...d, defaults: base }, given) };
4099
4349
  const { scene: bare, place } = withoutMotionEffect(this.scene, instance);
4100
4350
  const provider = this.effects.require();
4101
4351
  const source = { instance, effect: d.id, provider: provider.id, name: d.name, values: merged };
@@ -4105,7 +4355,7 @@ var AnimationEditorController = (_class = class {
4105
4355
  const { group, shots: shots2, notes: notes2 } = motionPartsFromVectorEffect(bare.artwork, motion2, source);
4106
4356
  const index = this.scene.artwork.nodes.findIndex((n) => n.id === instance);
4107
4357
  const nodes = [...bare.artwork.nodes];
4108
- nodes.splice(Math.max(0, index), 0, _optionalChain([old, 'optionalAccess', _164 => _164.transform]) ? { ...group, transform: old.transform } : group);
4358
+ nodes.splice(Math.max(0, index), 0, _optionalChain([old, 'optionalAccess', _183 => _183.transform]) ? { ...group, transform: old.transform } : group);
4109
4359
  const at = this.scene.shots.findIndex((s) => was.shots.includes(s.id));
4110
4360
  const kept = bare.shots;
4111
4361
  const nextShots = [...kept.slice(0, Math.max(0, at)), ...shots2, ...kept.slice(Math.max(0, at))];
@@ -4116,7 +4366,7 @@ var AnimationEditorController = (_class = class {
4116
4366
  let shots = bare.shots;
4117
4367
  if (place && shots.some((s) => s.id === place.shot)) shots = shots.map((s) => s.id === place.shot ? { ...s, run: [...s.run.slice(0, place.index), ...commands, ...s.run.slice(place.index)] } : s);
4118
4368
  else {
4119
- const at = this.scene.shots.findIndex((s) => s.id === _optionalChain([place, 'optionalAccess', _165 => _165.shot]));
4369
+ const at = this.scene.shots.findIndex((s) => s.id === _optionalChain([place, 'optionalAccess', _184 => _184.shot]));
4120
4370
  shots = [...shots.slice(0, Math.max(0, at)), { id: instance, label: d.name, run: commands }, ...shots.slice(Math.max(0, at))];
4121
4371
  }
4122
4372
  return { scene: { ...bare, shots }, label: `Change ${d.name}`, instance, notes };
@@ -4129,6 +4379,64 @@ var AnimationEditorController = (_class = class {
4129
4379
  const r = this.apply({ op: "replace_scene", scene: withoutMotionEffect(this.scene, instance).scene }, `Remove ${_nullishCoalesce(was.name, () => ( was.effect))}`);
4130
4380
  return r.ok ? { ok: true, effect: was, notes: [] } : r;
4131
4381
  }
4382
+ /**
4383
+ * The provider's camera moves for a role (`transition` for a shot's `camera.in`, `hold` for its
4384
+ * `camera.during`), or all of them. Empty without a provider that has camera moves.
4385
+ */
4386
+ cameraMoves(role) {
4387
+ return motionCameraMoves(this.effects.provider, role);
4388
+ }
4389
+ /**
4390
+ * Sets the camera move a shot gets in with (`transition`, its `camera.in`) or plays while it
4391
+ * holds (`hold`, its `camera.during`). The move is checked against the provider first (its
4392
+ * role, preset and values; a preset's values are written out), then set in one undo step.
4393
+ * A shot with no camera gets one that keeps the framing. Returns the shot's camera and when the
4394
+ * move plays. `merge` folds a slider drag's changes into one undo step.
4395
+ */
4396
+ async setShotCameraMove(shot, role, spec, options = {}) {
4397
+ const reason = this.readOnlyReason();
4398
+ if (reason) return this.refuse(reason);
4399
+ const found = this.scene.shots.find((s) => s.id === shot);
4400
+ if (!found) return this.refuse(`There is no shot "${shot}"; the shots are ${this.scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
4401
+ let resolved;
4402
+ try {
4403
+ resolved = await _chunkOPSK22DLcjs.resolveCameraMoveSpec.call(void 0, this.effects.require(), spec, role);
4404
+ } catch (error) {
4405
+ if (_chunkOPSK22DLcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refuse(error.message);
4406
+ throw error;
4407
+ }
4408
+ const field = _chunkOPSK22DLcjs.cameraMoveField.call(void 0, role);
4409
+ const current = this.scene.shots.find((s) => s.id === shot);
4410
+ if (!current) return this.refuse(`Shot "${shot}" was removed while the move was checked.`);
4411
+ const parts = role === "transition" && resolved.spec.ms === void 0 ? { ...resolved.spec, ms: resolved.description.camera.durationMs } : resolved.spec;
4412
+ const simple = parts.ms === void 0 && parts.preset === void 0 && parts.values === void 0;
4413
+ const camera = { ..._nullishCoalesce(current.camera, () => ( {})), [field]: simple ? parts.move : parts };
4414
+ const r = this.apply({ op: "update_shot", shot, set: { camera } }, `${role === "hold" ? "Hold move" : "Camera move"} ${resolved.description.name}`, { merge: options.merge });
4415
+ if (!r.ok) return r;
4416
+ return this.cameraMoveResult(shot, role, resolved.description.id);
4417
+ }
4418
+ /** Removes a shot's camera move for a role, keeping its framing (a camera left with nothing is removed). One undo step. Works without a provider. */
4419
+ clearShotCameraMove(shot, role) {
4420
+ const found = this.scene.shots.find((s) => s.id === shot);
4421
+ if (!found) return this.refuse(`There is no shot "${shot}"; the shots are ${this.scene.shots.map((s) => `"${s.id}"`).join(", ") || "none yet"}.`);
4422
+ const field = _chunkOPSK22DLcjs.cameraMoveField.call(void 0, role);
4423
+ if (_optionalChain([found, 'access', _185 => _185.camera, 'optionalAccess', _186 => _186[field]]) === void 0) return this.refuse(`Shot "${shot}" has no camera "${field}" move to clear${_optionalChain([found, 'access', _187 => _187.camera, 'optionalAccess', _188 => _188[field === "in" ? "during" : "in"]]) !== void 0 ? `; it has a "${field === "in" ? "during" : "in"}" move (role ${role === "hold" ? "transition" : "hold"})` : ""}.`);
4424
+ const rest = { ...found.camera };
4425
+ delete rest[field];
4426
+ const keep = motionCameraFramed(rest) || rest.in !== void 0 || rest.during !== void 0;
4427
+ const r = this.apply(keep ? { op: "update_shot", shot, set: { camera: rest } } : { op: "update_shot", shot, remove: ["camera"] }, role === "hold" ? "Clear hold move" : "Clear camera move");
4428
+ if (!r.ok) return r;
4429
+ return this.cameraMoveResult(shot, role);
4430
+ }
4431
+ cameraMoveResult(shot, role, move) {
4432
+ const timing = compileMotionScene(this.scene).shots.find((s) => s.id === shot);
4433
+ const camera = _nullishCoalesce(_optionalChain([this, 'access', _189 => _189.scene, 'access', _190 => _190.shots, 'access', _191 => _191.find, 'call', _192 => _192((s) => s.id === shot), 'optionalAccess', _193 => _193.camera]), () => ( null));
4434
+ const window = role === "transition" ? { start: timing.start, end: timing.commandsStart } : { start: timing.commandsEnd, end: timing.end };
4435
+ const notes = [];
4436
+ if (move && role === "transition" && timing.index === 0) notes.push('This is the first shot, which cuts to its framing, so its "in" move does not play; it plays from the second shot on.');
4437
+ if (move && !effectsPlayCamera(this.effects.provider)) notes.push("The provider cannot play camera moves, so the camera eases instead.");
4438
+ return { ok: true, shot, camera, ...move ? { window } : {}, notes };
4439
+ }
4132
4440
  /** Opens a scene (JSON or object). `clearHistory` drops the undo stack (opening a file); otherwise it is one undo step. */
4133
4441
  load(scene, options = {}) {
4134
4442
  if (options.clearHistory) this.cancelRecording();
@@ -4193,13 +4501,13 @@ var AnimationEditorController = (_class = class {
4193
4501
  viewScene() {
4194
4502
  const r = this.recording;
4195
4503
  if (!r) return this.scene;
4196
- if (_optionalChain([r, 'access', _166 => _166.preview, 'optionalAccess', _167 => _167.count]) === r.samples.length) return r.preview.scene;
4504
+ if (_optionalChain([r, 'access', _194 => _194.preview, 'optionalAccess', _195 => _195.count]) === r.samples.length) return r.preview.scene;
4197
4505
  let scene = this.scene;
4198
4506
  if (r.samples.length) {
4199
4507
  try {
4200
4508
  const { shot, at } = motionTakeShot(this.scene, { samples: r.samples, length: Math.max(0, this.player.currentTime - r.start) }, r.options);
4201
4509
  scene = { ...this.scene, shots: [...this.scene.shots.slice(0, at), shot, ...this.scene.shots.slice(at)] };
4202
- } catch (e6) {
4510
+ } catch (e8) {
4203
4511
  }
4204
4512
  }
4205
4513
  r.preview = { count: r.samples.length, scene };
@@ -4207,11 +4515,11 @@ var AnimationEditorController = (_class = class {
4207
4515
  }
4208
4516
  /** The scene at `time` (default: the playhead). */
4209
4517
  frame(time = this.player.currentTime, options = {}) {
4210
- return motionFrameAt(this.viewScene(), time, options);
4518
+ return motionFrameAt(this.viewScene(), time, { effects: this.effects.provider, ...options });
4211
4519
  }
4212
4520
  /** The scene at `time` (default: the playhead) as SVG. */
4213
4521
  toSvg(time = this.player.currentTime, options = {}) {
4214
- return motionStageSvg(this.viewScene(), time, options);
4522
+ return motionStageSvg(this.viewScene(), time, { effects: this.effects.provider, ...options });
4215
4523
  }
4216
4524
  // ---------------------------------------------------------------------------------------
4217
4525
  // Recording
@@ -4278,13 +4586,13 @@ var AnimationEditorController = (_class = class {
4278
4586
  }
4279
4587
  /** Records the drag's pose with the pointer at `point` (document units). */
4280
4588
  updateRecordGesture(point) {
4281
- const g = _optionalChain([this, 'access', _168 => _168.recording, 'optionalAccess', _169 => _169.gesture]);
4589
+ const g = _optionalChain([this, 'access', _196 => _196.recording, 'optionalAccess', _197 => _197.gesture]);
4282
4590
  if (g) this.recordGesture(g.pose, point);
4283
4591
  }
4284
4592
  /** Ends the stage drag (the take keeps recording). */
4285
4593
  endRecordGesture() {
4286
4594
  const r = this.recording;
4287
- if (!_optionalChain([r, 'optionalAccess', _170 => _170.gesture])) return;
4595
+ if (!_optionalChain([r, 'optionalAccess', _198 => _198.gesture])) return;
4288
4596
  r.gesture = null;
4289
4597
  this.notify();
4290
4598
  }
@@ -4298,7 +4606,7 @@ var AnimationEditorController = (_class = class {
4298
4606
  this.recordSample(g.node, { scaleX: Math.max(0.01, pose.scaleX * f), scaleY: Math.max(0.01, pose.scaleY * f) });
4299
4607
  } else {
4300
4608
  const turn = (Math.atan2(point.y - c.y, point.x - c.x) - Math.atan2(g.from.y - c.y, g.from.x - c.x)) * (180 / Math.PI);
4301
- const was = _nullishCoalesce(_optionalChain([this, 'access', _171 => _171.recording, 'access', _172 => _172.samples, 'access', _173 => _173.filter, 'call', _174 => _174((s) => s.node === g.node && s.rotation !== void 0), 'access', _175 => _175.at, 'call', _176 => _176(-1), 'optionalAccess', _177 => _177.rotation]), () => ( pose.rotation));
4609
+ const was = _nullishCoalesce(_optionalChain([this, 'access', _199 => _199.recording, 'access', _200 => _200.samples, 'access', _201 => _201.filter, 'call', _202 => _202((s) => s.node === g.node && s.rotation !== void 0), 'access', _203 => _203.at, 'call', _204 => _204(-1), 'optionalAccess', _205 => _205.rotation]), () => ( pose.rotation));
4302
4610
  let next = pose.rotation + turn;
4303
4611
  next += 360 * Math.round((was - next) / 360);
4304
4612
  this.recordSample(g.node, { rotation: next });
@@ -4354,15 +4662,15 @@ var AnimationEditorController = (_class = class {
4354
4662
  }
4355
4663
  /** The scene as a Flair `SvgMotion`. */
4356
4664
  toFlairMotion(options = {}) {
4357
- return toFlairSvgMotion(this.scene, options);
4665
+ return toFlairSvgMotion(this.scene, { effects: this.effects.provider, ...options });
4358
4666
  }
4359
4667
  /** The scene as a Flair catalog vector effect. */
4360
4668
  toFlairEffect(options = {}) {
4361
- return toFlairVectorEffect(this.scene, options);
4669
+ return toFlairVectorEffect(this.scene, { effects: this.effects.provider, ...options });
4362
4670
  }
4363
4671
  /** The scene as a Flair `EffectDocument`. */
4364
4672
  toFlairDocument(options = {}) {
4365
- return toFlairEffectDocument(this.scene, options);
4673
+ return toFlairEffectDocument(this.scene, { effects: this.effects.provider, ...options });
4366
4674
  }
4367
4675
  }, _class);
4368
4676
 
@@ -4392,7 +4700,7 @@ function elementsOf(args) {
4392
4700
  if (Array.isArray(args.ops)) {
4393
4701
  for (const op of args.ops) {
4394
4702
  fromShot(op);
4395
- if (Array.isArray(_optionalChain([op, 'optionalAccess', _178 => _178.shots]))) op.shots.forEach(fromShot);
4703
+ if (Array.isArray(_optionalChain([op, 'optionalAccess', _206 => _206.shots]))) op.shots.forEach(fromShot);
4396
4704
  }
4397
4705
  }
4398
4706
  return out.slice(0, 4);
@@ -4574,7 +4882,7 @@ var MOTION_COMMAND_SCHEMA = {
4574
4882
  oneOf: MOTION_COMMAND_TYPES.map((type) => MOTION_COMMAND_TYPE_SCHEMAS[type])
4575
4883
  };
4576
4884
  var REF2 = (name, description) => ({ $ref: `#/$defs/${name}`, ...description ? { description } : {} });
4577
- var firstSentence = (text) => _nullishCoalesce(_optionalChain([/^.*?[.;](?=\s|$)/, 'access', _179 => _179.exec, 'call', _180 => _180(text), 'optionalAccess', _181 => _181[0]]), () => ( text));
4885
+ var firstSentence = (text) => _nullishCoalesce(_optionalChain([/^.*?[.;](?=\s|$)/, 'access', _207 => _207.exec, 'call', _208 => _208(text), 'optionalAccess', _209 => _209[0]]), () => ( text));
4578
4886
  var COMMAND_TYPE_LINES = MOTION_COMMAND_TYPES.map((type) => `${type}: ${firstSentence(_nullishCoalesce(MOTION_COMMAND_TYPE_SCHEMAS[type].description, () => ( "")))}`);
4579
4887
  var EASE_COMPACT = {
4580
4888
  description: `Easing: a preset, or a curve { "type": "cubic-bezier", x1, y1, x2, y2 }, { "type": "spring", stiffness, damping, mass, velocity } (spring presets are Figma's; with no "duration" it lasts until it settles) or { "type": "elastic", amplitude, period, mode }. Default: ease-out for entrances, ease-in-out for moves.`,
@@ -4776,11 +5084,11 @@ function describeElement(node, ancestors) {
4776
5084
  ...effects.length ? { effects } : {}
4777
5085
  };
4778
5086
  }
4779
- var round2 = (n) => Math.round(n * 10) / 10;
5087
+ var round3 = (n) => Math.round(n * 10) / 10;
4780
5088
  function describeMotionElements(scene) {
4781
5089
  return [...indexMotionNodes(scene.artwork.nodes).values()].map((e) => ({
4782
5090
  ...describeElement(e.node, e.ancestors),
4783
- ...e.bounds ? { bounds: { x: round2(e.bounds.x), y: round2(e.bounds.y), width: round2(e.bounds.width), height: round2(e.bounds.height) } } : {}
5091
+ ...e.bounds ? { bounds: { x: round3(e.bounds.x), y: round3(e.bounds.y), width: round3(e.bounds.width), height: round3(e.bounds.height) } } : {}
4784
5092
  }));
4785
5093
  }
4786
5094
  function describeMotionShots(scene) {
@@ -4808,7 +5116,7 @@ var issueSummary = (issues) => ({
4808
5116
  errors: issues.filter((i) => i.severity === "error").length,
4809
5117
  warnings: issues.filter((i) => i.severity === "warning").length,
4810
5118
  notes: issues.filter((i) => i.severity === "note").length,
4811
- lines: issues.map((i) => `${i.severity}: ${_chunkEBDZWIOPcjs.motionIssueLine.call(void 0, i)}`)
5119
+ lines: issues.map((i) => `${i.severity}: ${_chunkERJA5CGTcjs.motionIssueLine.call(void 0, i)}`)
4812
5120
  });
4813
5121
  function createAnimationEditorToolProvider(controller, options = {}) {
4814
5122
  const readOnlyReason = () => {
@@ -4872,7 +5180,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4872
5180
  annotations: { title: "Describe command types", ...READ },
4873
5181
  handler: ({ types }) => {
4874
5182
  for (const type of types)
4875
- if (!MOTION_COMMAND_TYPES.includes(type)) throw new Error(`There is no command type ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`);
5183
+ if (!MOTION_COMMAND_TYPES.includes(type)) throw new Error(`There is no command type ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, type, MOTION_COMMAND_TYPES)}; use one of ${MOTION_COMMAND_TYPES.join(", ")}.`);
4876
5184
  return { commands: types.map((type) => ({ type, schema: MOTION_COMMAND_TYPE_SCHEMAS[type] })) };
4877
5185
  }
4878
5186
  };
@@ -4945,7 +5253,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4945
5253
  }
4946
5254
  if (Array.isArray(motion_paths)) {
4947
5255
  const known = new Set(describeMotionElements(s).map((e) => e.id));
4948
- for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, known)} to draw a motion path for.`);
5256
+ for (const id of motion_paths) if (!known.has(id)) throw new Error(`There is no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, known)} to draw a motion path for.`);
4949
5257
  }
4950
5258
  const overlays = { ...onion_skin ? { onionSkin: onion_skin } : {}, ...motion_paths ? { motionPaths: motion_paths } : {} };
4951
5259
  if (times) {
@@ -4983,9 +5291,9 @@ function createAnimationEditorToolProvider(controller, options = {}) {
4983
5291
  handler: ({ from = 0, to, limit = 200 }) => {
4984
5292
  const s = scene();
4985
5293
  const timeline = compileMotionScene(s);
4986
- const words = _nullishCoalesce(_optionalChain([s, 'access', _182 => _182.narration, 'optionalAccess', _183 => _183.words]), () => ( []));
5294
+ const words = _nullishCoalesce(_optionalChain([s, 'access', _210 => _210.narration, 'optionalAccess', _211 => _211.words]), () => ( []));
4987
5295
  const end = _nullishCoalesce(to, () => ( Math.max(timeline.duration, words.length ? _nullishCoalesce(words[words.length - 1].end, () => ( words[words.length - 1].start)) : 0)));
4988
- const shotAt = (ms2) => _optionalChain([timeline, 'access', _184 => _184.shots, 'access', _185 => _185.find, 'call', _186 => _186((x) => ms2 >= x.start && ms2 < x.end), 'optionalAccess', _187 => _187.id]);
5296
+ const shotAt = (ms2) => _optionalChain([timeline, 'access', _212 => _212.shots, 'access', _213 => _213.find, 'call', _214 => _214((x) => ms2 >= x.start && ms2 < x.end), 'optionalAccess', _215 => _215.id]);
4989
5297
  const beats = [];
4990
5298
  if (s.beat && s.beat.bpm > 0) {
4991
5299
  const first = Math.max(0, Math.ceil(motionBeatAt(s.beat, from).beat - 1e-9));
@@ -5015,7 +5323,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
5015
5323
  handler: ({ group }) => {
5016
5324
  const s = scene();
5017
5325
  const nodes = indexMotionNodes(s.artwork.nodes);
5018
- if (!nodes.has(group)) throw new Error(`There is no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, group, [...nodes.keys()])}.`);
5326
+ if (!nodes.has(group)) throw new Error(`There is no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, group, [...nodes.keys()])}.`);
5019
5327
  const layout = motionTextLayout(nodes, group);
5020
5328
  if (!layout) throw new Error(`"${group}" is not a group of paths; convert the text to outlines (one path a letter) and group it.`);
5021
5329
  return { group, letters: layout.lines.reduce((n, l) => n + l.words.reduce((m, w) => m + w.letters.length, 0), 0), ...layout };
@@ -5035,7 +5343,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
5035
5343
  handler: ({ node, from, to, step }) => {
5036
5344
  const s = scene();
5037
5345
  const ids = describeMotionElements(s).map((e) => e.id);
5038
- if (!ids.includes(node)) throw new Error(`There is no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, node, ids)}.`);
5346
+ if (!ids.includes(node)) throw new Error(`There is no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, node, ids)}.`);
5039
5347
  return motionPath(s, node, { from, to, step });
5040
5348
  }
5041
5349
  };
@@ -5287,11 +5595,11 @@ function createAnimationEditorToolProvider(controller, options = {}) {
5287
5595
  handler: ({ from, to, shots, stagger }) => {
5288
5596
  const s = scene();
5289
5597
  const ids = describeMotionElements(s).map((e) => e.id);
5290
- for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, ids)}. Nothing was changed.`);
5598
+ for (const id of [from, ...to]) if (!ids.includes(id)) throw new Error(`There is no element ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, ids)}. Nothing was changed.`);
5291
5599
  if (to.includes(from)) throw new Error(`"to" includes "${from}" itself; give other elements. Nothing was changed.`);
5292
5600
  const only = shots ? new Set(shots) : null;
5293
5601
  if (only) {
5294
- for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, s.shots.map((x) => x.id))}. Nothing was changed.`);
5602
+ for (const id of only) if (!s.shots.some((x) => x.id === id)) throw new Error(`There is no shot ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, s.shots.map((x) => x.id))}. Nothing was changed.`);
5295
5603
  }
5296
5604
  const copied = {};
5297
5605
  const edits = [];
@@ -5361,7 +5669,7 @@ function createAnimationEditorToolProvider(controller, options = {}) {
5361
5669
  inputSchema: object({ shot: SHOT_ID, commands: { type: "array", items: REF2("command"), minItems: 1, description: "Commands to add." }, at: { type: "integer", minimum: 0, description: "Index in the run (default: the end)." } }, ["shot", "commands"]),
5362
5670
  annotations: { title: "Add commands to a shot", ...WRITE },
5363
5671
  handler: ({ shot, commands, at }) => {
5364
- const before = _nullishCoalesce(_optionalChain([scene, 'call', _188 => _188(), 'access', _189 => _189.shots, 'access', _190 => _190.find, 'call', _191 => _191((s) => s.id === shot), 'optionalAccess', _192 => _192.run, 'access', _193 => _193.length]), () => ( 0));
5672
+ const before = _nullishCoalesce(_optionalChain([scene, 'call', _216 => _216(), 'access', _217 => _217.shots, 'access', _218 => _218.find, 'call', _219 => _219((s) => s.id === shot), 'optionalAccess', _220 => _220.run, 'access', _221 => _221.length]), () => ( 0));
5365
5673
  const first = _nullishCoalesce(at, () => ( before));
5366
5674
  return apply({ op: "add_commands", shot, commands, at }, "Add commands", (s) => {
5367
5675
  const shots = describeMotionShots(s);
@@ -5562,7 +5870,7 @@ var TIMING = /* @__PURE__ */ new Set(["duration", "delay", "stagger", "with", "e
5562
5870
  var COLORS = /* @__PURE__ */ new Set(["fill", "stroke", "color"]);
5563
5871
  var NODES = /* @__PURE__ */ new Set(["into", "path"]);
5564
5872
  function branch(type) {
5565
- return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _194 => _194.properties, 'optionalAccess', _195 => _195.type, 'optionalAccess', _196 => _196.const]) === type);
5873
+ return (_nullishCoalesce(MOTION_COMMAND_SCHEMA.oneOf, () => ( []))).find((b) => _optionalChain([b, 'access', _222 => _222.properties, 'optionalAccess', _223 => _223.type, 'optionalAccess', _224 => _224.const]) === type);
5566
5874
  }
5567
5875
  function unitOf(type, name) {
5568
5876
  if (name === "duration" || name === "delay" || name === "stagger") return "ms";
@@ -5597,7 +5905,7 @@ function kindOf(name, schema) {
5597
5905
  }
5598
5906
  function motionCommandFields(type) {
5599
5907
  const schema = branch(type);
5600
- if (!_optionalChain([schema, 'optionalAccess', _197 => _197.properties])) return [];
5908
+ if (!_optionalChain([schema, 'optionalAccess', _225 => _225.properties])) return [];
5601
5909
  const required = new Set(_nullishCoalesce(schema.required, () => ( [])));
5602
5910
  const fields = Object.entries(schema.properties).filter(([name]) => name !== "type").map(([name, s]) => {
5603
5911
  const kind = kindOf(name, s);
@@ -5654,7 +5962,7 @@ function defaultMotionCommand(type, targets, scene) {
5654
5962
  if (type === "wait") return { type: "wait", duration: 500 };
5655
5963
  if (!targets.length) return { error: "Pick a target first: click an element on the stage." };
5656
5964
  const nodes = [...indexMotionNodes(scene.artwork.nodes).values()];
5657
- const other = (pred) => _optionalChain([nodes, 'access', _198 => _198.find, 'call', _199 => _199((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _200 => _200.node, 'access', _201 => _201.id]);
5965
+ const other = (pred) => _optionalChain([nodes, 'access', _226 => _226.find, 'call', _227 => _227((e) => !targets.includes(e.node.id) && pred(e)), 'optionalAccess', _228 => _228.node, 'access', _229 => _229.id]);
5658
5966
  const base = { targets: [...targets] };
5659
5967
  switch (type) {
5660
5968
  case "scale":
@@ -5685,8 +5993,8 @@ function defaultMotionCommand(type, targets, scene) {
5685
5993
  }
5686
5994
  case "effect": {
5687
5995
  for (const id of targets) {
5688
- const node = _optionalChain([nodes, 'access', _202 => _202.find, 'call', _203 => _203((e) => e.node.id === id), 'optionalAccess', _204 => _204.node]);
5689
- for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _205 => _205.effects]), () => ( []))) {
5996
+ const node = _optionalChain([nodes, 'access', _230 => _230.find, 'call', _231 => _231((e) => e.node.id === id), 'optionalAccess', _232 => _232.node]);
5997
+ for (const effect of _nullishCoalesce(_optionalChain([node, 'optionalAccess', _233 => _233.effects]), () => ( []))) {
5690
5998
  const param = Object.entries(effect.params).find(([, v]) => typeof v === "number");
5691
5999
  if (param) return { type, ...base, effect: effect.id, param: param[0], to: param[1] + 1 };
5692
6000
  }
@@ -5711,11 +6019,11 @@ function motionCommandRows(scene, shotId) {
5711
6019
  return scene.shots[index].run.map((command3, i) => {
5712
6020
  const t = timeline.commands.find((c) => c.shotIndex === index && c.command === i);
5713
6021
  const primitive = motionFlairPrimitive(command3);
5714
- return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _206 => _206.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _207 => _207.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
6022
+ return { index: i, command: command3, summary: motionCommandSummary(command3), start: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _234 => _234.start]), () => ( 0)), end: _nullishCoalesce(_optionalChain([t, 'optionalAccess', _235 => _235.end]), () => ( 0)), ...primitive ? { flairPrimitive: primitive } : {} };
5715
6023
  });
5716
6024
  }
5717
6025
  function duplicateMotionCommandEdit(scene, shot, command3) {
5718
- const run = _nullishCoalesce(_optionalChain([scene, 'access', _208 => _208.shots, 'access', _209 => _209.find, 'call', _210 => _210((s) => s.id === shot), 'optionalAccess', _211 => _211.run]), () => ( []));
6026
+ const run = _nullishCoalesce(_optionalChain([scene, 'access', _236 => _236.shots, 'access', _237 => _237.find, 'call', _238 => _238((s) => s.id === shot), 'optionalAccess', _239 => _239.run]), () => ( []));
5719
6027
  return { op: "add_commands", shot, commands: run[command3] ? [structuredClone(run[command3])] : [], at: command3 + 1 };
5720
6028
  }
5721
6029
  var MOTION_EASE_CHOICES = [
@@ -5800,7 +6108,7 @@ function motionCueFromKey(key) {
5800
6108
  function motionCueChoices(scene, limit = 256) {
5801
6109
  const choices = [];
5802
6110
  const s = (ms2) => `${(ms2 / 1e3).toFixed(2)} s`;
5803
- const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _212 => _212.narration, 'optionalAccess', _213 => _213.words, 'access', _214 => _214.map, 'call', _215 => _215((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
6111
+ const end = Math.max(compileMotionScene(scene).duration, ..._nullishCoalesce(_optionalChain([scene, 'access', _240 => _240.narration, 'optionalAccess', _241 => _241.words, 'access', _242 => _242.map, 'call', _243 => _243((w) => _nullishCoalesce(w.end, () => ( w.start)))]), () => ( [0]))) + 2e3;
5804
6112
  if (scene.beat && scene.beat.bpm > 0) {
5805
6113
  for (let beat = 0; choices.length < limit; beat++) {
5806
6114
  const time = motionBeatTime(scene.beat, beat);
@@ -5810,7 +6118,7 @@ function motionCueChoices(scene, limit = 256) {
5810
6118
  choices.push({ value: `beat:${beat}`, label: `Beat ${beat} (bar ${at.bar}.${at.beatInBar}) \xB7 ${s(time)}`, time });
5811
6119
  }
5812
6120
  }
5813
- _optionalChain([scene, 'access', _216 => _216.narration, 'optionalAccess', _217 => _217.words, 'access', _218 => _218.forEach, 'call', _219 => _219((w, i) => {
6121
+ _optionalChain([scene, 'access', _244 => _244.narration, 'optionalAccess', _245 => _245.words, 'access', _246 => _246.forEach, 'call', _247 => _247((w, i) => {
5814
6122
  if (choices.length < limit * 2) choices.push({ value: `word:${i}`, label: `Word ${i} \u201C${w.text}\u201D \xB7 ${s(w.start)}`, time: w.start });
5815
6123
  })]);
5816
6124
  return choices;
@@ -5819,7 +6127,7 @@ function motionShotCueTime(scene, cue) {
5819
6127
  return cue ? motionCueTime(scene, cue) : void 0;
5820
6128
  }
5821
6129
  function formatMotionNarration(narration) {
5822
- return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _220 => _220.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
6130
+ return (_nullishCoalesce(_optionalChain([narration, 'optionalAccess', _248 => _248.words]), () => ( []))).map((w) => `${w.start} ${w.text}`).join("\n");
5823
6131
  }
5824
6132
  function parseMotionNarration(text) {
5825
6133
  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -5856,6 +6164,71 @@ function parseMotionDrivers(text) {
5856
6164
  return { drivers };
5857
6165
  }
5858
6166
 
6167
+ // src/animation-editor/camera-tools.ts
6168
+ var ROLE = {
6169
+ type: "string",
6170
+ enum: ["transition", "hold"],
6171
+ description: `transition: the move the camera gets into the shot with (its camera "in": a glide, whip pan, punch zoom, cut). hold: the move it makes while the shot holds (its camera "during": a Ken Burns drift, a crash zoom), played across the shot's hold.`
6172
+ };
6173
+ var summary = (e) => ({ id: e.id, name: e.name, role: e.camera.role, durationMs: e.camera.durationMs, ...e.camera.cut !== void 0 ? { cut: e.camera.cut } : {}, ...e.description ? { description: e.description } : {}, ..._optionalChain([e, 'access', _249 => _249.tags, 'optionalAccess', _250 => _250.length]) ? { tags: e.tags } : {} });
6174
+ var done = (r) => {
6175
+ if (!r.ok) throw new Error(r.error);
6176
+ return { shot: r.shot, camera: r.camera, ...r.window ? { window: r.window } : {}, ...r.notes.length ? { notes: r.notes } : {} };
6177
+ };
6178
+ function animationCameraMoveTools(controller, ctx) {
6179
+ return [
6180
+ {
6181
+ name: "list_camera_moves",
6182
+ title: "List camera moves",
6183
+ description: "Lists the effects provider's camera moves, for a role or both: { available, moves: [{ id, name, role, durationMs, cut (0\u20131 of the way through where the view jumps, for moves that cut), description, tags }] }. Use the ids with set_shot_camera_move (role transition for how the camera gets into a shot, hold for how it moves while the shot holds) and describe_effect for a move's controls and presets. Without a provider that has camera moves it returns available: false and the reason; the camera then eases between framings.",
6184
+ inputSchema: { type: "object", properties: { role: ROLE }, additionalProperties: false },
6185
+ annotations: { title: "List camera moves", ...ctx.annotations.read },
6186
+ handler: async (args) => {
6187
+ const provider = controller.effectsProvider;
6188
+ if (!effectsPlayCamera(provider)) return { available: false, reason: provider ? `${provider.name} has no camera moves (capabilities.supportsCamera is not set), so shots ease between framings.` : "No effects provider is registered, so there are no camera moves; shots ease between framings.", moves: [] };
6189
+ return { available: true, provider: provider.name, moves: (await controller.cameraMoves(args.role)).map(summary) };
6190
+ }
6191
+ },
6192
+ {
6193
+ name: "set_shot_camera_move",
6194
+ title: "Set a shot's camera move",
6195
+ description: `Sets the camera move a shot gets in with (role transition, its camera "in") or makes while it holds (role hold, its camera "during"), from list_camera_moves. The move is checked first: an id of the wrong role, an unknown preset or values outside its controls are refused with the moves or presets that fit. A shot with no camera gets one that keeps the framing; set the framing itself with update_shot. One undo step. Returns { shot, camera (the shot's camera now), window: { start, end } (ms when the move plays), notes }. The first shot cuts to its framing, so its transition does not play. A hold move plays across the shot's hold: lengthen it with update_shot (hold) for a slower move.`,
6196
+ inputSchema: {
6197
+ type: "object",
6198
+ properties: {
6199
+ shot: { type: "string", minLength: 1, description: "A shot id from get_animation." },
6200
+ role: ROLE,
6201
+ move: { type: "string", minLength: 1, description: "A camera move id of that role from list_camera_moves." },
6202
+ ms: { type: "number", minimum: 0, maximum: _chunkOPSK22DLcjs.CAMERA_MOVE_MAX_MS, description: `How long a transition takes, ms (0\u2013${_chunkOPSK22DLcjs.CAMERA_MOVE_MAX_MS}; default the move's durationMs). Not for a hold, which plays across the shot's hold.` },
6203
+ preset: { type: "string", minLength: 1, description: "A preset of the move by name, from describe_effect; its values are written out on the shot." },
6204
+ values: ctx.valuesSchema("Control values over the move's defaults (and the preset's), from describe_effect")
6205
+ },
6206
+ required: ["shot", "role", "move"],
6207
+ additionalProperties: false
6208
+ },
6209
+ annotations: { title: "Set a shot's camera move", ...ctx.annotations.writeIdempotent },
6210
+ handler: async (args) => {
6211
+ ctx.requireProvider();
6212
+ const spec = { move: args.move, ...args.ms !== void 0 ? { ms: args.ms } : {}, ...args.preset !== void 0 ? { preset: args.preset } : {}, ...args.values !== void 0 ? { values: args.values } : {} };
6213
+ return done(await controller.setShotCameraMove(args.shot, args.role, spec));
6214
+ }
6215
+ },
6216
+ {
6217
+ name: "clear_shot_camera_move",
6218
+ title: "Clear a shot's camera move",
6219
+ description: `Removes a shot's camera move for a role (transition: its camera "in"; hold: its camera "during"), keeping its framing; the camera then eases into the shot, or stays still while it holds. Works without a provider. One undo step. Returns { shot, camera (null when the shot has none left), notes }.`,
6220
+ inputSchema: {
6221
+ type: "object",
6222
+ properties: { shot: { type: "string", minLength: 1, description: "A shot id from get_animation." }, role: ROLE },
6223
+ required: ["shot", "role"],
6224
+ additionalProperties: false
6225
+ },
6226
+ annotations: { title: "Clear a shot's camera move", ...ctx.annotations.destructive },
6227
+ handler: async (args) => done(controller.clearShotCameraMove(args.shot, args.role))
6228
+ }
6229
+ ];
6230
+ }
6231
+
5859
6232
  // src/animation-editor/effect-tools.ts
5860
6233
  var info = (e) => ({ id: e.instance, effect: e.effect, ...e.name ? { name: e.name } : {}, ...e.provider ? { provider: e.provider } : {}, role: e.kind === "vector" ? "vector picture" : "motion", enabled: true, values: e.values, targets: e.targets, shots: e.shots });
5861
6234
  function createAnimationEffectsToolProvider(controller, options = {}) {
@@ -5864,11 +6237,11 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
5864
6237
  if (ro) return typeof ro === "string" ? ro : "The animation is read-only.";
5865
6238
  return controller.readOnlyReason();
5866
6239
  };
5867
- const done = (r, target) => {
6240
+ const done2 = (r, target) => {
5868
6241
  if (!r.ok) throw new Error(r.error);
5869
6242
  return { target, effect: info(r.effect), effects: controller.appliedEffects().filter((e) => e.targets.includes(target)).map(info), ...r.notes.length ? { notes: r.notes } : {} };
5870
6243
  };
5871
- return withAnimationPlayback(_chunk5MQOBTNPcjs.createEffectToolProvider.call(void 0, {
6244
+ return withAnimationPlayback(_chunkOPSK22DLcjs.createEffectToolProvider.call(void 0, {
5872
6245
  id: _nullishCoalesce(options.id, () => ( "animation-effects")),
5873
6246
  namespace: options.namespace,
5874
6247
  title: "Animation effects",
@@ -5891,16 +6264,17 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
5891
6264
  },
5892
6265
  apply: async (target, effect, args) => {
5893
6266
  if (args.index !== void 0 || args.opacity !== void 0 || args.enabled === false) throw new Error("index, opacity and enabled do not apply to motion effects; the effect becomes commands in a new shot.");
5894
- return done(await controller.applyMotionEffect(effect, [target], { values: args.values }), target);
6267
+ return done2(await controller.applyMotionEffect(effect, [target], { values: args.values }), target);
5895
6268
  },
5896
6269
  update: async (target, instance, changes) => {
5897
6270
  const extra = ["enabled", "opacity", "index"].filter((k) => changes[k] !== void 0);
5898
6271
  if (extra.length) throw new Error(`A motion effect only takes values; ${extra.join(", ")} do not apply (move or delete its commands with edit_animation).`);
5899
- return done(await controller.updateMotionEffect(instance, _nullishCoalesce(changes.values, () => ( {}))), target);
6272
+ return done2(await controller.updateMotionEffect(instance, _nullishCoalesce(changes.values, () => ( {}))), target);
5900
6273
  },
5901
- remove: async (target, instance) => done(controller.removeMotionEffect(instance), target),
6274
+ remove: async (target, instance) => done2(controller.removeMotionEffect(instance), target),
5902
6275
  subscribe: (notify) => controller.subscribe(() => notify()),
5903
6276
  extraTools: (ctx) => [
6277
+ ...animationCameraMoveTools(controller, ctx),
5904
6278
  {
5905
6279
  name: "add_vector_effect",
5906
6280
  title: "Add a vector effect",
@@ -6126,4 +6500,16 @@ function createAnimationEditorDocument(controller) {
6126
6500
 
6127
6501
 
6128
6502
 
6129
- 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_FIELDS = MOTION_COMMAND_FIELDS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_COMMAND_TYPE_SCHEMAS = MOTION_COMMAND_TYPE_SCHEMAS; 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 = _chunkEBDZWIOPcjs.MOTION_ISSUE_CODES; exports.MOTION_MAX_TAKE_MS = MOTION_MAX_TAKE_MS; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_RECORD_GESTURE_MODES = MOTION_RECORD_GESTURE_MODES; 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.createAnimationEditorDocument = createAnimationEditorDocument; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createAnimationEffectsToolProvider = createAnimationEffectsToolProvider; 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.motionArtworkSvg = motionArtworkSvg; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionCascade = motionCascade; exports.motionClientToDocument = motionClientToDocument; 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.motionCommandsFromEffect = motionCommandsFromEffect; 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 = _chunkEBDZWIOPcjs.motionIssue; exports.motionIssueKey = _chunkEBDZWIOPcjs.motionIssueKey; exports.motionIssueLine = _chunkEBDZWIOPcjs.motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionNodePose = motionNodePose; exports.motionPartsFromVectorEffect = motionPartsFromVectorEffect; 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.motionSceneEffects = motionSceneEffects; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTakeProblems = motionTakeProblems; exports.motionTakeShot = motionTakeShot; exports.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = _chunkEBDZWIOPcjs.namedWithSuggestion; exports.nextMotionEffectInstance = nextMotionEffectInstance; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.planAnimationToolPlayback = planAnimationToolPlayback; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.simplifyTimedSamples = simplifyTimedSamples; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = _chunkEBDZWIOPcjs.suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withAnimationPlayback = withAnimationPlayback; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox; exports.withoutMotionEffect = withoutMotionEffect;
6503
+
6504
+
6505
+
6506
+
6507
+
6508
+
6509
+
6510
+
6511
+
6512
+
6513
+
6514
+
6515
+ 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_FIELDS = MOTION_COMMAND_FIELDS; exports.MOTION_COMMAND_SCHEMA = MOTION_COMMAND_SCHEMA; exports.MOTION_COMMAND_TYPES = MOTION_COMMAND_TYPES; exports.MOTION_COMMAND_TYPE_SCHEMAS = MOTION_COMMAND_TYPE_SCHEMAS; 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 = _chunkERJA5CGTcjs.MOTION_ISSUE_CODES; exports.MOTION_MAX_TAKE_MS = MOTION_MAX_TAKE_MS; exports.MOTION_MIN_CHANGE_MS = MOTION_MIN_CHANGE_MS; exports.MOTION_RECORD_GESTURE_MODES = MOTION_RECORD_GESTURE_MODES; 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.animationCameraMoveTools = animationCameraMoveTools; exports.applyMotionControlValues = applyMotionControlValues; exports.applyMotionDrivers = applyMotionDrivers; exports.applyMotionEdits = applyMotionEdits; exports.checkMotionCameraMoves = checkMotionCameraMoves; exports.checkMotionScene = checkMotionScene; exports.clipsShapeProblems = clipsShapeProblems; exports.commandShapeProblems = commandShapeProblems; exports.compileMotionScene = compileMotionScene; exports.createAnimationEditorDocument = createAnimationEditorDocument; exports.createAnimationEditorToolProvider = createAnimationEditorToolProvider; exports.createAnimationEffectsToolProvider = createAnimationEffectsToolProvider; exports.createMotionScene = createMotionScene; exports.defaultMotionCommand = defaultMotionCommand; exports.describeMotionElements = describeMotionElements; exports.describeMotionShots = describeMotionShots; exports.driversShapeProblems = driversShapeProblems; exports.duplicateMotionCommandEdit = duplicateMotionCommandEdit; exports.effectsPlayCamera = effectsPlayCamera; 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.motionArtworkSvg = motionArtworkSvg; exports.motionBeatAt = motionBeatAt; exports.motionBeatTime = motionBeatTime; exports.motionBlurTimes = motionBlurTimes; exports.motionCameraBox = motionCameraBox; exports.motionCameraFramed = motionCameraFramed; exports.motionCameraMoves = motionCameraMoves; exports.motionCameraStage = motionCameraStage; exports.motionCameraTransform = motionCameraTransform; exports.motionCameraViewAt = motionCameraViewAt; exports.motionCameraWindows = motionCameraWindows; exports.motionCascade = motionCascade; exports.motionClientToDocument = motionClientToDocument; 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.motionCommandsFromEffect = motionCommandsFromEffect; 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 = _chunkERJA5CGTcjs.motionIssue; exports.motionIssueKey = _chunkERJA5CGTcjs.motionIssueKey; exports.motionIssueLine = _chunkERJA5CGTcjs.motionIssueLine; exports.motionMovingIds = motionMovingIds; exports.motionNodeAtElement = motionNodeAtElement; exports.motionNodeClips = motionNodeClips; exports.motionNodeOffset = motionNodeOffset; exports.motionNodePose = motionNodePose; exports.motionPartsFromVectorEffect = motionPartsFromVectorEffect; 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.motionSceneEffects = motionSceneEffects; exports.motionSceneShapeProblems = motionSceneShapeProblems; exports.motionSceneToJson = motionSceneToJson; exports.motionShotAt = motionShotAt; exports.motionShotCameraMove = motionShotCameraMove; exports.motionShotCueTime = motionShotCueTime; exports.motionShotTimeScale = motionShotTimeScale; exports.motionStageSvg = motionStageSvg; exports.motionTakeProblems = motionTakeProblems; exports.motionTakeShot = motionTakeShot; exports.motionTextLayout = motionTextLayout; exports.motionTextUnits = motionTextUnits; exports.motionTrackKey = motionTrackKey; exports.namedWithSuggestion = _chunkERJA5CGTcjs.namedWithSuggestion; exports.nextMotionEffectInstance = nextMotionEffectInstance; exports.parseMotionDrivers = parseMotionDrivers; exports.parseMotionFieldInput = parseMotionFieldInput; exports.parseMotionNarration = parseMotionNarration; exports.parseMotionScene = parseMotionScene; exports.planAnimationToolPlayback = planAnimationToolPlayback; exports.resolveMotionCamera = resolveMotionCamera; exports.resolveMotionEditRefs = resolveMotionEditRefs; exports.segmentProgress = segmentProgress; exports.segmentValue = segmentValue; exports.shotShapeProblems = shotShapeProblems; exports.simplifyTimedSamples = simplifyTimedSamples; exports.smoothMotionLegs = smoothMotionLegs; exports.smoothMotionTimes = smoothMotionTimes; exports.suggestName = _chunkERJA5CGTcjs.suggestName; exports.toFlairEffectDocument = toFlairEffectDocument; exports.toFlairSvgMotion = toFlairSvgMotion; exports.toFlairVectorEffect = toFlairVectorEffect; exports.toLottie = toLottie; exports.trackValue = trackValue; exports.withAnimationPlayback = withAnimationPlayback; exports.withCameraViewEffects = withCameraViewEffects; exports.withMotionLayers = withMotionLayers; exports.withViewBox = withViewBox; exports.withoutMotionEffect = withoutMotionEffect;