@pixerate/editor 0.229.0 → 0.231.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 (73) 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-5T3H7CGG.cjs} +21 -11
  28. package/dist/{chunk-K5GXW5TR.cjs → chunk-C73U5UI3.cjs} +14 -14
  29. package/dist/{chunk-LPTFDCJO.js → chunk-CSM5T6SE.js} +14 -4
  30. package/dist/{chunk-EBDZWIOP.cjs → chunk-ERJA5CGT.cjs} +5 -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/camera-tools.d.cts +10 -0
  48. package/dist/video-editor/camera-tools.d.ts +10 -0
  49. package/dist/video-editor/camera.d.cts +47 -0
  50. package/dist/video-editor/camera.d.ts +47 -0
  51. package/dist/video-editor/check.d.cts +1 -1
  52. package/dist/video-editor/check.d.ts +1 -1
  53. package/dist/video-editor/controller.d.cts +37 -2
  54. package/dist/video-editor/controller.d.ts +37 -2
  55. package/dist/video-editor/effect-tools.d.cts +2 -1
  56. package/dist/video-editor/effect-tools.d.ts +2 -1
  57. package/dist/video-editor/index.cjs +705 -390
  58. package/dist/video-editor/index.d.cts +2 -0
  59. package/dist/video-editor/index.d.ts +2 -0
  60. package/dist/video-editor/index.js +334 -19
  61. package/dist/video-editor/keyframes.d.cts +10 -3
  62. package/dist/video-editor/keyframes.d.ts +10 -3
  63. package/dist/video-editor/parse.d.cts +5 -3
  64. package/dist/video-editor/parse.d.ts +5 -3
  65. package/dist/video-editor/tools.d.cts +18 -0
  66. package/dist/video-editor/tools.d.ts +18 -0
  67. package/dist/video-editor/types.d.cts +37 -1
  68. package/dist/video-editor/types.d.ts +37 -1
  69. package/package.json +1 -1
  70. package/skills/pixerate-animation-editor/SKILL.md +28 -1
  71. package/skills/pixerate-animation-motion-graphics/SKILL.md +3 -0
  72. package/skills/pixerate-video-editor/SKILL.md +16 -1
  73. package/skills/pixerate-video-montage/SKILL.md +2 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7;
2
2
 
3
- var _chunkK5GXW5TRcjs = require('../chunk-K5GXW5TR.cjs');
3
+ var _chunkC73U5UI3cjs = require('../chunk-C73U5UI3.cjs');
4
4
 
5
5
 
6
6
 
@@ -148,16 +148,22 @@ var _chunkK5GXW5TRcjs = require('../chunk-K5GXW5TR.cjs');
148
148
 
149
149
 
150
150
 
151
- var _chunkIGPEBXUDcjs = require('../chunk-IGPEBXUD.cjs');
151
+
152
+ var _chunk5T3H7CGGcjs = require('../chunk-5T3H7CGG.cjs');
152
153
  require('../chunk-PY4GWSE2.cjs');
153
154
 
154
155
 
155
- var _chunkEBDZWIOPcjs = require('../chunk-EBDZWIOP.cjs');
156
+ var _chunkERJA5CGTcjs = require('../chunk-ERJA5CGT.cjs');
157
+
158
+
159
+
160
+
161
+
156
162
 
157
163
 
158
164
 
159
165
 
160
- var _chunk5MQOBTNPcjs = require('../chunk-5MQOBTNP.cjs');
166
+ var _chunkOPSK22DLcjs = require('../chunk-OPSK22DL.cjs');
161
167
  require('../chunk-WOFXZ3XU.cjs');
162
168
 
163
169
 
@@ -216,7 +222,7 @@ function parseVideoEase(v, path) {
216
222
  if (v[0] < 0 || v[0] > 1 || v[2] < 0 || v[2] > 1) fail(path, "must have x1 and x2 between 0 and 1");
217
223
  return [v[0], v[1], v[2], v[3]];
218
224
  }
219
- return oneOf(v, _chunkIGPEBXUDcjs.VIDEO_EASE_NAMES, path);
225
+ return oneOf(v, _chunk5T3H7CGGcjs.VIDEO_EASE_NAMES, path);
220
226
  }
221
227
  function parseVideoKeyframes(v, path, { min, max } = {}) {
222
228
  if (!isObject(v)) return fail(path, "must be a number or keyframes { keys: [{ t, v, ease }] }");
@@ -228,7 +234,10 @@ function parseVideoKeyframes(v, path, { min, max } = {}) {
228
234
  for (const key of Object.keys(k)) if (!["t", "v", "ease"].includes(key)) fail(`${at}.${key}`, "is not a key field (t, v, ease)");
229
235
  return compact({ t: num(k.t, `${at}.t`), v: num(k.v, `${at}.v`, { min, max }), ease: parseVideoEase(k.ease, `${at}.ease`) });
230
236
  });
231
- for (let i = 1; i < keys.length; i++) if (!(keys[i].t > keys[i - 1].t)) fail(`${path}.keys[${i}].t`, `must be later than the key before (${keys[i - 1].t} ms); keys go in time order, one per time`);
237
+ for (let i = 1; i < keys.length; i++) {
238
+ if (keys[i].t < keys[i - 1].t) fail(`${path}.keys[${i}].t`, `must not be before the key before (${keys[i - 1].t} ms); keys go in time order`);
239
+ if (i >= 2 && keys[i].t === keys[i - 2].t) fail(`${path}.keys[${i}].t`, `is the third key at ${keys[i].t} ms; a time takes one key, or two for a jump (the value just before, then the value after)`);
240
+ }
232
241
  return { keys };
233
242
  }
234
243
  function parseVideoAnimatable(v, path, range = {}) {
@@ -253,8 +262,9 @@ function parseVideoTimeRemap(v, speed, path) {
253
262
  const remap = parseVideoAnimatable(v, path, { optional: true, min: 0 });
254
263
  if (typeof remap === "number" || remap === void 0) return fail(path, "must be keyframes { keys: [{ t, v, ease }] } (v: ms of source after the in point)");
255
264
  if (speed !== void 0 && speed !== 1) fail(path, 'cannot be used with a speed; a ramp sets the speed itself (remove "speed")');
265
+ for (let i = 1; i < remap.keys.length; i++) if (remap.keys[i].t === remap.keys[i - 1].t) fail(`${path}.keys[${i}].t`, `must be later than the key before (${remap.keys[i - 1].t} ms); a speed ramp has one key per time`);
256
266
  try {
257
- _chunkIGPEBXUDcjs.checkVideoTimeRemap.call(void 0, remap, path);
267
+ _chunk5T3H7CGGcjs.checkVideoTimeRemap.call(void 0, remap, path);
258
268
  } catch (e) {
259
269
  throw new Error(e.message.replace(/\.?$/, "."));
260
270
  }
@@ -264,17 +274,17 @@ function parseVideoClipAnimation(v, path) {
264
274
  if (v === void 0) return void 0;
265
275
  if (!isObject(v)) return fail(path, "must be an object { effect, duration }");
266
276
  return compact({
267
- effect: oneOf(v.effect, _chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
277
+ effect: oneOf(v.effect, _chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
268
278
  duration: num(v.duration, `${path}.duration`, { optional: true, positive: true })
269
279
  });
270
280
  }
271
281
  function parseVideoGrade(v, path) {
272
282
  if (v === void 0) return void 0;
273
283
  if (!isObject(v)) return fail(path, "must be an object such as { exposure, contrast, saturation }");
274
- const known = /* @__PURE__ */ new Set([..._chunkIGPEBXUDcjs.VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
284
+ const known = /* @__PURE__ */ new Set([..._chunk5T3H7CGGcjs.VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
275
285
  const unknown = Object.keys(v).find((k) => !known.has(k));
276
286
  if (unknown) fail(`${path}.${unknown}`, `is not a grade setting; use ${[...known].join(", ")}`);
277
- return compact({ ...Object.fromEntries(_chunkIGPEBXUDcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, num(v[c.key], `${path}.${c.key}`, { optional: true, min: c.min, max: c.max })])), lut: parseVideoGradeLut(v.lut, `${path}.lut`) });
287
+ return compact({ ...Object.fromEntries(_chunk5T3H7CGGcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, num(v[c.key], `${path}.${c.key}`, { optional: true, min: c.min, max: c.max })])), lut: parseVideoGradeLut(v.lut, `${path}.lut`) });
278
288
  }
279
289
  function parseVideoGradeLut(v, path) {
280
290
  if (v === void 0) return void 0;
@@ -289,7 +299,7 @@ function parseVideoClipMask(v, path) {
289
299
  if (!isObject(v)) return fail(path, 'must be an object such as { shape: "ellipse", x: 0.5, y: 0.5, width: 0.4, height: 0.6, feather: 20 }');
290
300
  const unknown = Object.keys(v).find((k) => !MASK_KEYS.includes(k));
291
301
  if (unknown) fail(`${path}.${unknown}`, `is not a mask setting; use ${MASK_KEYS.join(", ")}`);
292
- const shape = oneOf(v.shape, _chunkIGPEBXUDcjs.VIDEO_MASK_SHAPES, `${path}.shape`, false);
302
+ const shape = oneOf(v.shape, _chunk5T3H7CGGcjs.VIDEO_MASK_SHAPES, `${path}.shape`, false);
293
303
  let points;
294
304
  if (v.points !== void 0) {
295
305
  if (shape !== "polygon") fail(`${path}.points`, "is only for polygon masks");
@@ -315,15 +325,15 @@ function parseVideoClipMask(v, path) {
315
325
  function parseVideoTransition(v, path) {
316
326
  if (v === void 0) return void 0;
317
327
  if (!isObject(v)) return fail(path, "must be an object { type, duration }");
318
- const type = oneOf(v.type, _chunkIGPEBXUDcjs.VIDEO_TRANSITION_TYPES, `${path}.type`, false);
328
+ const type = oneOf(v.type, _chunk5T3H7CGGcjs.VIDEO_TRANSITION_TYPES, `${path}.type`, false);
319
329
  if (type === "effect" && v.effect === void 0) fail(`${path}.effect`, 'is required for an effect transition: { effect: "<effect id>", values }');
320
330
  if (type !== "effect" && v.effect !== void 0) fail(`${path}.effect`, 'is only for transitions of type "effect"');
321
331
  return compact({
322
332
  type,
323
333
  duration: num(v.duration, `${path}.duration`, { positive: true }),
324
334
  color: str(v.color, `${path}.color`, true),
325
- direction: oneOf(v.direction, _chunkIGPEBXUDcjs.VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
326
- audioCurve: oneOf(v.audioCurve, _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES, `${path}.audioCurve`),
335
+ direction: oneOf(v.direction, _chunk5T3H7CGGcjs.VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
336
+ audioCurve: oneOf(v.audioCurve, _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES, `${path}.audioCurve`),
327
337
  effect: v.effect === void 0 ? void 0 : parseVideoEffectRef(v.effect, `${path}.effect`, false)
328
338
  });
329
339
  }
@@ -414,9 +424,45 @@ function parseVideoAssetProxies(v, path) {
414
424
  }
415
425
  return out.length ? out : void 0;
416
426
  }
427
+ var CAMERA_KEYS = ["in", "during", "from", "framing", "base"];
428
+ function parseCameraFraming(v, path) {
429
+ if (v === void 0) return void 0;
430
+ if (!isObject(v)) return fail(path, "must be an object { zoom, x, y }");
431
+ const unknown = Object.keys(v).find((k) => !["zoom", "x", "y"].includes(k));
432
+ if (unknown) fail(`${path}.${unknown}`, "is not a framing field (zoom, x, y)");
433
+ return compact({ zoom: num(v.zoom, `${path}.zoom`, { optional: true, positive: true }), x: num(v.x, `${path}.x`, { optional: true }), y: num(v.y, `${path}.y`, { optional: true }) });
434
+ }
435
+ function parseCameraMove(v, path, hold) {
436
+ if (v === void 0) return void 0;
437
+ if (typeof v === "string" && v) return v;
438
+ if (!isObject(v) || typeof v.move !== "string" || !v.move) return fail(path, "must be a camera move's id, or { move, ms, preset, values }");
439
+ const unknown = Object.keys(v).find((k) => !["move", "ms", "preset", "values"].includes(k));
440
+ if (unknown) fail(`${path}.${unknown}`, "is not a camera move field (move, ms, preset, values)");
441
+ if (hold && v.ms !== void 0) fail(`${path}.ms`, "is not for a hold move, which plays across the rest of the clip");
442
+ if (v.values !== void 0 && !isObject(v.values)) fail(`${path}.values`, "must be an object of the move's control values");
443
+ return compact({ move: v.move, ms: num(v.ms, `${path}.ms`, { optional: true, min: 0 }), preset: str(v.preset, `${path}.preset`, true), values: v.values });
444
+ }
445
+ function parseVideoClipCamera(v, path) {
446
+ if (v === void 0) return void 0;
447
+ if (!isObject(v)) return fail(path, "must be an object { in, during, from, framing, base }");
448
+ const unknown = Object.keys(v).find((k) => !CAMERA_KEYS.includes(k));
449
+ if (unknown) fail(`${path}.${unknown}`, `is not a camera field; use ${CAMERA_KEYS.join(", ")}`);
450
+ if (v.in === void 0 && v.during === void 0) fail(path, 'names no move: give "in", "during" or both, or remove the camera');
451
+ if (!isObject(v.base)) fail(`${path}.base`, "must be the clip's transform before the moves were baked, { x, y, scale, rotation } as numbers");
452
+ const base = v.base;
453
+ const extra = Object.keys(base).find((k) => !["x", "y", "scale", "rotation"].includes(k));
454
+ if (extra) fail(`${path}.base.${extra}`, "is not a transform field (x, y, scale, rotation)");
455
+ return compact({
456
+ in: parseCameraMove(v.in, `${path}.in`, false),
457
+ during: parseCameraMove(v.during, `${path}.during`, true),
458
+ from: parseCameraFraming(v.from, `${path}.from`),
459
+ framing: parseCameraFraming(v.framing, `${path}.framing`),
460
+ base: compact({ x: num(base.x, `${path}.base.x`, { optional: true }), y: num(base.y, `${path}.base.y`, { optional: true }), scale: num(base.scale, `${path}.base.scale`, { optional: true, min: 0 }), rotation: num(base.rotation, `${path}.base.rotation`, { optional: true }) })
461
+ });
462
+ }
417
463
  function parseVideoClip(v, path = "clip") {
418
464
  if (!isObject(v)) return fail(path, "must be an object");
419
- const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), _chunkIGPEBXUDcjs.VIDEO_CLIP_TYPES, `${path}.type`, false);
465
+ const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), _chunk5T3H7CGGcjs.VIDEO_CLIP_TYPES, `${path}.type`, false);
420
466
  const base = {
421
467
  id: str(v.id, `${path}.id`),
422
468
  name: str(v.name, `${path}.name`, true),
@@ -424,8 +470,8 @@ function parseVideoClip(v, path = "clip") {
424
470
  duration: num(v.duration, `${path}.duration`, { positive: true }),
425
471
  opacity: parseVideoAnimatable(v.opacity, `${path}.opacity`, { optional: true, min: 0, max: 1 }),
426
472
  transform: parseVideoTransform(v.transform, `${path}.transform`),
427
- fit: oneOf(v.fit, _chunkIGPEBXUDcjs.VIDEO_FITS, `${path}.fit`),
428
- blend: oneOf(v.blend, _chunkIGPEBXUDcjs.VIDEO_BLEND_MODES, `${path}.blend`),
473
+ fit: oneOf(v.fit, _chunk5T3H7CGGcjs.VIDEO_FITS, `${path}.fit`),
474
+ blend: oneOf(v.blend, _chunk5T3H7CGGcjs.VIDEO_BLEND_MODES, `${path}.blend`),
429
475
  grade: parseVideoGrade(v.grade, `${path}.grade`),
430
476
  animateIn: parseVideoClipAnimation(v.animateIn, `${path}.animateIn`),
431
477
  animateOut: parseVideoClipAnimation(v.animateOut, `${path}.animateOut`),
@@ -433,7 +479,8 @@ function parseVideoClip(v, path = "clip") {
433
479
  fadeOut: num(v.fadeOut, `${path}.fadeOut`, { optional: true, min: 0 }),
434
480
  transition: parseVideoTransition(v.transition, `${path}.transition`),
435
481
  effects: parseVideoClipEffects(v.effects, `${path}.effects`),
436
- mask: parseVideoClipMask(v.mask, `${path}.mask`)
482
+ mask: parseVideoClipMask(v.mask, `${path}.mask`),
483
+ camera: parseVideoClipCamera(v.camera, `${path}.camera`)
437
484
  };
438
485
  if (type === "media")
439
486
  return compact({
@@ -445,8 +492,8 @@ function parseVideoClip(v, path = "clip") {
445
492
  volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
446
493
  muted: bool(v.muted, `${path}.muted`),
447
494
  timeRemap: parseVideoTimeRemap(v.timeRemap, v.speed, `${path}.timeRemap`),
448
- fadeInCurve: oneOf(v.fadeInCurve, _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
449
- fadeOutCurve: oneOf(v.fadeOutCurve, _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
495
+ fadeInCurve: oneOf(v.fadeInCurve, _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
496
+ fadeOutCurve: oneOf(v.fadeOutCurve, _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
450
497
  });
451
498
  if (type === "sequence") {
452
499
  for (const key of ["speed", "timeRemap"])
@@ -458,8 +505,8 @@ function parseVideoClip(v, path = "clip") {
458
505
  in: num(v.in, `${path}.in`, { optional: true, min: 0 }),
459
506
  volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
460
507
  muted: bool(v.muted, `${path}.muted`),
461
- fadeInCurve: oneOf(v.fadeInCurve, _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
462
- fadeOutCurve: oneOf(v.fadeOutCurve, _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
508
+ fadeInCurve: oneOf(v.fadeInCurve, _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
509
+ fadeOutCurve: oneOf(v.fadeOutCurve, _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
463
510
  });
464
511
  }
465
512
  if (type === "text")
@@ -474,7 +521,7 @@ function parseVideoClip(v, path = "clip") {
474
521
  background: str(v.background, `${path}.background`, true)
475
522
  });
476
523
  if (type === "adjustment") {
477
- const scope = oneOf(v.scope, _chunkIGPEBXUDcjs.VIDEO_ADJUSTMENT_SCOPES, `${path}.scope`);
524
+ const scope = oneOf(v.scope, _chunk5T3H7CGGcjs.VIDEO_ADJUSTMENT_SCOPES, `${path}.scope`);
478
525
  const targetTrack = str(v.targetTrack, `${path}.targetTrack`, true);
479
526
  if (scope === "track" && !targetTrack) fail(`${path}.targetTrack`, 'is required when scope is "track": the id of the track whose pictures the adjustment changes');
480
527
  if (targetTrack !== void 0 && scope !== "track") fail(`${path}.targetTrack`, 'is only for scope "track"');
@@ -577,9 +624,9 @@ function createVideoProject(options = {}) {
577
624
  // src/video-editor/check.ts
578
625
  function videoClipKeyframes(clip) {
579
626
  const out = [
580
- { property: "opacity", keys: _chunkIGPEBXUDcjs.videoKeysOf.call(void 0, clip.opacity) },
581
- { property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? _chunkIGPEBXUDcjs.videoKeysOf.call(void 0, clip.volume) : [] },
582
- ..._chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: _chunkIGPEBXUDcjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _2 => _2.transform, 'optionalAccess', _3 => _3[p]])) }))
627
+ { property: "opacity", keys: _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, clip.opacity) },
628
+ { property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, clip.volume) : [] },
629
+ ..._chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _2 => _2.transform, 'optionalAccess', _3 => _3[p]])) }))
583
630
  ];
584
631
  return out.filter((o) => o.keys.length);
585
632
  }
@@ -597,6 +644,7 @@ var VIDEO_ISSUE_CODES = [
597
644
  "animations-too-long",
598
645
  "animation-keyed",
599
646
  "keyframes-outside-clip",
647
+ "camera-stale",
600
648
  "unknown-duration",
601
649
  "unused-asset",
602
650
  "unused-sequence",
@@ -607,8 +655,8 @@ var VIDEO_ISSUE_CODES = [
607
655
  var videoIssueKey = (i) => [i.code, _nullishCoalesce(i.sequence, () => ( "")), _nullishCoalesce(i.track, () => ( "")), _nullishCoalesce(i.clip, () => ( "")), _nullishCoalesce(i.asset, () => ( "")), _nullishCoalesce(i.marker, () => ( ""))].join("|");
608
656
  function checkVideoProject(project) {
609
657
  const issues = [];
610
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, project);
611
- const sequences = _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, project);
658
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, project);
659
+ const sequences = _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, project);
612
660
  const used = /* @__PURE__ */ new Set();
613
661
  const usedSequences = /* @__PURE__ */ new Set();
614
662
  const cycles = /* @__PURE__ */ new Map();
@@ -616,7 +664,7 @@ function checkVideoProject(project) {
616
664
  if ((asset.kind === "video" || asset.kind === "audio") && asset.duration === void 0)
617
665
  issues.push({ code: "unknown-duration", severity: "warning", asset: asset.id, message: `Asset "${asset.id}" has no duration, so clips of it cannot be checked against its length; set "duration" in ms.` });
618
666
  const checkTrack = (track, sequence) => {
619
- const clips = _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track);
667
+ const clips = _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track);
620
668
  const where = sequence ? ` in sequence "${sequence}"` : "";
621
669
  for (let i = 0; i < clips.length; i++) {
622
670
  const clip = clips[i];
@@ -626,13 +674,13 @@ function checkVideoProject(project) {
626
674
  const seq = sequences.get(clip.sequence);
627
675
  if (!seq) issues.push({ code: "missing-sequence", severity: "error", ...at, message: `Compound clip "${clip.id}" plays sequence "${clip.sequence}", which is not in the project; add the sequence or delete the clip.` });
628
676
  else {
629
- if (!cycles.has(seq.id)) cycles.set(seq.id, _chunkIGPEBXUDcjs.findVideoSequenceCycle.call(void 0, project, seq.id));
677
+ if (!cycles.has(seq.id)) cycles.set(seq.id, _chunk5T3H7CGGcjs.findVideoSequenceCycle.call(void 0, project, seq.id));
630
678
  const cycle = cycles.get(seq.id);
631
679
  if (cycle) issues.push({ code: "sequence-cycle", severity: "error", ...at, message: `Compound clip "${clip.id}" plays sequence "${seq.id}", which contains itself (${cycle.join(" \u2192 ")}), so it is left out of the picture and sound; remove the compound clip that closes the loop.` });
632
- const length = _chunkIGPEBXUDcjs.videoSequenceDuration.call(void 0, seq);
633
- const range = _chunkIGPEBXUDcjs.videoClipSourceRange.call(void 0, clip);
634
- if (range.out > length + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
635
- issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, range.out)} of sequence "${seq.id}", which is only ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, length)} long; shorten the clip or move its in point.` });
680
+ const length = _chunk5T3H7CGGcjs.videoSequenceDuration.call(void 0, seq);
681
+ const range = _chunk5T3H7CGGcjs.videoClipSourceRange.call(void 0, clip);
682
+ if (range.out > length + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
683
+ issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, range.out)} of sequence "${seq.id}", which is only ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, length)} long; shorten the clip or move its in point.` });
636
684
  }
637
685
  } else if (clip.type === "media") {
638
686
  used.add(clip.asset);
@@ -641,30 +689,41 @@ function checkVideoProject(project) {
641
689
  else {
642
690
  if (track.kind === "audio" && asset.kind === "image") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is an image on audio track "${track.id}"; move it to a video track.` });
643
691
  if (track.kind === "video" && asset.kind === "audio") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is audio on video track "${track.id}"; move it to an audio track.` });
644
- const range = _chunkIGPEBXUDcjs.videoClipSourceRange.call(void 0, clip);
645
- if (asset.duration !== void 0 && range.out > asset.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
646
- issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, range.out)} of "${asset.id}", which is only ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, asset.duration)} long; shorten the clip or move its in point.` });
692
+ const range = _chunk5T3H7CGGcjs.videoClipSourceRange.call(void 0, clip);
693
+ if (asset.duration !== void 0 && range.out > asset.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
694
+ issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, range.out)} of "${asset.id}", which is only ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, asset.duration)} long; shorten the clip or move its in point.` });
647
695
  }
648
696
  } else if (track.kind === "audio") issues.push({ code: "wrong-track", severity: "error", ...at, message: `Clip "${clip.id}" is a ${clip.type} clip on audio track "${track.id}"; move it to a video track.` });
649
697
  if (clip.type === "adjustment" && (_nullishCoalesce(clip.scope, () => ( "underneath"))) === "track" && !(sequence ? _nullishCoalesce(_optionalChain([sequences, 'access', _4 => _4.get, 'call', _5 => _5(sequence), 'optionalAccess', _6 => _6.tracks]), () => ( [])) : project.tracks).some((t) => t.id === clip.targetTrack))
650
698
  issues.push({ code: "missing-target-track", severity: "warning", ...at, message: `Adjustment clip "${clip.id}" changes track "${clip.targetTrack}", which is not ${sequence ? `in sequence "${sequence}"` : "in the project"}, so it changes nothing; set its targetTrack to a track beside it or change its scope.` });
651
699
  const next = clips[i + 1];
652
- if (next && next.start < _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip) - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
653
- issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, next.start)}; move one of them.` });
654
- if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
700
+ if (next && next.start < _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip) - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
701
+ issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, next.start)}; move one of them.` });
702
+ if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
655
703
  issues.push({ code: "fades-too-long", severity: "warning", ...at, message: `Clip "${clip.id}"'s fades (${_nullishCoalesce(clip.fadeIn, () => ( 0))} + ${_nullishCoalesce(clip.fadeOut, () => ( 0))} ms) are longer than the clip (${clip.duration} ms); shorten them.` });
656
- const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( _chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( _chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0);
657
- if (anim > clip.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
704
+ const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( _chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( _chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0);
705
+ if (anim > clip.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
658
706
  issues.push({ code: "animations-too-long", severity: "warning", ...at, message: `Clip "${clip.id}"'s entrance and exit (${anim} ms together) are longer than the clip (${clip.duration} ms), so both are shortened; give them shorter durations.` });
659
707
  for (const which of ["animateIn", "animateOut"]) {
660
708
  const a = clip[which];
661
709
  if (!a) continue;
662
- const keyed = _chunkIGPEBXUDcjs.videoClipAnimationProperties.call(void 0, a).filter((p) => _chunkIGPEBXUDcjs.videoKeysOf.call(void 0, p === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _7 => _7.transform, 'optionalAccess', _8 => _8[p]])).length);
710
+ const keyed = _chunk5T3H7CGGcjs.videoClipAnimationProperties.call(void 0, a).filter((p) => _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, p === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _7 => _7.transform, 'optionalAccess', _8 => _8[p]])).length);
663
711
  if (keyed.length)
664
712
  issues.push({ code: "animation-keyed", severity: "note", ...at, message: `Clip "${clip.id}"'s ${a.effect} ${which === "animateIn" ? "entrance" : "exit"} leaves ${keyed.join(", ")} alone, because the clip keys ${keyed.length > 1 ? "them" : "it"} itself; remove those keyframes or the animation.` });
665
713
  }
714
+ if (clip.camera) {
715
+ const last = Math.max(0, ..._chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.flatMap((p) => _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _9 => _9.transform, 'optionalAccess', _10 => _10[p]])).map((k) => k.t)));
716
+ const frame = 1e3 / (project.fps || 30);
717
+ if (last > 0 && Math.abs(last - clip.duration) > frame + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
718
+ issues.push({
719
+ code: "camera-stale",
720
+ severity: "warning",
721
+ ...at,
722
+ message: `Clip "${clip.id}"'s camera moves were baked for ${Math.round(last)} ms but the clip is ${Math.round(clip.duration)} ms, so ${last < clip.duration ? "the camera stops early" : "the end of the move is cut off"}; set the move again (set_clip_camera_move) to re-bake it.`
723
+ });
724
+ }
666
725
  for (const { property, keys } of videoClipKeyframes(clip)) {
667
- const outside = keys.filter((k) => k.t < -_chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON || k.t > clip.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON);
726
+ const outside = keys.filter((k) => k.t < -_chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON || k.t > clip.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON);
668
727
  if (outside.length)
669
728
  issues.push({
670
729
  code: "keyframes-outside-clip",
@@ -675,20 +734,20 @@ function checkVideoProject(project) {
675
734
  }
676
735
  if (clip.transition) {
677
736
  const d = clip.transition.duration;
678
- const before = _chunkIGPEBXUDcjs.videoClipBefore.call(void 0, track, clip);
737
+ const before = _chunk5T3H7CGGcjs.videoClipBefore.call(void 0, track, clip);
679
738
  if (!before) {
680
739
  issues.push({ code: "transition-without-cut", severity: "warning", ...at, message: `Clip "${clip.id}" has a transition but no clip ends where it starts on track "${track.id}", so it plays as nothing; butt a clip up against it or remove the transition.` });
681
740
  continue;
682
741
  }
683
- if (d > clip.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON || d > before.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) {
742
+ if (d > clip.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON || d > before.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) {
684
743
  issues.push({ code: "transition-too-long", severity: "error", ...at, message: `The ${d} ms transition into "${clip.id}" is longer than "${clip.id}" (${clip.duration} ms) or "${before.id}" (${before.duration} ms); make it at most ${Math.min(clip.duration, before.duration)} ms.` });
685
744
  continue;
686
745
  }
687
746
  if (clip.transition.type === "dip") continue;
688
- const outgoing = _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, before, assets, sequences).after;
689
- const incoming = _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, clip, assets, sequences).before;
747
+ const outgoing = _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, before, assets, sequences).after;
748
+ const incoming = _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, clip, assets, sequences).before;
690
749
  const half = d / 2;
691
- if (outgoing < half - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON || incoming < half - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) {
750
+ if (outgoing < half - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON || incoming < half - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) {
692
751
  const fits = 2 * Math.min(outgoing, incoming);
693
752
  issues.push({
694
753
  code: "transition-handles",
@@ -705,9 +764,9 @@ function checkVideoProject(project) {
705
764
  for (const sequence of _nullishCoalesce(project.sequences, () => ( [])))
706
765
  if (!usedSequences.has(sequence.id)) issues.push({ code: "unused-sequence", severity: "note", sequence: sequence.id, message: `Sequence "${sequence.id}" is not played by any compound clip.` });
707
766
  for (const asset of project.assets) if (!used.has(asset.id)) issues.push({ code: "unused-asset", severity: "note", asset: asset.id, message: `Asset "${asset.id}" is not used by any clip.` });
708
- const end = _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, project);
767
+ const end = _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, project);
709
768
  for (const marker of _nullishCoalesce(project.markers, () => ( [])))
710
- if (marker.time > end + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, marker.time)} is past the end (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, end)}).` });
769
+ if (marker.time > end + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, marker.time)} is past the end (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, end)}).` });
711
770
  if (!project.tracks.some((t) => t.clips.length)) issues.push({ code: "empty", severity: "note", message: "The project has no clips yet; add assets and then clips." });
712
771
  const rank = { error: 0, warning: 1, note: 2 };
713
772
  return issues.sort((a, b) => rank[a.severity] - rank[b.severity]);
@@ -761,7 +820,7 @@ function mergeSpans(spans) {
761
820
  const out = [];
762
821
  for (const [from, to] of [...spans].sort((a, b) => a[0] - b[0])) {
763
822
  const last = out[out.length - 1];
764
- if (last && from <= last[1] + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
823
+ if (last && from <= last[1] + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
765
824
  else out.push([from, to]);
766
825
  }
767
826
  return out;
@@ -775,16 +834,16 @@ function clipAnimatables(clip) {
775
834
  // A speed ramp is keys in clip time too, so trims and splits keep it on the same frames of source.
776
835
  { get: () => c.timeRemap, set: (v) => c.timeRemap = v }
777
836
  ];
778
- for (const p of _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access', _9 => _9.transform, 'optionalAccess', _10 => _10[p]]), set: (v) => c.transform && (c.transform[p] = v) });
837
+ for (const p of _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access', _11 => _11.transform, 'optionalAccess', _12 => _12[p]]), set: (v) => c.transform && (c.transform[p] = v) });
779
838
  return out;
780
839
  }
781
840
  function retimeClipKeys(clip, fn) {
782
841
  for (const a of clipAnimatables(clip)) {
783
842
  const v = a.get();
784
- if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, v)) a.set(fn(v));
843
+ if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, v)) a.set(fn(v));
785
844
  }
786
845
  }
787
- var OPTIONAL_CLIP_FIELDS = ["name", "effects", "mask", "scope", "targetTrack", "values", "provider", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "transition", "in", "speed", "timeRemap", "volume", "muted", "color", "fontSize", "fontFamily", "fontWeight", "background"];
846
+ var OPTIONAL_CLIP_FIELDS = ["name", "effects", "mask", "camera", "scope", "targetTrack", "values", "provider", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "transition", "in", "speed", "timeRemap", "volume", "muted", "color", "fontSize", "fontFamily", "fontWeight", "background"];
788
847
  var TIME_FIELDS = { slip_clip: ["delta"], roll_edit: ["delta"], slide_clip: ["delta"], lift_range: ["from", "to"], extract_range: ["from", "to"], split_at: ["at"] };
789
848
  var Editor = (_class = class {
790
849
  constructor(p) {;_class.prototype.__init.call(this);
@@ -794,16 +853,16 @@ var Editor = (_class = class {
794
853
  __init() {this.outcomes = []}
795
854
  track(id) {
796
855
  const t = this.p.tracks.find((x) => x.id === id);
797
- if (!t) refuse(`There is no track ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, this.p.tracks.map((x) => x.id))}; the tracks are ${this.p.tracks.map((x) => `"${x.id}" (${x.kind})`).join(", ") || "none"}.`);
856
+ if (!t) refuse(`There is no track ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, this.p.tracks.map((x) => x.id))}; the tracks are ${this.p.tracks.map((x) => `"${x.id}" (${x.kind})`).join(", ") || "none"}.`);
798
857
  return t;
799
858
  }
800
859
  clip(id) {
801
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, this.p, id);
802
- const nested = at ? null : _chunkIGPEBXUDcjs.findVideoSequenceClip.call(void 0, this.p, id);
860
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.p, id);
861
+ const nested = at ? null : _chunk5T3H7CGGcjs.findVideoSequenceClip.call(void 0, this.p, id);
803
862
  if (nested) refuse(`Clip "${id}" is inside sequence "${nested.sequence.id}", and clips inside sequences cannot be edited yet; edit the compound clip that plays the sequence instead (list_video_sequences shows which).`);
804
863
  if (!at) {
805
864
  const ids = this.p.tracks.flatMap((t) => t.clips.map((c) => c.id));
806
- refuse(`There is no clip ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, ids)}${ids.length ? "" : "; the project has no clips yet"}.`);
865
+ refuse(`There is no clip ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, ids)}${ids.length ? "" : "; the project has no clips yet"}.`);
807
866
  }
808
867
  return at;
809
868
  }
@@ -812,43 +871,43 @@ var Editor = (_class = class {
812
871
  }
813
872
  asset(id) {
814
873
  const a = this.p.assets.find((x) => x.id === id);
815
- if (!a) refuse(`There is no asset ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, id, this.p.assets.map((x) => x.id))}; add it first (the assets are ${this.p.assets.map((x) => `"${x.id}"`).join(", ") || "none yet"}).`);
874
+ if (!a) refuse(`There is no asset ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, id, this.p.assets.map((x) => x.id))}; add it first (the assets are ${this.p.assets.map((x) => `"${x.id}"`).join(", ") || "none yet"}).`);
816
875
  return a;
817
876
  }
818
877
  fits(track, start, duration, ignore, what) {
819
- const hit = _chunkIGPEBXUDcjs.videoOverlap.call(void 0, track, start, start + duration, ignore);
878
+ const hit = _chunk5T3H7CGGcjs.videoOverlap.call(void 0, track, start, start + duration, ignore);
820
879
  if (hit) {
821
- const free = _chunkIGPEBXUDcjs.nextFreeVideoSlot.call(void 0, track, start, duration, ignore);
822
- refuse(`${what} at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, start)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, start + duration)} would overlap clip "${hit.id}" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, hit))}) on track "${track.id}"; the next free place is ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
880
+ const free = _chunk5T3H7CGGcjs.nextFreeVideoSlot.call(void 0, track, start, duration, ignore);
881
+ refuse(`${what} at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, start)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, start + duration)} would overlap clip "${hit.id}" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, hit))}) on track "${track.id}"; the next free place is ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
823
882
  }
824
883
  }
825
884
  /** An adjustment clip's target track must exist. */
826
885
  adjustmentTarget(clip) {
827
886
  if (clip.type !== "adjustment" || clip.targetTrack === void 0) return;
828
- const ids = _chunkIGPEBXUDcjs.allVideoTracks.call(void 0, this.p).map(({ track }) => track.id);
829
- if (!ids.includes(clip.targetTrack)) refuse(`Adjustment clip "${clip.id}" targets track ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, clip.targetTrack, ids)}, which does not exist; the tracks are ${ids.map((t) => `"${t}"`).join(", ")}.`);
887
+ const ids = _chunk5T3H7CGGcjs.allVideoTracks.call(void 0, this.p).map(({ track }) => track.id);
888
+ if (!ids.includes(clip.targetTrack)) refuse(`Adjustment clip "${clip.id}" targets track ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, clip.targetTrack, ids)}, which does not exist; the tracks are ${ids.map((t) => `"${t}"`).join(", ")}.`);
830
889
  }
831
890
  kindFits(track, clip) {
832
891
  const asset = clip.type === "media" ? this.asset(clip.asset) : null;
833
892
  if (clip.type === "sequence") {
834
893
  const ids = (_nullishCoalesce(this.p.sequences, () => ( []))).map((q) => q.id);
835
- if (typeof clip.sequence !== "string" || !ids.includes(clip.sequence)) refuse(`There is no sequence ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, String(clip.sequence), ids)}; the sequences are ${ids.map((q) => `"${q}"`).join(", ") || "none"}.`);
894
+ if (typeof clip.sequence !== "string" || !ids.includes(clip.sequence)) refuse(`There is no sequence ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, String(clip.sequence), ids)}; the sequences are ${ids.map((q) => `"${q}"`).join(", ") || "none"}.`);
836
895
  return;
837
896
  }
838
897
  if (track.kind === "audio" && (clip.type !== "media" || asset.kind === "image")) refuse(`Track "${track.id}" is an audio track; ${clip.type === "media" ? "images" : `${clip.type} clips`} go on a video track.`);
839
- if (track.kind === "video" && _optionalChain([asset, 'optionalAccess', _11 => _11.kind]) === "audio") refuse(`Track "${track.id}" is a video track; audio asset "${asset.id}" goes on an audio track.`);
898
+ if (track.kind === "video" && _optionalChain([asset, 'optionalAccess', _13 => _13.kind]) === "audio") refuse(`Track "${track.id}" is a video track; audio asset "${asset.id}" goes on an audio track.`);
840
899
  }
841
900
  /** Moves every clip on `track` starting at or after `from` by `delta`. */
842
901
  shift(track, from, delta, except = /* @__PURE__ */ new Set()) {
843
902
  if (!delta) return;
844
- for (const c of track.clips) if (!except.has(c.id) && c.start >= from - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
903
+ for (const c of track.clips) if (!except.has(c.id) && c.start >= from - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
845
904
  track.clips.sort((a, b) => a.start - b.start);
846
905
  }
847
906
  get frame() {
848
907
  return 1e3 / this.p.fps;
849
908
  }
850
909
  ids() {
851
- return _chunkIGPEBXUDcjs.allVideoClipIds.call(void 0, this.p);
910
+ return _chunk5T3H7CGGcjs.allVideoClipIds.call(void 0, this.p);
852
911
  }
853
912
  /**
854
913
  * The tracks a ripple on `sources` moves, top to bottom: the sources, and every unlocked
@@ -856,8 +915,8 @@ var Editor = (_class = class {
856
915
  */
857
916
  rippleTracks(sources) {
858
917
  const set = new Set(sources);
859
- if ([...set].some(_chunkIGPEBXUDcjs.videoTrackSyncLocked)) {
860
- for (const t of this.p.tracks) if (_chunkIGPEBXUDcjs.videoTrackSyncLocked.call(void 0, t) && !t.locked) set.add(t);
918
+ if ([...set].some(_chunk5T3H7CGGcjs.videoTrackSyncLocked)) {
919
+ for (const t of this.p.tracks) if (_chunk5T3H7CGGcjs.videoTrackSyncLocked.call(void 0, t) && !t.locked) set.add(t);
861
920
  }
862
921
  return this.p.tracks.filter((t) => set.has(t));
863
922
  }
@@ -874,7 +933,7 @@ var Editor = (_class = class {
874
933
  return open;
875
934
  }
876
935
  range(from, to) {
877
- if (!(to - from > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)) refuse(`"to" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, to)}) must be after "from" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, from)}).`);
936
+ if (!(to - from > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)) refuse(`"to" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, to)}) must be after "from" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, from)}).`);
878
937
  }
879
938
  /** Moves a media or compound clip's in point by `delta` of timeline time (stills, titles and colours have none). */
880
939
  moveIn(clip, delta) {
@@ -883,18 +942,18 @@ var Editor = (_class = class {
883
942
  if (clip.in < 1e-9) delete clip.in;
884
943
  return;
885
944
  }
886
- if (clip.type !== "media" || _optionalChain([_chunkIGPEBXUDcjs.videoAssetMap.call(void 0, this.p), 'access', _12 => _12.get, 'call', _13 => _13(clip.asset), 'optionalAccess', _14 => _14.kind]) === "image") return;
887
- clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * _chunkIGPEBXUDcjs.videoClipSpeed.call(void 0, clip));
945
+ if (clip.type !== "media" || _optionalChain([_chunk5T3H7CGGcjs.videoAssetMap.call(void 0, this.p), 'access', _14 => _14.get, 'call', _15 => _15(clip.asset), 'optionalAccess', _16 => _16.kind]) === "image") return;
946
+ clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * _chunk5T3H7CGGcjs.videoClipSpeed.call(void 0, clip));
888
947
  if (clip.in < 1e-9) delete clip.in;
889
948
  }
890
949
  /** Moves a clip's head `delta` later in time (start, in point and keys); the caller sets start and duration. */
891
950
  trimHead(clip, delta) {
892
951
  if (!isRamped(clip)) this.moveIn(clip, delta);
893
- retimeClipKeys(clip, (v) => _chunkIGPEBXUDcjs.retimeVideoAnimatable.call(void 0, v, -delta));
952
+ retimeClipKeys(clip, (v) => _chunk5T3H7CGGcjs.retimeVideoAnimatable.call(void 0, v, -delta));
894
953
  }
895
954
  /** Cuts `clip` at `at` (inside it): the left part keeps the id, the right part is returned. */
896
955
  cut(track, clip, at, id) {
897
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip);
956
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip);
898
957
  const right = { ...structuredClone(clip), id: _nullishCoalesce(id, () => ( freshId(`${clip.id}-`, this.ids()))), start: at, duration: end - at };
899
958
  delete right.transition;
900
959
  delete right.fadeIn;
@@ -902,9 +961,9 @@ var Editor = (_class = class {
902
961
  delete right.animateIn;
903
962
  const leftValues = clipAnimatables(clip);
904
963
  clipAnimatables(right).forEach((r, i) => {
905
- const [l, rr] = _chunkIGPEBXUDcjs.splitVideoAnimatable.call(void 0, leftValues[i].get(), at - clip.start);
906
- if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, l)) leftValues[i].set(l);
907
- if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, rr)) r.set(rr);
964
+ const [l, rr] = _chunk5T3H7CGGcjs.splitVideoAnimatable.call(void 0, leftValues[i].get(), at - clip.start);
965
+ if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, l)) leftValues[i].set(l);
966
+ if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, rr)) r.set(rr);
908
967
  });
909
968
  if (!isRamped(right)) this.moveIn(right, at - clip.start);
910
969
  clip.duration = at - clip.start;
@@ -918,7 +977,7 @@ var Editor = (_class = class {
918
977
  /** Cuts every clip on `tracks` that runs across `at`; returns the new right-hand parts. */
919
978
  cutAcross(tracks, at) {
920
979
  const made = [];
921
- for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON && _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) > at + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
980
+ for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON && _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) > at + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
922
981
  return made;
923
982
  }
924
983
  /**
@@ -936,10 +995,10 @@ var Editor = (_class = class {
936
995
  */
937
996
  close(tracks, from, to) {
938
997
  for (const t of tracks) {
939
- const hit = _chunkIGPEBXUDcjs.videoOverlap.call(void 0, t, from, to);
998
+ const hit = _chunk5T3H7CGGcjs.videoOverlap.call(void 0, t, from, to);
940
999
  if (hit)
941
1000
  refuse(
942
- `Rippling out ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, from)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, hit))}) is in that stretch. Extract the range across "${t.id}" too (extract_range with its id in "tracks"), turn its sync lock off (update_track with syncLocked false) or lock it, or lift instead of rippling.`
1001
+ `Rippling out ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, from)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, hit))}) is in that stretch. Extract the range across "${t.id}" too (extract_range with its id in "tracks"), turn its sync lock off (update_track with syncLocked false) or lock it, or lift instead of rippling.`
943
1002
  );
944
1003
  }
945
1004
  for (const t of tracks) this.shift(t, to, from - to);
@@ -951,10 +1010,10 @@ var Editor = (_class = class {
951
1010
  clear(track, from, to, report) {
952
1011
  for (const c of [...track.clips]) {
953
1012
  const start = c.start;
954
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c);
955
- if (end <= from + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON || start >= to - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) continue;
956
- const coversHead = start >= from - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON;
957
- const coversTail = end <= to + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON;
1013
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c);
1014
+ if (end <= from + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON || start >= to - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) continue;
1015
+ const coversHead = start >= from - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON;
1016
+ const coversTail = end <= to + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON;
958
1017
  if (coversHead && coversTail) {
959
1018
  track.clips = track.clips.filter((x) => x !== c);
960
1019
  report.removed.push(c.id);
@@ -977,8 +1036,8 @@ var Editor = (_class = class {
977
1036
  /** Clamps a slip, roll or slide to `[lo, hi]`, refusing when it cannot move that way at all. */
978
1037
  clamp(delta, lo, hi, why) {
979
1038
  const applied = Math.min(Math.max(delta, Math.min(0, lo)), Math.max(0, hi));
980
- if (Math.abs(delta) > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON && Math.abs(applied) <= _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(why());
981
- return Math.abs(applied) <= _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON ? 0 : applied;
1039
+ if (Math.abs(delta) > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON && Math.abs(applied) <= _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(why());
1040
+ return Math.abs(applied) <= _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON ? 0 : applied;
982
1041
  }
983
1042
  /** Places a clip on a track by `mode`, returning what it cut, trimmed, removed and rippled. */
984
1043
  place(track, clip, mode, outcome) {
@@ -988,14 +1047,14 @@ var Editor = (_class = class {
988
1047
  outcome.rippled = tracks.map((t) => t.id);
989
1048
  } else if (mode === "overwrite") {
990
1049
  const report = { removed: [], trimmed: [], created: [] };
991
- this.clear(track, clip.start, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip), report);
1050
+ this.clear(track, clip.start, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip), report);
992
1051
  Object.assign(outcome, report);
993
1052
  } else this.fits(track, clip.start, clip.duration, /* @__PURE__ */ new Set([clip.id]), `Clip "${clip.id}"`);
994
1053
  track.clips.push(clip);
995
1054
  track.clips.sort((a, b) => a.start - b.start);
996
1055
  }
997
1056
  placement(mode, ripple) {
998
- if (mode !== void 0 && !_chunkIGPEBXUDcjs.VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${_chunkIGPEBXUDcjs.VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
1057
+ if (mode !== void 0 && !_chunk5T3H7CGGcjs.VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${_chunk5T3H7CGGcjs.VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
999
1058
  if (ripple && mode !== void 0 && mode !== "insert") refuse(`"ripple" means mode "insert", so it cannot go with mode "${mode}"; pass one or the other.`);
1000
1059
  return _nullishCoalesce(mode, () => ( (ripple ? "insert" : "refuse")));
1001
1060
  }
@@ -1032,7 +1091,7 @@ var Editor = (_class = class {
1032
1091
  }
1033
1092
  case "remove_asset": {
1034
1093
  const asset = this.asset(e.asset);
1035
- const users = _chunkIGPEBXUDcjs.allVideoTracks.call(void 0, this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
1094
+ const users = _chunk5T3H7CGGcjs.allVideoTracks.call(void 0, this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
1036
1095
  if (users.length) refuse(`Asset "${asset.id}" is used by clip${users.length > 1 ? "s" : ""} ${users.map((u) => `"${u}"`).join(", ")}; delete ${users.length > 1 ? "them" : "it"} first.`);
1037
1096
  this.p.assets = this.p.assets.filter((a) => a !== asset);
1038
1097
  return this.outcomes.push({ op: e.op, asset: asset.id });
@@ -1085,12 +1144,12 @@ var Editor = (_class = class {
1085
1144
  else draft.duration = (asset.duration - (_nullishCoalesce(draft.in, () => ( 0)))) / (_nullishCoalesce(draft.speed, () => ( 1)));
1086
1145
  if (!(draft.duration > 0)) refuse(`"in" (${draft.in} ms) is at or past the end of "${asset.id}" (${asset.duration} ms).`);
1087
1146
  } else if (draft.type === "sequence") {
1088
- const length = _chunkIGPEBXUDcjs.videoSequenceDuration.call(void 0, _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
1147
+ const length = _chunk5T3H7CGGcjs.videoSequenceDuration.call(void 0, _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
1089
1148
  if (!(length > 0)) refuse(`"in" (${_nullishCoalesce(draft.in, () => ( 0))} ms) is at or past the end of sequence "${draft.sequence}".`);
1090
1149
  draft.duration = length;
1091
1150
  } else draft.duration = VIDEO_DEFAULT_TITLE_DURATION;
1092
1151
  }
1093
- const end = _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track).reduce((m, c) => Math.max(m, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c)), 0);
1152
+ const end = _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track).reduce((m, c) => Math.max(m, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c)), 0);
1094
1153
  draft.start ??= end;
1095
1154
  const clip = parseVideoClip(draft, "clip");
1096
1155
  this.adjustmentTarget(clip);
@@ -1116,20 +1175,20 @@ var Editor = (_class = class {
1116
1175
  case "trim_clip": {
1117
1176
  const { track, clip } = this.clip(e.clip);
1118
1177
  this.unlocked(track);
1119
- const speed = _chunkIGPEBXUDcjs.videoClipSpeed.call(void 0, clip);
1120
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip);
1178
+ const speed = _chunk5T3H7CGGcjs.videoClipSpeed.call(void 0, clip);
1179
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip);
1121
1180
  const minimum = 1e3 / this.p.fps;
1122
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, this.p);
1181
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, this.p);
1123
1182
  if (e.edge === "start") {
1124
1183
  const delta = e.to - clip.start;
1125
- if (clip.duration - delta < minimum - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, end)}.`);
1184
+ if (clip.duration - delta < minimum - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, end)}.`);
1126
1185
  if (clip.type === "media" && !isRamped(clip) || clip.type === "sequence") {
1127
1186
  const sourceIn = (_nullishCoalesce(clip.in, () => ( 0))) + delta * speed;
1128
- if (sourceIn < -_chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" starts ${Math.round((_nullishCoalesce(clip.in, () => ( 0))) / speed)} ms into its source, so its start can move at most that far earlier (to ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
1187
+ if (sourceIn < -_chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" starts ${Math.round((_nullishCoalesce(clip.in, () => ( 0))) / speed)} ms into its source, so its start can move at most that far earlier (to ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
1129
1188
  clip.in = Math.max(0, sourceIn);
1130
1189
  if (clip.in === 0) delete clip.in;
1131
1190
  }
1132
- retimeClipKeys(clip, (v) => _chunkIGPEBXUDcjs.retimeVideoAnimatable.call(void 0, v, -delta));
1191
+ retimeClipKeys(clip, (v) => _chunk5T3H7CGGcjs.retimeVideoAnimatable.call(void 0, v, -delta));
1133
1192
  if (e.ripple) {
1134
1193
  const tracks = this.rippleTracks([track]);
1135
1194
  if (delta > 0) {
@@ -1150,17 +1209,17 @@ var Editor = (_class = class {
1150
1209
  }
1151
1210
  } else {
1152
1211
  const duration = e.to - clip.start;
1153
- if (duration < minimum - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, clip.start)}.`);
1212
+ if (duration < minimum - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, clip.start)}.`);
1154
1213
  if (clip.type === "media" && !isRamped(clip)) {
1155
1214
  const asset = assets.get(clip.asset);
1156
1215
  const out = (_nullishCoalesce(clip.in, () => ( 0))) + duration * speed;
1157
- if (_optionalChain([asset, 'optionalAccess', _15 => _15.duration]) !== void 0 && out > asset.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
1158
- refuse(`"${clip.id}" can end at most at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
1216
+ if (_optionalChain([asset, 'optionalAccess', _17 => _17.duration]) !== void 0 && out > asset.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
1217
+ refuse(`"${clip.id}" can end at most at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
1159
1218
  }
1160
1219
  if (clip.type === "sequence") {
1161
- const seq = _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p).get(clip.sequence);
1162
- const length = seq ? _chunkIGPEBXUDcjs.videoSequenceDuration.call(void 0, seq) : Infinity;
1163
- if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
1220
+ const seq = _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p).get(clip.sequence);
1221
+ const length = seq ? _chunk5T3H7CGGcjs.videoSequenceDuration.call(void 0, seq) : Infinity;
1222
+ if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
1164
1223
  }
1165
1224
  if (e.ripple) {
1166
1225
  const tracks = this.rippleTracks([track]);
@@ -1182,9 +1241,9 @@ var Editor = (_class = class {
1182
1241
  case "split_clip": {
1183
1242
  const { track, clip } = this.clip(e.clip);
1184
1243
  this.unlocked(track);
1185
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip);
1244
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip);
1186
1245
  const minimum = 1e3 / this.p.fps;
1187
- if (e.at < clip.start + minimum - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON || e.at > end - minimum + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, e.at)} is not inside "${clip.id}" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, clip.start)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, end)}), at least a frame from either end.`);
1246
+ if (e.at < clip.start + minimum - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON || e.at > end - minimum + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, e.at)} is not inside "${clip.id}" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, clip.start)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, end)}), at least a frame from either end.`);
1188
1247
  if (e.id !== void 0 && this.ids().includes(e.id)) refuse(`There is already a clip "${e.id}".`);
1189
1248
  const right = this.cut(track, clip, e.at, e.id);
1190
1249
  return this.outcomes.push({ op: e.op, clips: [clip.id, right.id], clip: right.id, track: track.id });
@@ -1195,12 +1254,12 @@ var Editor = (_class = class {
1195
1254
  for (const track of new Set(found.map((f) => f.track))) track.clips = track.clips.filter((c) => !found.some((f) => f.clip === c));
1196
1255
  if (!e.ripple) return this.outcomes.push({ op: e.op, clips: found.map((f) => f.clip.id) });
1197
1256
  const rippled = /* @__PURE__ */ new Set();
1198
- const groups = [...new Set(found.map((f) => f.track))].filter((t) => !_chunkIGPEBXUDcjs.videoTrackSyncLocked.call(void 0, t)).map((t) => [t]);
1199
- if (found.some((f) => _chunkIGPEBXUDcjs.videoTrackSyncLocked.call(void 0, f.track))) groups.push(found.filter((f) => _chunkIGPEBXUDcjs.videoTrackSyncLocked.call(void 0, f.track)).map((f) => f.track));
1257
+ const groups = [...new Set(found.map((f) => f.track))].filter((t) => !_chunk5T3H7CGGcjs.videoTrackSyncLocked.call(void 0, t)).map((t) => [t]);
1258
+ if (found.some((f) => _chunk5T3H7CGGcjs.videoTrackSyncLocked.call(void 0, f.track))) groups.push(found.filter((f) => _chunk5T3H7CGGcjs.videoTrackSyncLocked.call(void 0, f.track)).map((f) => f.track));
1200
1259
  for (const sources of groups) {
1201
1260
  const tracks = this.rippleTracks(sources);
1202
1261
  tracks.forEach((t) => rippled.add(t));
1203
- const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, f.clip)]));
1262
+ const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, f.clip)]));
1204
1263
  for (const [from, to] of spans.reverse()) this.close(tracks, from, to);
1205
1264
  }
1206
1265
  return this.outcomes.push({ op: e.op, clips: found.map((f) => f.clip.id), rippled: this.p.tracks.filter((t) => rippled.has(t)).map((t) => t.id) });
@@ -1216,15 +1275,15 @@ var Editor = (_class = class {
1216
1275
  if ("timeRemap" in set) refuse("Set a speed ramp with set_time_remap, which checks it against the media and moves later clips if asked.");
1217
1276
  let stretch = 1;
1218
1277
  if (at.clip.type === "media" && !("duration" in set)) {
1219
- const was = _chunkIGPEBXUDcjs.videoClipSpeed.call(void 0, at.clip);
1220
- const now = "speed" in set ? set.speed : _optionalChain([e, 'access', _16 => _16.remove, 'optionalAccess', _17 => _17.includes, 'call', _18 => _18("speed")]) ? 1 : was;
1278
+ const was = _chunk5T3H7CGGcjs.videoClipSpeed.call(void 0, at.clip);
1279
+ const now = "speed" in set ? set.speed : _optionalChain([e, 'access', _18 => _18.remove, 'optionalAccess', _19 => _19.includes, 'call', _20 => _20("speed")]) ? 1 : was;
1221
1280
  if (now !== was) {
1222
1281
  set.duration = at.clip.duration * was / now;
1223
1282
  stretch = was / now;
1224
1283
  }
1225
1284
  }
1226
1285
  const next = { ...structuredClone(at.clip), ...set };
1227
- if (stretch !== 1) retimeClipKeys(next, (v) => _chunkIGPEBXUDcjs.retimeVideoAnimatable.call(void 0, v, 0, stretch));
1286
+ if (stretch !== 1) retimeClipKeys(next, (v) => _chunk5T3H7CGGcjs.retimeVideoAnimatable.call(void 0, v, 0, stretch));
1228
1287
  for (const k of _nullishCoalesce(e.remove, () => ( []))) delete next[k];
1229
1288
  const clip = parseVideoClip(next, "set");
1230
1289
  this.adjustmentTarget(clip);
@@ -1238,17 +1297,17 @@ var Editor = (_class = class {
1238
1297
  const { track, clip } = this.clip(e.clip);
1239
1298
  this.unlocked(track);
1240
1299
  if (clip.type === "sequence") refuse(`Clip "${clip.id}" is a compound clip, which plays its sequence at normal speed; ramp the clips inside the sequence instead.`);
1241
- if (clip.type !== "media") refuse(`Clip "${clip.id}" is a ${_chunkIGPEBXUDcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to ramp; only video and audio clips change speed.`);
1300
+ if (clip.type !== "media") refuse(`Clip "${clip.id}" is a ${_chunk5T3H7CGGcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to ramp; only video and audio clips change speed.`);
1242
1301
  const asset = this.asset(clip.asset);
1243
1302
  if (asset.kind === "image") refuse(`Clip "${clip.id}" is a still ("${asset.id}"), so it has no motion to ramp.`);
1244
1303
  const media = clip;
1245
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, media);
1304
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, media);
1246
1305
  const duration = _nullishCoalesce(e.duration, () => ( media.duration));
1247
- if (!(duration >= 1e3 / this.p.fps - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
1306
+ if (!(duration >= 1e3 / this.p.fps - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
1248
1307
  if (e.keys === null) {
1249
1308
  if (!media.timeRemap) refuse(`Clip "${clip.id}" has no speed ramp to remove.`);
1250
1309
  const from = (_nullishCoalesce(media.in, () => ( 0))) + media.timeRemap.keys[0].v;
1251
- if (asset.duration !== void 0 && from + duration > asset.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
1310
+ if (asset.duration !== void 0 && from + duration > asset.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
1252
1311
  refuse(`At normal speed from ${Math.round(from)} ms, "${clip.id}" would run past the end of "${asset.id}" (${asset.duration} ms); give a duration of at most ${Math.floor(asset.duration - from)} ms.`);
1253
1312
  delete media.timeRemap;
1254
1313
  media.in = from;
@@ -1256,17 +1315,17 @@ var Editor = (_class = class {
1256
1315
  } else {
1257
1316
  if (!Array.isArray(e.keys) || !e.keys.length) refuse('"keys" must be a list of at least one { t, v, ease } (or null to remove the ramp).');
1258
1317
  const remap = parseVideoTimeRemap({ keys: e.keys }, void 0, "keys");
1259
- remap.keys = _chunkIGPEBXUDcjs.sortVideoKeys.call(void 0, remap.keys);
1260
- _chunkIGPEBXUDcjs.checkVideoTimeRemap.call(void 0, remap, "keys");
1261
- const span = _chunkIGPEBXUDcjs.videoTimeRemapSpan.call(void 0, remap);
1262
- if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON)
1318
+ remap.keys = _chunk5T3H7CGGcjs.sortVideoKeys.call(void 0, remap.keys, { jumps: false });
1319
+ _chunk5T3H7CGGcjs.checkVideoTimeRemap.call(void 0, remap, "keys");
1320
+ const span = _chunk5T3H7CGGcjs.videoTimeRemapSpan.call(void 0, remap);
1321
+ if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON)
1263
1322
  refuse(`The ramp plays ${Math.round(span.to)} ms of source from the in point (${_nullishCoalesce(media.in, () => ( 0))} ms), past the end of "${asset.id}" (${asset.duration} ms); it can use at most ${Math.floor(asset.duration - (_nullishCoalesce(media.in, () => ( 0))))} ms.`);
1264
1323
  media.timeRemap = remap;
1265
1324
  delete media.speed;
1266
1325
  }
1267
1326
  const newEnd = media.start + duration;
1268
1327
  const outcome = { op: e.op, clip: clip.id, track: track.id };
1269
- if (Math.abs(newEnd - end) > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) {
1328
+ if (Math.abs(newEnd - end) > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) {
1270
1329
  if (e.ripple) {
1271
1330
  const tracks = this.rippleTracks([track]);
1272
1331
  if (newEnd < end) {
@@ -1295,11 +1354,11 @@ var Editor = (_class = class {
1295
1354
  case "slip_clip": {
1296
1355
  const { track, clip } = this.clip(e.clip);
1297
1356
  this.unlocked(track);
1298
- if (clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${_chunkIGPEBXUDcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to slip; only video, audio and compound clips slip.`);
1357
+ if (clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${_chunk5T3H7CGGcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to slip; only video, audio and compound clips slip.`);
1299
1358
  const source = clip.type === "sequence" ? `sequence "${clip.sequence}"` : `"${this.asset(clip.asset).id}"`;
1300
1359
  if (clip.type === "media" && this.asset(clip.asset).kind === "image") refuse(`Clip "${clip.id}" is a still ("${clip.asset}"), so it has no source to slip; only video and audio clips slip.`);
1301
- const handles = _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, clip, _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, this.p), _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p));
1302
- const { lead, tail } = _chunkIGPEBXUDcjs.videoClipOverhang.call(void 0, track, clip);
1360
+ const handles = _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, clip, _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, this.p), _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p));
1361
+ const { lead, tail } = _chunk5T3H7CGGcjs.videoClipOverhang.call(void 0, track, clip);
1303
1362
  const delta = this.clamp(
1304
1363
  e.delta,
1305
1364
  lead - handles.before,
@@ -1317,13 +1376,13 @@ var Editor = (_class = class {
1317
1376
  this.unlocked(track);
1318
1377
  const L = left.clip;
1319
1378
  const R = right.clip;
1320
- if (Math.abs(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, L) - R.start) > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) {
1321
- if (Math.abs(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, R) - L.start) <= _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
1322
- refuse(`"${L.id}" ends at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, L))} but "${R.id}" starts at ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
1379
+ if (Math.abs(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, L) - R.start) > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) {
1380
+ if (Math.abs(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, R) - L.start) <= _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
1381
+ refuse(`"${L.id}" ends at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, L))} but "${R.id}" starts at ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
1323
1382
  }
1324
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, this.p);
1325
- const lo = Math.max(-(L.duration - this.frame), -(_chunkIGPEBXUDcjs.videoClipHandles.call(void 0, R, assets, _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkIGPEBXUDcjs.videoClipOverhang.call(void 0, track, R).lead));
1326
- const hi = Math.min(R.duration - this.frame, _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, L, assets, _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkIGPEBXUDcjs.videoClipOverhang.call(void 0, track, L).tail);
1383
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, this.p);
1384
+ const lo = Math.max(-(L.duration - this.frame), -(_chunk5T3H7CGGcjs.videoClipHandles.call(void 0, R, assets, _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p)).before - _chunk5T3H7CGGcjs.videoClipOverhang.call(void 0, track, R).lead));
1385
+ const hi = Math.min(R.duration - this.frame, _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, L, assets, _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p)).after - _chunk5T3H7CGGcjs.videoClipOverhang.call(void 0, track, L).tail);
1327
1386
  const delta = this.clamp(
1328
1387
  e.delta,
1329
1388
  lo,
@@ -1339,18 +1398,18 @@ var Editor = (_class = class {
1339
1398
  case "slide_clip": {
1340
1399
  const { track, clip } = this.clip(e.clip);
1341
1400
  this.unlocked(track);
1342
- const before = _chunkIGPEBXUDcjs.videoClipBefore.call(void 0, track, clip);
1343
- const after = _chunkIGPEBXUDcjs.videoClipAfter.call(void 0, track, clip);
1401
+ const before = _chunk5T3H7CGGcjs.videoClipBefore.call(void 0, track, clip);
1402
+ const after = _chunk5T3H7CGGcjs.videoClipAfter.call(void 0, track, clip);
1344
1403
  if (!before && !after) refuse(`"${clip.id}" has no clip right before or after it on track "${track.id}", so there is nothing to slide against; use move_clip.`);
1345
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, this.p);
1346
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip);
1404
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, this.p);
1405
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip);
1347
1406
  const others = track.clips.filter((c) => c !== clip);
1348
1407
  const room = {
1349
- earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) <= clip.start + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c)), 0),
1350
- later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
1408
+ earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) <= clip.start + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c)), 0),
1409
+ later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
1351
1410
  };
1352
- const lo = -Math.min(room.earlier, after ? _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, after, assets, _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkIGPEBXUDcjs.videoClipOverhang.call(void 0, track, after).lead : Infinity);
1353
- const hi = Math.min(room.later, before ? _chunkIGPEBXUDcjs.videoClipHandles.call(void 0, before, assets, _chunkIGPEBXUDcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkIGPEBXUDcjs.videoClipOverhang.call(void 0, track, before).tail : Infinity);
1411
+ const lo = -Math.min(room.earlier, after ? _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, after, assets, _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p)).before - _chunk5T3H7CGGcjs.videoClipOverhang.call(void 0, track, after).lead : Infinity);
1412
+ const hi = Math.min(room.later, before ? _chunk5T3H7CGGcjs.videoClipHandles.call(void 0, before, assets, _chunk5T3H7CGGcjs.videoSequenceMap.call(void 0, this.p)).after - _chunk5T3H7CGGcjs.videoClipOverhang.call(void 0, track, before).tail : Infinity);
1354
1413
  const delta = this.clamp(
1355
1414
  e.delta,
1356
1415
  lo,
@@ -1365,7 +1424,7 @@ var Editor = (_class = class {
1365
1424
  this.trimHead(after, delta);
1366
1425
  }
1367
1426
  track.clips.sort((a, b) => a.start - b.start);
1368
- return this.outcomes.push({ op: e.op, clip: clip.id, clips: [_optionalChain([before, 'optionalAccess', _19 => _19.id]), clip.id, _optionalChain([after, 'optionalAccess', _20 => _20.id])].filter((x) => !!x), track: track.id, delta });
1427
+ return this.outcomes.push({ op: e.op, clip: clip.id, clips: [_optionalChain([before, 'optionalAccess', _21 => _21.id]), clip.id, _optionalChain([after, 'optionalAccess', _22 => _22.id])].filter((x) => !!x), track: track.id, delta });
1369
1428
  }
1370
1429
  case "lift_range":
1371
1430
  case "extract_range": {
@@ -1383,29 +1442,29 @@ var Editor = (_class = class {
1383
1442
  }
1384
1443
  case "split_at": {
1385
1444
  const tracks = this.rangeTracks(e.tracks);
1386
- const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON && _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) > e.at + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON).map((c) => c.id));
1387
- if (!lefts.length) refuse(`No clip runs across ${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, e.at)} on ${e.tracks ? `track${tracks.length > 1 ? "s" : ""} ${tracks.map((t) => `"${t.id}"`).join(", ")}` : "the unlocked tracks"}, so there is nothing to split there.`);
1445
+ const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON && _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) > e.at + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON).map((c) => c.id));
1446
+ if (!lefts.length) refuse(`No clip runs across ${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, e.at)} on ${e.tracks ? `track${tracks.length > 1 ? "s" : ""} ${tracks.map((t) => `"${t.id}"`).join(", ")}` : "the unlocked tracks"}, so there is nothing to split there.`);
1388
1447
  const created = this.cutAcross(tracks, e.at).map((c) => c.id);
1389
1448
  return this.outcomes.push({ op: e.op, clips: lefts, created });
1390
1449
  }
1391
1450
  case "set_keyframes": {
1392
1451
  const { track, clip } = this.clip(e.clip);
1393
1452
  this.unlocked(track);
1394
- if (!_chunkIGPEBXUDcjs.VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${_chunkIGPEBXUDcjs.VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
1453
+ if (!_chunk5T3H7CGGcjs.VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${_chunk5T3H7CGGcjs.VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
1395
1454
  if (e.property === "volume" && clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${clip.type} clip and has no volume; volume keys go on media and compound clips.`);
1396
- const limits = _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_LIMITS[e.property];
1397
- const transform = _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
1455
+ const limits = _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_LIMITS[e.property];
1456
+ const transform = _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
1398
1457
  const c = clip;
1399
- const current = transform ? _optionalChain([c, 'access', _21 => _21.transform, 'optionalAccess', _22 => _22[e.property]]) : c[e.property];
1458
+ const current = transform ? _optionalChain([c, 'access', _23 => _23.transform, 'optionalAccess', _24 => _24[e.property]]) : c[e.property];
1400
1459
  let value;
1401
1460
  if (e.keys === null) {
1402
- const v = _chunkIGPEBXUDcjs.videoValueAt.call(void 0, current, 0, limits.default);
1403
- value = _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, current) ? v === limits.default ? void 0 : v : current;
1461
+ const v = _chunk5T3H7CGGcjs.videoValueAt.call(void 0, current, 0, limits.default);
1462
+ value = _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, current) ? v === limits.default ? void 0 : v : current;
1404
1463
  } else {
1405
1464
  if (!Array.isArray(e.keys) || !e.keys.length) refuse('"keys" must list at least one key { t, v }; pass null to remove the keyframes.');
1406
1465
  let sorted = [];
1407
1466
  try {
1408
- sorted = _chunkIGPEBXUDcjs.sortVideoKeys.call(void 0, e.keys);
1467
+ sorted = _chunk5T3H7CGGcjs.sortVideoKeys.call(void 0, e.keys);
1409
1468
  } catch (error) {
1410
1469
  refuse(error.message);
1411
1470
  }
@@ -1424,12 +1483,12 @@ var Editor = (_class = class {
1424
1483
  this.unlocked(track);
1425
1484
  let at = 0;
1426
1485
  const moved = [];
1427
- for (const clip of _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track)) {
1428
- if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON && clip.start > at + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) {
1486
+ for (const clip of _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track)) {
1487
+ if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON && clip.start > at + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) {
1429
1488
  clip.start = Math.max(at, _nullishCoalesce(e.from, () => ( 0)));
1430
1489
  moved.push(clip.id);
1431
1490
  }
1432
- at = Math.max(at, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip));
1491
+ at = Math.max(at, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip));
1433
1492
  }
1434
1493
  return this.outcomes.push({ op: e.op, track: track.id, clips: moved });
1435
1494
  }
@@ -1444,7 +1503,7 @@ var Editor = (_class = class {
1444
1503
  case "update_marker": {
1445
1504
  const markers = _nullishCoalesce(this.p.markers, () => ( []));
1446
1505
  const i = markers.findIndex((m) => m.id === e.marker);
1447
- if (i < 0) refuse(`There is no marker ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, e.marker, markers.map((m) => m.id))}.`);
1506
+ if (i < 0) refuse(`There is no marker ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, e.marker, markers.map((m) => m.id))}.`);
1448
1507
  if (e.set && "id" in e.set) refuse("A marker's id cannot be changed.");
1449
1508
  const next = { ...markers[i], ...e.set };
1450
1509
  for (const k of _nullishCoalesce(e.remove, () => ( []))) delete next[k];
@@ -1454,7 +1513,7 @@ var Editor = (_class = class {
1454
1513
  }
1455
1514
  case "remove_marker": {
1456
1515
  const markers = _nullishCoalesce(this.p.markers, () => ( []));
1457
- if (!markers.some((m) => m.id === e.marker)) refuse(`There is no marker ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, e.marker, markers.map((m) => m.id))}.`);
1516
+ if (!markers.some((m) => m.id === e.marker)) refuse(`There is no marker ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, e.marker, markers.map((m) => m.id))}.`);
1458
1517
  this.p.markers = markers.filter((m) => m.id !== e.marker);
1459
1518
  if (!this.p.markers.length) delete this.p.markers;
1460
1519
  return this.outcomes.push({ op: e.op, marker: e.marker });
@@ -1464,7 +1523,7 @@ var Editor = (_class = class {
1464
1523
  return this.outcomes.push({ op: e.op });
1465
1524
  }
1466
1525
  default:
1467
- refuse(`Unknown op ${_chunkEBDZWIOPcjs.namedWithSuggestion.call(void 0, String(e.op), VIDEO_EDIT_OPS)}; the ops are ${VIDEO_EDIT_OPS.join(", ")}.`);
1526
+ refuse(`Unknown op ${_chunkERJA5CGTcjs.namedWithSuggestion.call(void 0, String(e.op), VIDEO_EDIT_OPS)}; the ops are ${VIDEO_EDIT_OPS.join(", ")}.`);
1468
1527
  }
1469
1528
  }
1470
1529
  }, _class);
@@ -1478,7 +1537,7 @@ function applyVideoEdits(project, edits) {
1478
1537
  editor.run(edit);
1479
1538
  } catch (error) {
1480
1539
  const message = error.message;
1481
- return { ok: false, error: `${list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _23 => _23.op])}): ` : ""}${message}${/Nothing was changed\.$/.test(message) ? "" : " Nothing was changed."}` };
1540
+ return { ok: false, error: `${list.length > 1 ? `op ${i + 1} (${_optionalChain([edit, 'optionalAccess', _25 => _25.op])}): ` : ""}${message}${/Nothing was changed\.$/.test(message) ? "" : " Nothing was changed."}` };
1482
1541
  }
1483
1542
  }
1484
1543
  let next;
@@ -1559,24 +1618,24 @@ function videoTranscriptTrack(project, track) {
1559
1618
  if (!project.tracks.some((t) => t.id === track)) throw new Error(`There is no track "${track}"; the tracks are ${project.tracks.map((t) => `"${t.id}"`).join(", ")}.`);
1560
1619
  return track;
1561
1620
  }
1562
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, project);
1563
- const transcribed = (t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _24 => _24.get, 'call', _25 => _25(c.asset), 'optionalAccess', _26 => _26.transcript, 'optionalAccess', _27 => _27.length]));
1564
- return _nullishCoalesce(_optionalChain([(_nullishCoalesce(project.tracks.find((t) => t.kind === "audio" && transcribed(t)), () => ( project.tracks.find(transcribed)))), 'optionalAccess', _28 => _28.id]), () => ( null));
1621
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, project);
1622
+ const transcribed = (t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _26 => _26.get, 'call', _27 => _27(c.asset), 'optionalAccess', _28 => _28.transcript, 'optionalAccess', _29 => _29.length]));
1623
+ return _nullishCoalesce(_optionalChain([(_nullishCoalesce(project.tracks.find((t) => t.kind === "audio" && transcribed(t)), () => ( project.tracks.find(transcribed)))), 'optionalAccess', _30 => _30.id]), () => ( null));
1565
1624
  }
1566
1625
  function videoTimelineTranscript(project, options = {}) {
1567
1626
  const id = videoTranscriptTrack(project, options.track);
1568
1627
  if (!id) return [];
1569
1628
  const track = project.tracks.find((t) => t.id === id);
1570
- const assets = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, project);
1629
+ const assets = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, project);
1571
1630
  const out = [];
1572
- for (const clip of _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track)) {
1631
+ for (const clip of _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track)) {
1573
1632
  if (clip.type !== "media") continue;
1574
- const words = _optionalChain([assets, 'access', _29 => _29.get, 'call', _30 => _30(clip.asset), 'optionalAccess', _31 => _31.transcript]);
1575
- if (!_optionalChain([words, 'optionalAccess', _32 => _32.length])) continue;
1576
- const speed = _chunkIGPEBXUDcjs.videoClipSpeed.call(void 0, clip);
1633
+ const words = _optionalChain([assets, 'access', _31 => _31.get, 'call', _32 => _32(clip.asset), 'optionalAccess', _33 => _33.transcript]);
1634
+ if (!_optionalChain([words, 'optionalAccess', _34 => _34.length])) continue;
1635
+ const speed = _chunk5T3H7CGGcjs.videoClipSpeed.call(void 0, clip);
1577
1636
  const from = _nullishCoalesce(clip.in, () => ( 0));
1578
1637
  const to = from + clip.duration * speed;
1579
- const toTimeline = (s) => Math.min(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip), Math.max(clip.start, clip.start + (s - from) / speed));
1638
+ const toTimeline = (s) => Math.min(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip), Math.max(clip.start, clip.start + (s - from) / speed));
1580
1639
  words.forEach((w, index) => {
1581
1640
  const mid = (w.start + w.end) / 2;
1582
1641
  if (mid < from || mid >= to) return;
@@ -1621,19 +1680,19 @@ function findVideoTranscriptPauses(words, options = {}) {
1621
1680
  let to = b.start - keep;
1622
1681
  if (options.fps) {
1623
1682
  const f = 1e3 / options.fps;
1624
- from = _chunkIGPEBXUDcjs.snapToVideoFrame.call(void 0, Math.ceil(from / f - 1e-9) * f, options.fps);
1625
- to = _chunkIGPEBXUDcjs.snapToVideoFrame.call(void 0, Math.floor(to / f + 1e-9) * f, options.fps);
1683
+ from = _chunk5T3H7CGGcjs.snapToVideoFrame.call(void 0, Math.ceil(from / f - 1e-9) * f, options.fps);
1684
+ to = _chunk5T3H7CGGcjs.snapToVideoFrame.call(void 0, Math.floor(to / f + 1e-9) * f, options.fps);
1626
1685
  }
1627
- if (to - from > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
1686
+ if (to - from > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
1628
1687
  }
1629
1688
  return out;
1630
1689
  }
1631
1690
  function mergeVideoRanges(ranges) {
1632
- const sorted = ranges.filter((r) => r.to - r.from > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
1691
+ const sorted = ranges.filter((r) => r.to - r.from > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
1633
1692
  const out = [];
1634
1693
  for (const r of sorted) {
1635
1694
  const last = out[out.length - 1];
1636
- if (last && r.from <= last.to + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
1695
+ if (last && r.from <= last.to + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
1637
1696
  else out.push(r);
1638
1697
  }
1639
1698
  return out;
@@ -1679,7 +1738,7 @@ function findVideoRepetitions(words, options = {}) {
1679
1738
  var VIDEO_DISFLUENCY_KINDS = ["filler", "pause", "repetition"];
1680
1739
  function detectVideoDisfluencies(words, options = {}) {
1681
1740
  const kinds = new Set(_nullishCoalesce(options.kinds, () => ( VIDEO_DISFLUENCY_KINDS)));
1682
- const startIndex = (time) => Math.max(0, words.findIndex((w) => w.start >= time - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON));
1741
+ const startIndex = (time) => Math.max(0, words.findIndex((w) => w.start >= time - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON));
1683
1742
  const out = [];
1684
1743
  if (kinds.has("filler"))
1685
1744
  for (const r of findVideoFillers(words, options.fillers)) {
@@ -1693,13 +1752,13 @@ function detectVideoDisfluencies(words, options = {}) {
1693
1752
  }
1694
1753
  if (kinds.has("pause"))
1695
1754
  for (const r of findVideoTranscriptPauses(words, options.pauses)) {
1696
- const after = words.findIndex((w) => w.start >= r.to - _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON);
1755
+ const after = words.findIndex((w) => w.start >= r.to - _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON);
1697
1756
  out.push({ ...r, kind: "pause", words: [Math.max(0, after - 1), Math.max(0, after)] });
1698
1757
  }
1699
1758
  return out.sort((a, b) => a.from - b.from || a.to - b.to);
1700
1759
  }
1701
1760
  function videoCutsWithMargin(ranges, keep) {
1702
- return ranges.map((r) => ({ ...r, from: r.from + keep, to: r.to - keep })).filter((r) => r.to - r.from > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON);
1761
+ return ranges.map((r) => ({ ...r, from: r.from + keep, to: r.to - keep })).filter((r) => r.to - r.from > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON);
1703
1762
  }
1704
1763
 
1705
1764
  // src/video-editor/mix.ts
@@ -1805,7 +1864,7 @@ function videoDuckingKeys(clip, speech, options = {}) {
1805
1864
  const gap = Math.max(_nullishCoalesce(options.mergeGap, () => ( 600)), attack + release);
1806
1865
  const base = _nullishCoalesce(options.base, () => ( 1));
1807
1866
  const low = Math.round(base * 10 ** (duckDb / 20) * 1e4) / 1e4;
1808
- const end = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip);
1867
+ const end = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip);
1809
1868
  const ranges = [];
1810
1869
  for (const r of mergeVideoRanges(speech)) {
1811
1870
  if (r.to <= clip.start - release || r.from >= end + attack) continue;
@@ -2010,7 +2069,7 @@ function videoClipWaveform(clip, peaks, columns) {
2010
2069
  const step = clip.duration / Math.max(1, n);
2011
2070
  for (let c = 0; c < n; c++) {
2012
2071
  const { min, max } = videoAudioPeakRange(peaks, start + c * step * speed, start + (c + 1) * step * speed);
2013
- const gain = _chunkIGPEBXUDcjs.videoClipSoundGain.call(void 0, clip, (c + 0.5) * step);
2072
+ const gain = _chunk5T3H7CGGcjs.videoClipSoundGain.call(void 0, clip, (c + 0.5) * step);
2014
2073
  out[2 * c] = min * gain;
2015
2074
  out[2 * c + 1] = max * gain;
2016
2075
  }
@@ -2141,7 +2200,7 @@ var VideoAudioPeaksCache = (_class2 = class {
2141
2200
  // src/video-editor/plan.ts
2142
2201
  function clipIndex(project) {
2143
2202
  const out = /* @__PURE__ */ new Map();
2144
- for (const { track } of _chunkIGPEBXUDcjs.allVideoTracks.call(void 0, project)) for (const c of track.clips) out.set(c.id, c);
2203
+ for (const { track } of _chunk5T3H7CGGcjs.allVideoTracks.call(void 0, project)) for (const c of track.clips) out.set(c.id, c);
2145
2204
  return out;
2146
2205
  }
2147
2206
  function diffVideoProjects(before, after) {
@@ -2150,32 +2209,32 @@ function diffVideoProjects(before, after) {
2150
2209
  const clipsAdded = [...b.keys()].filter((id) => !a.has(id));
2151
2210
  const clipsRemoved = [...a.keys()].filter((id) => !b.has(id));
2152
2211
  const clipsChanged = [...b.keys()].filter((id) => a.has(id) && JSON.stringify(a.get(id)) !== JSON.stringify(b.get(id)));
2153
- const durationBefore = _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, before);
2154
- const durationAfter = _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, after);
2212
+ const durationBefore = _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, before);
2213
+ const durationAfter = _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, after);
2155
2214
  return { durationBefore, durationAfter, durationDelta: durationAfter - durationBefore, clipsAdded, clipsRemoved, clipsChanged };
2156
2215
  }
2157
2216
  function planVideoEdits(project, input) {
2158
- if (!_optionalChain([input, 'access', _33 => _33.title, 'optionalAccess', _34 => _34.trim, 'call', _35 => _35()])) return { ok: false, error: 'A plan needs a title saying what it does (e.g. "Remove 12 filler words").' };
2217
+ if (!_optionalChain([input, 'access', _35 => _35.title, 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()])) return { ok: false, error: 'A plan needs a title saying what it does (e.g. "Remove 12 filler words").' };
2159
2218
  if (!input.edits.length) return { ok: false, error: "The plan has no edits; there is nothing to propose." };
2160
2219
  const result = applyVideoEdits(project, input.edits);
2161
2220
  if (!result.ok) return { ok: false, error: result.error };
2162
2221
  const known = new Set(checkVideoProject(project).map(videoIssueKey));
2163
- const summary = { ...diffVideoProjects(project, result.project), newIssues: result.issues.filter((i) => !known.has(videoIssueKey(i))), edits: input.edits.length };
2222
+ const summary2 = { ...diffVideoProjects(project, result.project), newIssues: result.issues.filter((i) => !known.has(videoIssueKey(i))), edits: input.edits.length };
2164
2223
  const plan = {
2165
2224
  id: _nullishCoalesce(input.id, () => ( "plan")),
2166
2225
  title: input.title.trim(),
2167
2226
  ...input.description ? { description: input.description } : {},
2168
2227
  ...input.source ? { source: input.source } : {},
2169
2228
  edits: structuredClone([...input.edits]),
2170
- ..._optionalChain([input, 'access', _36 => _36.ranges, 'optionalAccess', _37 => _37.length]) ? { ranges: input.ranges.map((r) => ({ ...r })) } : {},
2171
- summary
2229
+ ..._optionalChain([input, 'access', _38 => _38.ranges, 'optionalAccess', _39 => _39.length]) ? { ranges: input.ranges.map((r) => ({ ...r })) } : {},
2230
+ summary: summary2
2172
2231
  };
2173
2232
  return { ok: true, plan, project: result.project };
2174
2233
  }
2175
2234
  function describeVideoEditPlan(plan) {
2176
2235
  const s = plan.summary;
2177
2236
  const parts = [];
2178
- if (_optionalChain([plan, 'access', _38 => _38.ranges, 'optionalAccess', _39 => _39.length])) parts.push(`${plan.ranges.length} stretch${plan.ranges.length > 1 ? "es" : ""}`);
2237
+ if (_optionalChain([plan, 'access', _40 => _40.ranges, 'optionalAccess', _41 => _41.length])) parts.push(`${plan.ranges.length} stretch${plan.ranges.length > 1 ? "es" : ""}`);
2179
2238
  const delta = s.durationDelta;
2180
2239
  const length = Math.abs(delta) < 0.5 ? "same length" : `${(Math.abs(delta) / 1e3).toFixed(1)} s ${delta < 0 ? "shorter" : "longer"}`;
2181
2240
  const clips = [s.clipsAdded.length && `${s.clipsAdded.length} added`, s.clipsChanged.length && `${s.clipsChanged.length} changed`, s.clipsRemoved.length && `${s.clipsRemoved.length} removed`].filter(Boolean).join(", ");
@@ -2514,23 +2573,23 @@ var VideoPreviewPixels = (_class3 = class {constructor() { _class3.prototype.__i
2514
2573
  next(time, timeout = 5e3) {
2515
2574
  const matches = () => this.drawnAt && this.drawnAt.complete && Math.abs(this.drawnAt.time - time) < 0.5;
2516
2575
  return new Promise((resolve, reject) => {
2517
- const done = (fn) => {
2576
+ const done2 = (fn) => {
2518
2577
  clearTimeout(timer);
2519
2578
  off();
2520
2579
  fn();
2521
2580
  };
2522
2581
  const check = () => {
2523
- if (!this.reader) return done(() => reject(new Error("The preview was closed before it drew the frame.")));
2582
+ if (!this.reader) return done2(() => reject(new Error("The preview was closed before it drew the frame.")));
2524
2583
  if (!matches()) return;
2525
2584
  try {
2526
2585
  const snap = this.read();
2527
- done(() => snap ? resolve(snap) : reject(new Error("The preview has no pixels to read.")));
2586
+ done2(() => snap ? resolve(snap) : reject(new Error("The preview has no pixels to read.")));
2528
2587
  } catch (e) {
2529
- done(() => reject(e));
2588
+ done2(() => reject(e));
2530
2589
  }
2531
2590
  };
2532
2591
  const off = this.subscribe(check);
2533
- const timer = setTimeout(() => done(() => reject(new Error(`The preview did not finish drawing ${Math.round(time)} ms within ${timeout} ms; its media may still be loading or may have failed to load. Try again, or check the asset sources.`))), timeout);
2592
+ const timer = setTimeout(() => done2(() => reject(new Error(`The preview did not finish drawing ${Math.round(time)} ms within ${timeout} ms; its media may still be loading or may have failed to load. Try again, or check the asset sources.`))), timeout);
2534
2593
  check();
2535
2594
  });
2536
2595
  }
@@ -2555,6 +2614,88 @@ function readVideoScopesPanel(feed, kinds = VIDEO_SCOPE_KINDS, options = {}) {
2555
2614
  return { ok: true, time: snap.time, complete: snap.complete, images, stats, notes: videoExposureNotes(stats) };
2556
2615
  }
2557
2616
 
2617
+ // src/video-editor/camera.ts
2618
+ function videoCameraView(framing, stage) {
2619
+ const zoom = _nullishCoalesce(_optionalChain([framing, 'optionalAccess', _42 => _42.zoom]), () => ( 1));
2620
+ return { zoom, scrollX: stage.width / (2 * zoom) - (stage.width / 2 + (_nullishCoalesce(_optionalChain([framing, 'optionalAccess', _43 => _43.x]), () => ( 0)))), scrollY: stage.height / (2 * zoom) - (stage.height / 2 + (_nullishCoalesce(_optionalChain([framing, 'optionalAccess', _44 => _44.y]), () => ( 0)))) };
2621
+ }
2622
+ function videoTransformOfView(view, base, stage) {
2623
+ const cx = stage.width / 2;
2624
+ const cy = stage.height / 2;
2625
+ const px = (cx + (_nullishCoalesce(base.x, () => ( 0))) + view.scrollX) * view.zoom - cx;
2626
+ const py = (cy + (_nullishCoalesce(base.y, () => ( 0))) + view.scrollY) * view.zoom - cy;
2627
+ const roll = _nullishCoalesce(view.roll, () => ( 0));
2628
+ const a = roll * Math.PI / 180;
2629
+ const tidy = (n) => Math.round(n * 1e3) / 1e3 || 0;
2630
+ return {
2631
+ x: tidy(px * Math.cos(a) - py * Math.sin(a)),
2632
+ y: tidy(px * Math.sin(a) + py * Math.cos(a)),
2633
+ scale: tidy((_nullishCoalesce(base.scale, () => ( 1))) * view.zoom),
2634
+ rotation: tidy((_nullishCoalesce(base.rotation, () => ( 0))) + roll)
2635
+ };
2636
+ }
2637
+ function videoCameraBase(clip) {
2638
+ if (clip.camera) return clip.camera.base;
2639
+ const t = _nullishCoalesce(clip.transform, () => ( {}));
2640
+ const keyed = _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.filter((p) => _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, t[p]));
2641
+ if (keyed.length)
2642
+ throw new Error(`Clip "${clip.id}" keys its ${keyed.join(", ")}, which a camera move would replace; remove those keyframes first (set_video_keyframes with keys null).`);
2643
+ return Object.fromEntries(_chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.flatMap((p) => typeof t[p] === "number" ? [[p, t[p]]] : []));
2644
+ }
2645
+ async function bakeVideoClipCamera(clip, camera, project, provider) {
2646
+ const stage = { width: project.width, height: project.height };
2647
+ const fps = project.fps > 0 ? project.fps : 30;
2648
+ const to = videoCameraView(camera.framing, stage);
2649
+ const notes = [];
2650
+ const cuts = [];
2651
+ const windows = {};
2652
+ let keys = [];
2653
+ let inMs = 0;
2654
+ const moveIn = _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, camera.in);
2655
+ if (moveIn) {
2656
+ const { description } = await _chunkOPSK22DLcjs.resolveCameraMoveSpec.call(void 0, provider, moveIn, "transition");
2657
+ inMs = _nullishCoalesce(moveIn.ms, () => ( description.camera.durationMs));
2658
+ if (inMs > clip.duration) throw new Error(`The move into clip "${clip.id}" takes ${inMs} ms, longer than the clip (${clip.duration} ms); give a shorter "ms" or lengthen the clip.`);
2659
+ const sample = await _chunkOPSK22DLcjs.sampleEffectCameraMove.call(void 0, provider, moveIn.move, { from: videoCameraView(camera.from, stage), to, ms: inMs, stage, fps, values: moveIn.values });
2660
+ keys.push(...sample.keys);
2661
+ if (sample.cut !== void 0) cuts.push(sample.cut);
2662
+ windows.in = { start: 0, end: inMs };
2663
+ }
2664
+ const moveDuring = _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, camera.during);
2665
+ const holdMs = clip.duration - inMs;
2666
+ if (moveDuring && holdMs > 0) {
2667
+ await _chunkOPSK22DLcjs.resolveCameraMoveSpec.call(void 0, provider, moveDuring, "hold");
2668
+ const at = keys.length ? keys[keys.length - 1].view : to;
2669
+ const sample = await _chunkOPSK22DLcjs.sampleEffectCameraMove.call(void 0, provider, moveDuring.move, { from: at, to: at, ms: holdMs, stage, fps, values: moveDuring.values });
2670
+ const shifted = sample.keys.map((k) => ({ t: k.t + inMs, view: k.view }));
2671
+ if (keys.length && shifted.length && sameView(keys[keys.length - 1].view, shifted[0].view)) shifted.shift();
2672
+ keys.push(...shifted);
2673
+ if (sample.cut !== void 0) cuts.push(sample.cut + inMs);
2674
+ windows.during = { start: inMs, end: clip.duration };
2675
+ } else if (moveDuring) notes.push(`The move into the clip fills it, so the hold move "${moveDuring.move}" has no time to play; shorten the move in or lengthen the clip.`);
2676
+ if (!keys.length) keys = [{ t: 0, view: to }];
2677
+ const flat = keys.some((k) => k.view.tilt || k.view.turn || k.view.blur && k.view.blur > 0);
2678
+ if (flat) notes.push("A clip transform has no tilt, turn or motion blur, so those parts of the move are left out; the zoom, pan and roll are kept.");
2679
+ const base = videoCameraBase(clip);
2680
+ const transforms = keys.map((k) => ({ t: Math.round(k.t * 1e3) / 1e3, value: videoTransformOfView(k.view, base, stage) }));
2681
+ const transform = {};
2682
+ for (const p of _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES) {
2683
+ const out = [];
2684
+ for (const { t, value } of transforms) {
2685
+ const last = out[out.length - 1];
2686
+ const prev = out[out.length - 2];
2687
+ if (last && prev && last.v === value[p] && prev.v === value[p] && prev.t !== last.t) out[out.length - 1] = { t, v: value[p] };
2688
+ else out.push({ t, v: value[p] });
2689
+ }
2690
+ transform[p] = out.length > 1 && out.some((k) => k.v !== out[0].v) ? { keys: out } : out[0].v;
2691
+ }
2692
+ return { transform, cuts, windows, notes };
2693
+ }
2694
+ var sameView = (a, b) => ["zoom", "scrollX", "scrollY", "tilt", "turn", "roll", "blur"].every((k) => Math.abs((_nullishCoalesce(a[k], () => ( 0))) - (_nullishCoalesce(b[k], () => ( 0)))) < 1e-9);
2695
+ function videoClipCameraMove(clip, role) {
2696
+ return _chunkOPSK22DLcjs.cameraMoveParts.call(void 0, _optionalChain([clip, 'optionalAccess', _45 => _45.camera, 'optionalAccess', _46 => _46[role === "transition" ? "in" : "during"]]));
2697
+ }
2698
+
2558
2699
  // src/video-editor/transcript-controller.ts
2559
2700
  var TranscriptVideoController = (_class4 = class {
2560
2701
  constructor(controller, options = {}) {;_class4.prototype.__init9.call(this);_class4.prototype.__init10.call(this);_class4.prototype.__init11.call(this);_class4.prototype.__init12.call(this);_class4.prototype.__init13.call(this);_class4.prototype.__init14.call(this);_class4.prototype.__init15.call(this);
@@ -2590,7 +2731,7 @@ var TranscriptVideoController = (_class4 = class {
2590
2731
  }}
2591
2732
  /** Stops following the editor. */
2592
2733
  destroy() {
2593
- _optionalChain([this, 'access', _40 => _40.unsubscribe, 'optionalCall', _41 => _41()]);
2734
+ _optionalChain([this, 'access', _47 => _47.unsubscribe, 'optionalCall', _48 => _48()]);
2594
2735
  this.unsubscribe = null;
2595
2736
  this.listeners.clear();
2596
2737
  }
@@ -2604,7 +2745,7 @@ var TranscriptVideoController = (_class4 = class {
2604
2745
  words = videoTimelineTranscript(project, { track: this.track });
2605
2746
  } catch (e4) {
2606
2747
  }
2607
- const disfluencies = detectVideoDisfluencies(words, { ...this.options.disfluencies, pauses: { fps: project.fps, ..._optionalChain([this, 'access', _42 => _42.options, 'access', _43 => _43.disfluencies, 'optionalAccess', _44 => _44.pauses]) } });
2748
+ const disfluencies = detectVideoDisfluencies(words, { ...this.options.disfluencies, pauses: { fps: project.fps, ..._optionalChain([this, 'access', _49 => _49.options, 'access', _50 => _50.disfluencies, 'optionalAccess', _51 => _51.pauses]) } });
2608
2749
  const flags = {};
2609
2750
  for (const d of disfluencies)
2610
2751
  for (let i = d.words[0]; i <= d.words[1]; i++) {
@@ -2727,12 +2868,12 @@ var TranscriptVideoController = (_class4 = class {
2727
2868
  // src/video-editor/proxy.ts
2728
2869
  var VIDEO_PROXY_SCALES = [0.5, 0.25];
2729
2870
  function videoAssetProxy(asset, scale) {
2730
- if (!_optionalChain([asset, 'optionalAccess', _45 => _45.proxies, 'optionalAccess', _46 => _46.length]) || !(scale > 0) || scale >= 1) return null;
2871
+ if (!_optionalChain([asset, 'optionalAccess', _52 => _52.proxies, 'optionalAccess', _53 => _53.length]) || !(scale > 0) || scale >= 1) return null;
2731
2872
  let best = null;
2732
2873
  for (const p of asset.proxies) if (p.scale >= scale - 1e-9 && p.scale < 1 && (!best || p.scale < best.scale)) best = p;
2733
2874
  return best;
2734
2875
  }
2735
- var videoPreviewSrc = (asset, scale, fallback = _nullishCoalesce(_optionalChain([asset, 'optionalAccess', _47 => _47.src]), () => ( ""))) => _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _48 => _48(asset, scale), 'optionalAccess', _49 => _49.src]), () => ( fallback));
2876
+ var videoPreviewSrc = (asset, scale, fallback = _nullishCoalesce(_optionalChain([asset, 'optionalAccess', _54 => _54.src]), () => ( ""))) => _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _55 => _55(asset, scale), 'optionalAccess', _56 => _56.src]), () => ( fallback));
2736
2877
  function resolveVideoPreviewScale(scale, shown) {
2737
2878
  if (scale === void 0 || scale === "auto") return Math.min(1, Math.max(0, shown));
2738
2879
  if (scale === "full") return 1;
@@ -2781,7 +2922,7 @@ function videoProxyFfmpeg(asset, options = {}) {
2781
2922
  output
2782
2923
  ];
2783
2924
  const proxy = { scale, src: output, ...asset.width && asset.height ? { width: Math.trunc(asset.width * scale / 2) * 2, height: Math.trunc(asset.height * scale / 2) * 2 } : {} };
2784
- return { asset: asset.id, args, command: ["ffmpeg", ...args].map(_chunkIGPEBXUDcjs.videoShellQuote).join(" "), proxy };
2925
+ return { asset: asset.id, args, command: ["ffmpeg", ...args].map(_chunk5T3H7CGGcjs.videoShellQuote).join(" "), proxy };
2785
2926
  }
2786
2927
  function videoProxyPlan(project, options = {}) {
2787
2928
  const scale = _nullishCoalesce(options.scale, () => ( 0.5));
@@ -2791,7 +2932,7 @@ function videoProxyPlan(project, options = {}) {
2791
2932
  if (!a) throw new Error(`There is no asset "${id}"; the assets are ${project.assets.map((x) => `"${x.id}"`).join(", ") || "none"}.`);
2792
2933
  if (a.kind !== "video") throw new Error(`Asset "${id}" is ${a.kind === "image" ? "an image" : "audio"}; only video assets have proxies.`);
2793
2934
  }
2794
- return project.assets.filter((a) => a.kind === "video" && (!wanted || wanted.has(a.id)) && !_optionalChain([a, 'access', _50 => _50.proxies, 'optionalAccess', _51 => _51.some, 'call', _52 => _52((p) => Math.abs(p.scale - scale) < 1e-9)])).map((a) => videoProxyFfmpeg(a, { ...options, scale }));
2935
+ return project.assets.filter((a) => a.kind === "video" && (!wanted || wanted.has(a.id)) && !_optionalChain([a, 'access', _57 => _57.proxies, 'optionalAccess', _58 => _58.some, 'call', _59 => _59((p) => Math.abs(p.scale - scale) < 1e-9)])).map((a) => videoProxyFfmpeg(a, { ...options, scale }));
2795
2936
  }
2796
2937
  var VIDEO_PREVIEW_SCALE_OPTIONS = [
2797
2938
  { value: "auto", label: "Auto", scale: "auto" },
@@ -2799,7 +2940,7 @@ var VIDEO_PREVIEW_SCALE_OPTIONS = [
2799
2940
  ...VIDEO_PROXY_SCALES.map((s) => ({ value: String(s), label: s === 0.5 ? "\xBD" : s === 0.25 ? "\xBC" : `${s * 100}%`, scale: s }))
2800
2941
  ];
2801
2942
  var parseVideoPreviewScale = (value) => value === "full" ? "full" : Number(value) > 0 && Number(value) <= 1 ? Number(value) : "auto";
2802
- var videoProjectHasProxies = (project) => project.assets.some((a) => !!_optionalChain([a, 'access', _53 => _53.proxies, 'optionalAccess', _54 => _54.length]));
2943
+ var videoProjectHasProxies = (project) => project.assets.some((a) => !!_optionalChain([a, 'access', _60 => _60.proxies, 'optionalAccess', _61 => _61.length]));
2803
2944
 
2804
2945
  // src/video-editor/frame-cache.ts
2805
2946
  var videoSourceFrame = (sourceTime, fps) => Math.max(0, Math.floor(sourceTime * fps / 1e3 + 1e-6));
@@ -2807,7 +2948,7 @@ var videoSourceFrameTime = (frame, fps) => (frame + 0.5) * 1e3 / fps;
2807
2948
  var videoFrameCacheKey = (src, frame) => `${frame}@${src}`;
2808
2949
  function videoFrameRequestsAt(project, time, srcFor = (l) => l.src) {
2809
2950
  const out = [];
2810
- for (const layer of _chunkIGPEBXUDcjs.videoFrameLeafLayers.call(void 0, _chunkIGPEBXUDcjs.videoFrameAt.call(void 0, project, time).layers)) {
2951
+ for (const layer of _chunk5T3H7CGGcjs.videoFrameLeafLayers.call(void 0, _chunk5T3H7CGGcjs.videoFrameAt.call(void 0, project, time).layers)) {
2811
2952
  if (layer.type !== "media" || layer.assetKind !== "video") continue;
2812
2953
  const src = srcFor(layer);
2813
2954
  if (!src) continue;
@@ -2843,7 +2984,7 @@ function videoCacheEvictions(entries, options) {
2843
2984
  return d >= 0 ? d : -d * behind;
2844
2985
  };
2845
2986
  const out = [];
2846
- for (const e of entries.filter((x) => !_optionalChain([options, 'access', _55 => _55.protect, 'optionalAccess', _56 => _56.has, 'call', _57 => _57(x.key)])).sort((a, b) => cost(b) - cost(a))) {
2987
+ for (const e of entries.filter((x) => !_optionalChain([options, 'access', _62 => _62.protect, 'optionalAccess', _63 => _63.has, 'call', _64 => _64(x.key)])).sort((a, b) => cost(b) - cost(a))) {
2847
2988
  if (total <= options.maxBytes) break;
2848
2989
  out.push(e.key);
2849
2990
  total -= e.bytes;
@@ -2884,7 +3025,7 @@ var VideoFrameCache = (_class5 = class {
2884
3025
  const entry = this.entries.get(videoFrameCacheKey(src, videoSourceFrame(sourceTime, fps)));
2885
3026
  if (entry) this.hits++;
2886
3027
  else this.misses++;
2887
- return _optionalChain([entry, 'optionalAccess', _58 => _58.frame, 'access', _59 => _59.image]);
3028
+ return _optionalChain([entry, 'optionalAccess', _65 => _65.frame, 'access', _66 => _66.image]);
2888
3029
  }
2889
3030
  /** Whether a frame is cached, without counting it. */
2890
3031
  has(src, sourceTime, fps) {
@@ -2892,7 +3033,7 @@ var VideoFrameCache = (_class5 = class {
2892
3033
  }
2893
3034
  /** Keeps a decoded frame (replacing any with the same key), then evicts to the budget. */
2894
3035
  put(request, frame) {
2895
- if (this.destroyed) return void _optionalChain([frame, 'access', _60 => _60.image, 'access', _61 => _61.close, 'optionalCall', _62 => _62()]);
3036
+ if (this.destroyed) return void _optionalChain([frame, 'access', _67 => _67.image, 'access', _68 => _68.close, 'optionalCall', _69 => _69()]);
2896
3037
  const old = this.entries.get(request.key);
2897
3038
  if (old) this.drop(old);
2898
3039
  const bytes = Math.max(1, frame.width * frame.height * 4);
@@ -2991,7 +3132,7 @@ var VideoFrameCache = (_class5 = class {
2991
3132
  (frame) => {
2992
3133
  this.inFlight.delete(r.key);
2993
3134
  if (generation === this.generation || this.bytes + frame.width * frame.height * 4 <= this.maxBytes) this.put(r, frame);
2994
- else _optionalChain([frame, 'access', _63 => _63.image, 'access', _64 => _64.close, 'optionalCall', _65 => _65()]);
3135
+ else _optionalChain([frame, 'access', _70 => _70.image, 'access', _71 => _71.close, 'optionalCall', _72 => _72()]);
2995
3136
  },
2996
3137
  () => this.inFlight.delete(r.key)
2997
3138
  ).finally(() => this.pump());
@@ -3004,7 +3145,7 @@ var VideoFrameCache = (_class5 = class {
3004
3145
  drop(e) {
3005
3146
  this.entries.delete(e.key);
3006
3147
  this.bytes -= e.bytes;
3007
- _optionalChain([e, 'access', _66 => _66.frame, 'access', _67 => _67.image, 'access', _68 => _68.close, 'optionalCall', _69 => _69()]);
3148
+ _optionalChain([e, 'access', _73 => _73.frame, 'access', _74 => _74.image, 'access', _75 => _75.close, 'optionalCall', _76 => _76()]);
3008
3149
  }
3009
3150
  emit() {
3010
3151
  for (const l of [...this.listeners]) l();
@@ -3056,7 +3197,7 @@ var VideoPreviewEngine = (_class6 = class {
3056
3197
  this.source = source;
3057
3198
  this.options = options;
3058
3199
  this.canvas = canvas2;
3059
- this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas2, 'access', _74 => _74.getContext, 'optionalCall', _75 => _75("2d")]), () => ( null));
3200
+ this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas2, 'access', _81 => _81.getContext, 'optionalCall', _82 => _82("2d")]), () => ( null));
3060
3201
  this.unsubscribe = source.subscribe(() => this.update());
3061
3202
  this.lutCache = options.luts !== void 0 ? options.luts : _nullishCoalesce(source.luts, () => ( null));
3062
3203
  this.unsubscribeLuts = this.lutCache ? this.lutCache.subscribe(() => this.redraw()) : () => {
@@ -3101,7 +3242,7 @@ var VideoPreviewEngine = (_class6 = class {
3101
3242
  /** The canvas's pixels and the frame they show, or `null` when its context cannot be read. */
3102
3243
  readPixels() {
3103
3244
  const ctx = this.ctx;
3104
- if (!_optionalChain([ctx, 'optionalAccess', _76 => _76.getImageData]) || !this.drawn) return null;
3245
+ if (!_optionalChain([ctx, 'optionalAccess', _83 => _83.getImageData]) || !this.drawn) return null;
3105
3246
  return { ...this.drawn, pixels: ctx.getImageData(0, 0, this.canvas.width, this.canvas.height) };
3106
3247
  }
3107
3248
  createMedia(kind) {
@@ -3139,8 +3280,8 @@ var VideoPreviewEngine = (_class6 = class {
3139
3280
  entry.media.pause();
3140
3281
  entry.media.removeEventListener("seeked", entry.onReady);
3141
3282
  entry.media.removeEventListener("loadeddata", entry.onReady);
3142
- _optionalChain([entry, 'access', _77 => _77.media, 'access', _78 => _78.removeAttribute, 'optionalCall', _79 => _79("src")]);
3143
- _optionalChain([entry, 'access', _80 => _80.media, 'access', _81 => _81.load, 'optionalCall', _82 => _82()]);
3283
+ _optionalChain([entry, 'access', _84 => _84.media, 'access', _85 => _85.removeAttribute, 'optionalCall', _86 => _86("src")]);
3284
+ _optionalChain([entry, 'access', _87 => _87.media, 'access', _88 => _88.load, 'optionalCall', _89 => _89()]);
3144
3285
  this.media.delete(entry.clip);
3145
3286
  }
3146
3287
  /** Brings the media elements in step with the editor and draws the frame. */
@@ -3148,13 +3289,13 @@ var VideoPreviewEngine = (_class6 = class {
3148
3289
  if (this.destroyed) return;
3149
3290
  const state = this.source.getState();
3150
3291
  const { project, time, playing } = state;
3151
- const frame = _chunkIGPEBXUDcjs.videoFrameAt.call(void 0, project, time);
3292
+ const frame = _chunk5T3H7CGGcjs.videoFrameAt.call(void 0, project, time);
3152
3293
  const scale = resolveVideoPreviewScale(_nullishCoalesce(this.options.previewScale, () => ( state.previewScale)), this.resolutionFor(project.width));
3153
3294
  const assets = new Map(project.assets.map((a) => [a.id, a]));
3154
3295
  this.srcFor = (layer) => videoPreviewSrc(assets.get(_nullishCoalesce(layer.asset, () => ( ""))), scale, layer.src);
3155
3296
  this.playing = playing;
3156
3297
  this.fps = project.fps;
3157
- _optionalChain([this, 'access', _83 => _83.frameCache, 'optionalAccess', _84 => _84.update, 'call', _85 => _85(project, time, { playing, srcFor: this.srcFor })]);
3298
+ _optionalChain([this, 'access', _90 => _90.frameCache, 'optionalAccess', _91 => _91.update, 'call', _92 => _92(project, time, { playing, srcFor: this.srcFor })]);
3158
3299
  const tolerance = (_nullishCoalesce(this.options.tolerance, () => ( 200))) / 1e3;
3159
3300
  const active = /* @__PURE__ */ new Set();
3160
3301
  const sync = (clip, src, kind, sourceTime, speed, gain) => {
@@ -3178,10 +3319,10 @@ var VideoPreviewEngine = (_class6 = class {
3178
3319
  }
3179
3320
  };
3180
3321
  const sounding = new Map(frame.audio.map((a) => [a.clip, a]));
3181
- for (const layer of _chunkIGPEBXUDcjs.videoFrameLeafLayers.call(void 0, frame.layers)) {
3322
+ for (const layer of _chunk5T3H7CGGcjs.videoFrameLeafLayers.call(void 0, frame.layers)) {
3182
3323
  if (layer.type !== "media" || layer.assetKind !== "video" || !layer.src) continue;
3183
3324
  const sound = sounding.get(layer.clip);
3184
- sync(layer.clip, this.srcFor(layer), "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _86 => _86.speed]), () => ( 1)), sound ? sound.gain : null);
3325
+ sync(layer.clip, this.srcFor(layer), "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _93 => _93.speed]), () => ( 1)), sound ? sound.gain : null);
3185
3326
  sounding.delete(layer.clip);
3186
3327
  }
3187
3328
  for (const a of sounding.values()) sync(a.clip, a.src, "audio", a.sourceTime, a.speed, a.gain);
@@ -3190,9 +3331,9 @@ var VideoPreviewEngine = (_class6 = class {
3190
3331
  }
3191
3332
  /** With effects, the frame is drawn at the start of its frame, so effect pictures are cached once per frame. */
3192
3333
  drawable(project, frame) {
3193
- if (!_optionalChain([this, 'access', _87 => _87.effects, 'optionalAccess', _88 => _88.available]) || !_chunkIGPEBXUDcjs.videoLayersUseEffects.call(void 0, frame.layers)) return frame;
3194
- const at = _chunkIGPEBXUDcjs.videoEffectFrameTime.call(void 0, frame.time, project.fps);
3195
- return at === frame.time ? frame : { ..._chunkIGPEBXUDcjs.videoFrameAt.call(void 0, project, at), time: frame.time };
3334
+ if (!_optionalChain([this, 'access', _94 => _94.effects, 'optionalAccess', _95 => _95.available]) || !_chunk5T3H7CGGcjs.videoLayersUseEffects.call(void 0, frame.layers)) return frame;
3335
+ const at = _chunk5T3H7CGGcjs.videoEffectFrameTime.call(void 0, frame.time, project.fps);
3336
+ return at === frame.time ? frame : { ..._chunk5T3H7CGGcjs.videoFrameAt.call(void 0, project, at), time: frame.time };
3196
3337
  }
3197
3338
  redraw() {
3198
3339
  if (this.scheduled || this.destroyed) return;
@@ -3201,7 +3342,7 @@ var VideoPreviewEngine = (_class6 = class {
3201
3342
  this.scheduled = false;
3202
3343
  if (this.destroyed) return;
3203
3344
  const { project, time } = this.source.getState();
3204
- this.draw(this.drawable(project, _chunkIGPEBXUDcjs.videoFrameAt.call(void 0, project, time)));
3345
+ this.draw(this.drawable(project, _chunk5T3H7CGGcjs.videoFrameAt.call(void 0, project, time)));
3205
3346
  });
3206
3347
  }
3207
3348
  __init40() {this.sourceFor = (layer) => {
@@ -3212,7 +3353,7 @@ var VideoPreviewEngine = (_class6 = class {
3212
3353
  const entry = this.media.get(layer.clip);
3213
3354
  const ready = !!entry && entry.media.readyState >= 2;
3214
3355
  const cache = this.frameCache;
3215
- const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _89 => _89.src]), () => ( this.srcFor(layer)));
3356
+ const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _96 => _96.src]), () => ( this.srcFor(layer)));
3216
3357
  const sourceTime = _nullishCoalesce(layer.sourceTime, () => ( 0));
3217
3358
  if (cache && src && (!this.playing || !ready || entry.media.seeking)) {
3218
3359
  const hit = cache.get(src, sourceTime, this.fps);
@@ -3244,7 +3385,7 @@ var VideoPreviewEngine = (_class6 = class {
3244
3385
  if (!source) this.complete = false;
3245
3386
  return source;
3246
3387
  };
3247
- _chunkIGPEBXUDcjs.drawVideoFrame.call(void 0, this.ctx, frame, sourceFor, resolution, {
3388
+ _chunk5T3H7CGGcjs.drawVideoFrame.call(void 0, this.ctx, frame, sourceFor, resolution, {
3248
3389
  defineSvgFilter: this.defineSvgFilter,
3249
3390
  lutFor: this.lutFor,
3250
3391
  scratch: this.scratch,
@@ -3254,12 +3395,12 @@ var VideoPreviewEngine = (_class6 = class {
3254
3395
  }
3255
3396
  });
3256
3397
  this.drawn = { time: frame.time, complete: this.complete };
3257
- _optionalChain([this, 'access', _90 => _90.options, 'access', _91 => _91.onFrame, 'optionalCall', _92 => _92(frame)]);
3258
- _optionalChain([this, 'access', _93 => _93.pixelsTarget, 'optionalAccess', _94 => _94.drawn, 'call', _95 => _95(frame.time, this.complete)]);
3398
+ _optionalChain([this, 'access', _97 => _97.options, 'access', _98 => _98.onFrame, 'optionalCall', _99 => _99(frame)]);
3399
+ _optionalChain([this, 'access', _100 => _100.pixelsTarget, 'optionalAccess', _101 => _101.drawn, 'call', _102 => _102(frame.time, this.complete)]);
3259
3400
  }
3260
3401
  /** A grade's LUT once loaded; while it loads (or if it fails) the frame is drawn without it and counts as incomplete. */
3261
3402
  __init41() {this.lutFor = (src) => {
3262
- const lut = _optionalChain([this, 'access', _96 => _96.lutCache, 'optionalAccess', _97 => _97.get, 'call', _98 => _98(src)]);
3403
+ const lut = _optionalChain([this, 'access', _103 => _103.lutCache, 'optionalAccess', _104 => _104.get, 'call', _105 => _105(src)]);
3263
3404
  if (!lut) this.complete = false;
3264
3405
  return lut;
3265
3406
  }}
@@ -3304,7 +3445,7 @@ var VideoPreviewEngine = (_class6 = class {
3304
3445
  this.unsubscribeLuts();
3305
3446
  this.unsubscribeFrames();
3306
3447
  this.unsubscribeEffects();
3307
- _optionalChain([this, 'access', _99 => _99.filterHost, 'optionalAccess', _100 => _100.remove, 'call', _101 => _101()]);
3448
+ _optionalChain([this, 'access', _106 => _106.filterHost, 'optionalAccess', _107 => _107.remove, 'call', _108 => _108()]);
3308
3449
  this.filterHost = null;
3309
3450
  this.filters.clear();
3310
3451
  this.unsubscribe();
@@ -3348,17 +3489,17 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3348
3489
  constructor(options = {}) {;_class7.prototype.__init44.call(this);_class7.prototype.__init45.call(this);_class7.prototype.__init46.call(this);_class7.prototype.__init47.call(this);_class7.prototype.__init48.call(this);_class7.prototype.__init49.call(this);_class7.prototype.__init50.call(this);_class7.prototype.__init51.call(this);_class7.prototype.__init52.call(this);_class7.prototype.__init53.call(this);_class7.prototype.__init54.call(this);_class7.prototype.__init55.call(this);
3349
3490
  this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkFJ2MSI43cjs.HistoryManager)()));
3350
3491
  this.audioPeaks = options.audioPeaks instanceof VideoAudioPeaksCache ? options.audioPeaks : new VideoAudioPeaksCache(options.audioPeaks);
3351
- this.luts = options.luts instanceof _chunkIGPEBXUDcjs.VideoLutCache ? options.luts : new (0, _chunkIGPEBXUDcjs.VideoLutCache)(options.luts);
3492
+ this.luts = options.luts instanceof _chunk5T3H7CGGcjs.VideoLutCache ? options.luts : new (0, _chunk5T3H7CGGcjs.VideoLutCache)(options.luts);
3352
3493
  this.frameCache = _nullishCoalesce(options.frameCache, () => ( null));
3353
- this.effects = new (0, _chunk5MQOBTNPcjs.EffectsSlot)();
3494
+ this.effects = new (0, _chunkOPSK22DLcjs.EffectsSlot)();
3354
3495
  if (options.effects) this.effects.set(options.effects);
3355
- this.effectsEngine = new (0, _chunkIGPEBXUDcjs.VideoEffectsEngine)({ slot: this.effects });
3496
+ this.effectsEngine = new (0, _chunk5T3H7CGGcjs.VideoEffectsEngine)({ slot: this.effects });
3356
3497
  this.project = options.project ? parseVideoProject(options.project) : createVideoProject();
3357
3498
  this.issues = checkVideoProject(this.project);
3358
3499
  this.readOnly = _nullishCoalesce(options.readOnly, () => ( false));
3359
3500
  this.previewScale = checkPreviewScale(_nullishCoalesce(options.previewScale, () => ( "auto")));
3360
3501
  this.onChange = options.onChange;
3361
- this.player = new (0, _chunkM5GLQQWGcjs.AnimationPlayer)({ clock: options.clock, duration: () => _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, this.project), loop: "none" });
3502
+ this.player = new (0, _chunkM5GLQQWGcjs.AnimationPlayer)({ clock: options.clock, duration: () => _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, this.project), loop: "none" });
3362
3503
  this.state = this.computeState();
3363
3504
  this.connect();
3364
3505
  }
@@ -3395,12 +3536,12 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3395
3536
  const h = this.history.getState();
3396
3537
  return {
3397
3538
  project: this.project,
3398
- duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, this.project),
3539
+ duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, this.project),
3399
3540
  time: p.time,
3400
3541
  playing: p.playing,
3401
3542
  loop: p.loop,
3402
3543
  selection: this.selection,
3403
- current: _chunkIGPEBXUDcjs.videoClipsAt.call(void 0, this.project, p.time).map((c) => c.clip.id),
3544
+ current: _chunk5T3H7CGGcjs.videoClipsAt.call(void 0, this.project, p.time).map((c) => c.clip.id),
3404
3545
  issues: this.issues,
3405
3546
  readOnly: this.readOnly,
3406
3547
  error: this.error,
@@ -3433,12 +3574,12 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3433
3574
  this.issues = checkVideoProject(project);
3434
3575
  const ids = new Set(project.tracks.flatMap((t) => t.clips.map((c) => c.id)));
3435
3576
  if (this.selection.some((id) => !ids.has(id))) this.selection = this.selection.filter((id) => ids.has(id));
3436
- this.player.setDuration(() => _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, this.project));
3577
+ this.player.setDuration(() => _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, this.project));
3437
3578
  } finally {
3438
3579
  this.applying = false;
3439
3580
  }
3440
3581
  this.notify();
3441
- _optionalChain([this, 'access', _102 => _102.onChange, 'optionalCall', _103 => _103(project)]);
3582
+ _optionalChain([this, 'access', _109 => _109.onChange, 'optionalCall', _110 => _110(project)]);
3442
3583
  }
3443
3584
  commit(label, next, merge) {
3444
3585
  const before = this.project;
@@ -3595,7 +3736,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3595
3736
  }
3596
3737
  /** Selects clips (unknown ids are dropped). `add` toggles them into the current selection. */
3597
3738
  select(clips, options = {}) {
3598
- const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _104 => _104.filter, 'call', _105 => _105((id) => _chunkIGPEBXUDcjs.findVideoClip.call(void 0, this.project, id))]), () => ( []));
3739
+ const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _111 => _111.filter, 'call', _112 => _112((id) => _chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.project, id))]), () => ( []));
3599
3740
  let next;
3600
3741
  if (options.add) {
3601
3742
  next = [...this.selection];
@@ -3622,7 +3763,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3622
3763
  step(frames) {
3623
3764
  this.player.pause();
3624
3765
  const fps = this.project.fps;
3625
- this.player.seek(Math.max(0, _chunkIGPEBXUDcjs.snapToVideoFrame.call(void 0, this.player.currentTime, fps) + frames * 1e3 / fps));
3766
+ this.player.seek(Math.max(0, _chunk5T3H7CGGcjs.snapToVideoFrame.call(void 0, this.player.currentTime, fps) + frames * 1e3 / fps));
3626
3767
  }
3627
3768
  setLoop(loop) {
3628
3769
  this.player.setLoop(loop);
@@ -3639,14 +3780,14 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3639
3780
  */
3640
3781
  snap(time, options = {}) {
3641
3782
  const threshold = _nullishCoalesce(options.threshold, () => ( 8 * 1e3 / this.project.fps));
3642
- const points = _chunkIGPEBXUDcjs.videoSnapPoints.call(void 0, this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
3643
- const hit = _chunkIGPEBXUDcjs.snapVideoTime.call(void 0, time, points, threshold);
3644
- return hit.snapped !== null ? hit : { time: Math.max(0, _chunkIGPEBXUDcjs.snapToVideoFrame.call(void 0, time, this.project.fps)), snapped: null };
3783
+ const points = _chunk5T3H7CGGcjs.videoSnapPoints.call(void 0, this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
3784
+ const hit = _chunk5T3H7CGGcjs.snapVideoTime.call(void 0, time, points, threshold);
3785
+ return hit.snapped !== null ? hit : { time: Math.max(0, _chunk5T3H7CGGcjs.snapToVideoFrame.call(void 0, time, this.project.fps)), snapped: null };
3645
3786
  }
3646
3787
  /** Splits the selected clips (or every clip) under the playhead there, as one undo step. */
3647
3788
  splitAtPlayhead() {
3648
- const t = _chunkIGPEBXUDcjs.snapToVideoFrame.call(void 0, this.player.currentTime, this.project.fps);
3649
- const under = _chunkIGPEBXUDcjs.videoClipsAt.call(void 0, this.project, t).filter(({ clip }) => t > clip.start && t < _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip));
3789
+ const t = _chunk5T3H7CGGcjs.snapToVideoFrame.call(void 0, this.player.currentTime, this.project.fps);
3790
+ const under = _chunk5T3H7CGGcjs.videoClipsAt.call(void 0, this.project, t).filter(({ clip }) => t > clip.start && t < _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip));
3650
3791
  const chosen = this.selection.length ? under.filter(({ clip }) => this.selection.includes(clip.id)) : under;
3651
3792
  if (!chosen.length) return this.refuse("No clip is under the playhead to split.");
3652
3793
  return this.apply(chosen.map(({ clip }) => ({ op: "split_clip", clip: clip.id, at: t })), "Split");
@@ -3674,7 +3815,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3674
3815
  /** The provider's description of an effect, checked for `place` (rejects without a provider or for an unknown id). */
3675
3816
  async describeEffect(effect, place) {
3676
3817
  const d = await this.effects.require().describe(effect);
3677
- if (place) _chunkIGPEBXUDcjs.checkVideoEffectPlace.call(void 0, d, place);
3818
+ if (place) _chunk5T3H7CGGcjs.checkVideoEffectPlace.call(void 0, d, place);
3678
3819
  return d;
3679
3820
  }
3680
3821
  refused(message) {
@@ -3687,7 +3828,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3687
3828
  try {
3688
3829
  plan = await run();
3689
3830
  } catch (error) {
3690
- if (_chunk5MQOBTNPcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refused(error.message);
3831
+ if (_chunkOPSK22DLcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refused(error.message);
3691
3832
  throw error;
3692
3833
  }
3693
3834
  const result = this.apply(plan.edit, plan.label, { merge });
@@ -3695,7 +3836,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3695
3836
  return { ...result, clip: plan.clip, ...plan.effect ? { effect: plan.effect() } : {} };
3696
3837
  }
3697
3838
  clipOrThrow(id) {
3698
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, this.project, id);
3839
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.project, id);
3699
3840
  if (!at) throw new Error(`There is no clip "${id}"; list_applied_effects or get_video_project lists the clips.`);
3700
3841
  return at.clip;
3701
3842
  }
@@ -3708,7 +3849,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3708
3849
  return this.effectEdit(async () => {
3709
3850
  const current = this.clipOrThrow(clip);
3710
3851
  const d = await this.describeEffect(effect, "clip");
3711
- const values = _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
3852
+ const values = _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
3712
3853
  const stack = [..._nullishCoalesce(current.effects, () => ( []))];
3713
3854
  const taken = new Set(stack.map((e) => e.id));
3714
3855
  let n = 1;
@@ -3744,7 +3885,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3744
3885
  if (!(k in d.controls.properties)) throw new Error(`"${k}" is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ")}.`);
3745
3886
  base[k] = d.defaults[k];
3746
3887
  }
3747
- next.values = _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d, given, { base, keyframes: true });
3888
+ next.values = _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d, given, { base, keyframes: true });
3748
3889
  }
3749
3890
  if (changes.enabled !== void 0) {
3750
3891
  if (changes.enabled) delete next.enabled;
@@ -3758,11 +3899,92 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3758
3899
  return { edit: { op: "update_clip", clip, set: { effects: stack } }, label: `Change effect ${_nullishCoalesce(was.name, () => ( was.effect))}`, clip, effect: () => next };
3759
3900
  }, options.merge);
3760
3901
  }
3902
+ /** The provider's camera moves for a role (`transition` into a clip, `hold` while it plays), or all of them. Empty without camera support. */
3903
+ async cameraMoves(role) {
3904
+ const provider = this.effects.provider;
3905
+ if (!_optionalChain([provider, 'optionalAccess', _113 => _113.capabilities, 'access', _114 => _114.supportsCamera]) || !provider.cameraView) return [];
3906
+ return (await provider.list({ kind: "camera" })).filter((e) => e.kind === "camera" && e.camera && (!role || e.camera.role === role));
3907
+ }
3908
+ cameraClip(id) {
3909
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.project, id);
3910
+ if (!at) {
3911
+ const ids = this.project.tracks.flatMap((t) => t.clips.map((c) => c.id));
3912
+ throw new Error(`There is no clip "${id}"; the clips are ${ids.map((c) => `"${c}"`).join(", ") || "none"} (get_video_project lists them).`);
3913
+ }
3914
+ if (at.track.kind === "audio") throw new Error(`Clip "${id}" is on audio track "${at.track.id}" and has no picture for a camera to move over.`);
3915
+ if (at.clip.type === "adjustment") throw new Error(`Clip "${id}" is an adjustment clip, which has no picture of its own for a camera to move over.`);
3916
+ return at.clip;
3917
+ }
3918
+ async cameraEdit(clipId, camera, label, merge) {
3919
+ const clip = this.cameraClip(clipId);
3920
+ const base = videoCameraBase(clip);
3921
+ if (!camera) {
3922
+ const restored = Object.keys(base).length ? { transform: base } : {};
3923
+ const r2 = this.apply({ op: "update_clip", clip: clipId, set: restored, remove: ["camera", ...Object.keys(base).length ? [] : ["transform"]] }, label, { merge });
3924
+ if (!r2.ok) return r2;
3925
+ return { ok: true, clip: clipId, camera: null, keys: { x: 0, y: 0, scale: 0, rotation: 0 }, cuts: [], windows: {}, notes: [] };
3926
+ }
3927
+ const bake = await bakeVideoClipCamera(clip, camera, this.project, this.effects.require());
3928
+ const r = this.apply({ op: "update_clip", clip: clipId, set: { camera, transform: bake.transform } }, label, { merge });
3929
+ if (!r.ok) return r;
3930
+ const keys = Object.fromEntries(_chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => [p, _chunk5T3H7CGGcjs.videoKeysOf.call(void 0, bake.transform[p]).length]));
3931
+ return { ok: true, clip: clipId, camera, keys, cuts: bake.cuts, windows: bake.windows, notes: bake.notes };
3932
+ }
3933
+ /**
3934
+ * Sets the camera move a clip plays into (`transition`: from `from` to `framing` from the
3935
+ * clip's start) or while it holds (`hold`: across the rest of the clip at `framing`), and bakes
3936
+ * the clip's moves into its x, y, scale and rotation keys at the project's frame rate, keeping a
3937
+ * cut's two keys. The move is checked first (role, preset, values; a preset's values and a move
3938
+ * in's length are written out). A clip whose transform is keyed by hand is refused. One undo step.
3939
+ */
3940
+ async setClipCameraMove(clip, role, spec, options = {}) {
3941
+ const reason = this.readOnlyReason();
3942
+ if (reason) return this.refused(reason);
3943
+ try {
3944
+ const current = this.cameraClip(clip);
3945
+ const { spec: parts, description } = await _chunkOPSK22DLcjs.resolveCameraMoveSpec.call(void 0, this.effects.require(), spec, role);
3946
+ const move = role === "transition" && parts.ms === void 0 ? { ...parts, ms: description.camera.durationMs } : parts;
3947
+ const simple = move.ms === void 0 && move.preset === void 0 && move.values === void 0;
3948
+ const camera = { ..._nullishCoalesce(current.camera, () => ( { base: videoCameraBase(current) })), [_chunkOPSK22DLcjs.cameraMoveField.call(void 0, role)]: simple ? move.move : move };
3949
+ for (const key of ["from", "framing"]) {
3950
+ if (options[key] === null) delete camera[key];
3951
+ else if (options[key] !== void 0) camera[key] = options[key];
3952
+ }
3953
+ if (camera.from && !camera.in) throw new Error('"from" is where a move in starts; set a transition move too, or leave "from" out.');
3954
+ return await this.cameraEdit(clip, camera, `${role === "hold" ? "Hold move" : "Camera move"} ${description.name}`, options.merge);
3955
+ } catch (error) {
3956
+ if (_chunkOPSK22DLcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refused(error.message);
3957
+ throw error;
3958
+ }
3959
+ }
3960
+ /**
3961
+ * Removes a clip's camera move for a role and bakes what is left (which needs the provider);
3962
+ * with no move left the transform goes back to what it was before the moves. One undo step.
3963
+ */
3964
+ async clearClipCameraMove(clip, role) {
3965
+ const reason = this.readOnlyReason();
3966
+ if (reason) return this.refused(reason);
3967
+ try {
3968
+ const current = this.cameraClip(clip);
3969
+ const field = _chunkOPSK22DLcjs.cameraMoveField.call(void 0, role);
3970
+ const other = field === "in" ? "during" : "in";
3971
+ if (_optionalChain([current, 'access', _115 => _115.camera, 'optionalAccess', _116 => _116[field]]) === void 0)
3972
+ throw new Error(`Clip "${clip}" has no camera "${field}" move to clear${_optionalChain([current, 'access', _117 => _117.camera, 'optionalAccess', _118 => _118[other]]) !== void 0 ? `; it has a "${other}" move (role ${role === "hold" ? "transition" : "hold"})` : ""}.`);
3973
+ const camera = { ...current.camera };
3974
+ delete camera[field];
3975
+ if (field === "in") delete camera.from;
3976
+ const left = camera.in !== void 0 || camera.during !== void 0;
3977
+ return await this.cameraEdit(clip, left ? camera : null, role === "hold" ? "Clear hold move" : "Clear camera move");
3978
+ } catch (error) {
3979
+ if (_chunkOPSK22DLcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refused(error.message);
3980
+ throw error;
3981
+ }
3982
+ }
3761
3983
  /** Removes an effect from a clip's stack (works without a provider, so placeholders can be cleared). One undo step. */
3762
3984
  removeClipEffect(clip, instance) {
3763
3985
  const reason = this.readOnlyReason();
3764
3986
  if (reason) return this.refused(reason);
3765
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, this.project, clip);
3987
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.project, clip);
3766
3988
  if (!at) return this.refused(`There is no clip "${clip}".`);
3767
3989
  const stack = _nullishCoalesce(at.clip.effects, () => ( []));
3768
3990
  const was = stack.find((e) => e.id === instance);
@@ -3779,7 +4001,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3779
4001
  return this.effectEdit(async () => {
3780
4002
  this.clipOrThrow(clip);
3781
4003
  const d = await this.describeEffect(effect, "transition");
3782
- const values = _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d, options.values);
4004
+ const values = _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d, options.values);
3783
4005
  const duration = _nullishCoalesce(_nullishCoalesce(options.duration, () => ( d.duration)), () => ( 1e3));
3784
4006
  return { edit: { op: "set_transition", clip, transition: { type: "effect", duration, effect: { effect: d.id, provider: this.effects.require().id, name: d.name, values } } }, label: `Transition ${d.name}`, clip };
3785
4007
  });
@@ -3792,7 +4014,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3792
4014
  addEffectClip(track, effect, options = {}) {
3793
4015
  return this.effectEdit(async () => {
3794
4016
  const d = await this.describeEffect(effect, "generator");
3795
- const values = _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
4017
+ const values = _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
3796
4018
  const duration = _nullishCoalesce(_nullishCoalesce(options.duration, () => ( d.duration)), () => ( 5e3));
3797
4019
  const label = `Add ${d.name}`;
3798
4020
  const clipId = _nullishCoalesce(options.id, () => ( ""));
@@ -3801,7 +4023,7 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3801
4023
  label,
3802
4024
  clip: clipId
3803
4025
  };
3804
- }).then((r) => r.ok && !r.clip ? { ...r, clip: _nullishCoalesce(_optionalChain([r, 'access', _106 => _106.outcomes, 'access', _107 => _107[0], 'optionalAccess', _108 => _108.clip]), () => ( "")) } : r);
4026
+ }).then((r) => r.ok && !r.clip ? { ...r, clip: _nullishCoalesce(_optionalChain([r, 'access', _119 => _119.outcomes, 'access', _120 => _120[0], 'optionalAccess', _121 => _121.clip]), () => ( "")) } : r);
3805
4027
  }
3806
4028
  /**
3807
4029
  * Changes the values of an effect clip's picture (`target` its id) or of the effect transition
@@ -3814,42 +4036,42 @@ var VideoEditorController = (_class7 = class _VideoEditorController {
3814
4036
  if (part === "generator") {
3815
4037
  if (current.type !== "effect") throw new Error(`Clip "${clip}" is not an effect clip.`);
3816
4038
  const d2 = await this.describeEffect(current.effect);
3817
- return { edit: { op: "update_clip", clip, set: { values: _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d2, values, { base: _nullishCoalesce(current.values, () => ( {})), keyframes: true }) } }, label: `Change ${_nullishCoalesce(current.name, () => ( d2.name))}`, clip };
4039
+ return { edit: { op: "update_clip", clip, set: { values: _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d2, values, { base: _nullishCoalesce(current.values, () => ( {})), keyframes: true }) } }, label: `Change ${_nullishCoalesce(current.name, () => ( d2.name))}`, clip };
3818
4040
  }
3819
4041
  const t = current.transition;
3820
- if (_optionalChain([t, 'optionalAccess', _109 => _109.type]) !== "effect" || !t.effect) throw new Error(`Clip "${clip}" has no effect transition.`);
4042
+ if (_optionalChain([t, 'optionalAccess', _122 => _122.type]) !== "effect" || !t.effect) throw new Error(`Clip "${clip}" has no effect transition.`);
3821
4043
  const d = await this.describeEffect(t.effect.effect);
3822
- const merged = _chunkIGPEBXUDcjs.checkVideoEffectValues.call(void 0, d, values, { base: _nullishCoalesce(t.effect.values, () => ( {})) });
4044
+ const merged = _chunk5T3H7CGGcjs.checkVideoEffectValues.call(void 0, d, values, { base: _nullishCoalesce(t.effect.values, () => ( {})) });
3823
4045
  return { edit: { op: "set_transition", clip, transition: { ...t, effect: { ...t.effect, values: merged } } }, label: `Change transition ${d.name}`, clip };
3824
4046
  }, options.merge);
3825
4047
  }
3826
4048
  /** Keys for one numeric control of a clip effect (clip-relative ms), or `null` to stop animating it (keeping its value at the clip's start). */
3827
4049
  setClipEffectKeyframes(clip, instance, control, keys) {
3828
- const current = _optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, this.project, clip), 'optionalAccess', _110 => _110.clip]);
3829
- const was = _optionalChain([current, 'optionalAccess', _111 => _111.effects, 'optionalAccess', _112 => _112.find, 'call', _113 => _113((e) => e.id === instance)]);
3830
- const value = _optionalChain([was, 'optionalAccess', _114 => _114.values, 'optionalAccess', _115 => _115[control]]);
3831
- const plain = keys === null ? _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, value) ? _optionalChain([value, 'access', _116 => _116.keys, 'access', _117 => _117[0], 'optionalAccess', _118 => _118.v]) : value : { keys: [...keys].sort((a, b) => a.t - b.t) };
4050
+ const current = _optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, this.project, clip), 'optionalAccess', _123 => _123.clip]);
4051
+ const was = _optionalChain([current, 'optionalAccess', _124 => _124.effects, 'optionalAccess', _125 => _125.find, 'call', _126 => _126((e) => e.id === instance)]);
4052
+ const value = _optionalChain([was, 'optionalAccess', _127 => _127.values, 'optionalAccess', _128 => _128[control]]);
4053
+ const plain = keys === null ? _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, value) ? _optionalChain([value, 'access', _129 => _129.keys, 'access', _130 => _130[0], 'optionalAccess', _131 => _131.v]) : value : { keys: [...keys].sort((a, b) => a.t - b.t) };
3832
4054
  return this.updateClipEffect(clip, instance, { values: { [control]: _nullishCoalesce(plain, () => ( null)) } });
3833
4055
  }
3834
4056
  /** What plays at `time` (default: the playhead). */
3835
4057
  frame(time = this.player.currentTime) {
3836
- return _chunkIGPEBXUDcjs.videoFrameAt.call(void 0, this.project, time);
4058
+ return _chunk5T3H7CGGcjs.videoFrameAt.call(void 0, this.project, time);
3837
4059
  }
3838
4060
  /** The frame at `time` (default: the playhead) as SVG. */
3839
4061
  toSvg(time = this.player.currentTime, options = {}) {
3840
- return _chunkIGPEBXUDcjs.videoProjectSvg.call(void 0, this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
4062
+ return _chunk5T3H7CGGcjs.videoProjectSvg.call(void 0, this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
3841
4063
  }
3842
4064
  /** The project as an ffmpeg command. */
3843
4065
  toFfmpeg(options = {}) {
3844
- return _chunkIGPEBXUDcjs.toVideoFfmpeg.call(void 0, this.project, options);
4066
+ return _chunk5T3H7CGGcjs.toVideoFfmpeg.call(void 0, this.project, options);
3845
4067
  }
3846
4068
  /** The ffmpeg command that measures the mix's loudness (see `toVideoLoudnessMeasure`). */
3847
4069
  toLoudnessMeasure(options = {}) {
3848
- return _chunkIGPEBXUDcjs.toVideoLoudnessMeasure.call(void 0, this.project, options);
4070
+ return _chunk5T3H7CGGcjs.toVideoLoudnessMeasure.call(void 0, this.project, options);
3849
4071
  }
3850
4072
  /** One track as a CMX 3600 EDL. */
3851
4073
  toEdl(options = {}) {
3852
- return _chunkIGPEBXUDcjs.toVideoEdl.call(void 0, this.project, options);
4074
+ return _chunk5T3H7CGGcjs.toVideoEdl.call(void 0, this.project, options);
3853
4075
  }
3854
4076
  }, _class7.__initStatic(), _class7);
3855
4077
  function checkPreviewScale(scale) {
@@ -3883,7 +4105,7 @@ function planVideoToolPlayback(tool, args) {
3883
4105
  const clips = clipsOf(args);
3884
4106
  const track = str2(args.track) ? args.track : void 0;
3885
4107
  const newClip = args.clip && typeof args.clip === "object" ? args.clip : null;
3886
- const time = [args.start, args.at, args.time, args.to, _optionalChain([newClip, 'optionalAccess', _119 => _119.start])].find(num2);
4108
+ const time = [args.start, args.at, args.time, args.to, _optionalChain([newClip, 'optionalAccess', _132 => _132.start])].find(num2);
3887
4109
  const click = (ref) => [{ type: "target", ref }, { type: "press" }, { type: "release" }];
3888
4110
  if (clips.length === 1 && (time !== void 0 || track) && tool !== "split_video_clip") {
3889
4111
  const clip = clips[0];
@@ -3917,12 +4139,12 @@ function videoRulerTicks(duration, pxPerSecond, fps) {
3917
4139
  const ticks = [];
3918
4140
  for (let t = 0; t <= duration + 1e-6; t += step) {
3919
4141
  const isMajor = Math.abs(t / major - Math.round(t / major)) < 1e-9;
3920
- ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: _chunkIGPEBXUDcjs.formatVideoTimecode.call(void 0, t, fps).replace(/^00:/, "") } : {} });
4142
+ ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: _chunk5T3H7CGGcjs.formatVideoTimecode.call(void 0, t, fps).replace(/^00:/, "") } : {} });
3921
4143
  }
3922
4144
  return ticks;
3923
4145
  }
3924
4146
  function videoClipShowsWaveform(clip, asset, mode = "audio") {
3925
- if (clip.type !== "media" || mode === "none" || !_chunkIGPEBXUDcjs.videoAssetHasSound.call(void 0, asset)) return false;
4147
+ if (clip.type !== "media" || mode === "none" || !_chunk5T3H7CGGcjs.videoAssetHasSound.call(void 0, asset)) return false;
3926
4148
  return mode === "all" || asset.kind === "audio";
3927
4149
  }
3928
4150
  var VIDEO_CLIP_ANIMATION_LABELS = {
@@ -3979,15 +4201,15 @@ function videoClipLabel(clip, asset, sequence) {
3979
4201
  if (clip.name) return clip.name;
3980
4202
  if (clip.type === "text") return clip.text.split("\n")[0];
3981
4203
  if (clip.type === "color") return clip.color;
3982
- if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess', _120 => _120.name]), () => ( clip.sequence))}`;
4204
+ if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess', _133 => _133.name]), () => ( clip.sequence))}`;
3983
4205
  if (clip.type === "effect") return `Effect: ${clip.effect}`;
3984
4206
  if (clip.type === "adjustment") return `Adjustment${clip.scope === "all" ? " (all tracks)" : clip.scope === "track" ? ` (${clip.targetTrack})` : ""}`;
3985
- const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _121 => _121.name]), () => ( _optionalChain([asset, 'optionalAccess', _122 => _122.src, 'access', _123 => _123.replace, 'call', _124 => _124(/^.*[\\/]/, "")]))), () => ( clip.asset));
3986
- const speed = _chunkIGPEBXUDcjs.videoClipSpeed.call(void 0, clip);
4207
+ const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _134 => _134.name]), () => ( _optionalChain([asset, 'optionalAccess', _135 => _135.src, 'access', _136 => _136.replace, 'call', _137 => _137(/^.*[\\/]/, "")]))), () => ( clip.asset));
4208
+ const speed = _chunk5T3H7CGGcjs.videoClipSpeed.call(void 0, clip);
3987
4209
  return speed !== 1 ? `${base} (${Math.round(speed * 100)}%)` : base;
3988
4210
  }
3989
4211
  function planVideoClipDrag(project, input) {
3990
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, input.clip);
4212
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, input.clip);
3991
4213
  if (!at) return null;
3992
4214
  const { clip, track } = at;
3993
4215
  const snap = _nullishCoalesce(input.snap, () => ( ((t) => t)));
@@ -4004,17 +4226,17 @@ function planVideoClipDrag(project, input) {
4004
4226
  }
4005
4227
  const minimum = 1e3 / project.fps;
4006
4228
  if (input.mode === "trim-start") {
4007
- const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip) - minimum);
4229
+ const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip) - minimum);
4008
4230
  const changed2 = Math.abs(to2 - clip.start) > 1e-6;
4009
- const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip) - to2 };
4231
+ const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip) - to2 };
4010
4232
  return { ...plan, track: track.id, edit: changed2 ? { op: "trim_clip", clip: clip.id, edge: "start", to: to2, ...input.ripple ? { ripple: true } : {} } : null };
4011
4233
  }
4012
- const to = Math.max(snap(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip) + input.delta), clip.start + minimum);
4013
- const changed = Math.abs(to - _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip)) > 1e-6;
4234
+ const to = Math.max(snap(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip) + input.delta), clip.start + minimum);
4235
+ const changed = Math.abs(to - _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip)) > 1e-6;
4014
4236
  return { start: clip.start, duration: to - clip.start, track: track.id, edit: changed ? { op: "trim_clip", clip: clip.id, edge: "end", to, ...input.ripple ? { ripple: true } : {} } : null };
4015
4237
  }
4016
4238
  function videoDropTracks(project, clipId) {
4017
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, clipId);
4239
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, clipId);
4018
4240
  if (!at) return [];
4019
4241
  return project.tracks.filter((t) => t.kind === at.track.kind && !t.locked).map((t) => t.id);
4020
4242
  }
@@ -4023,10 +4245,10 @@ function videoDragLabel(edit) {
4023
4245
  return edit.op === "trim_clip" && edit.ripple ? "Ripple trim" : "Trim clip";
4024
4246
  }
4025
4247
  function videoAssetDropEdit(project, assetId, options = {}) {
4026
- const asset = _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, project).get(assetId);
4248
+ const asset = _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, project).get(assetId);
4027
4249
  if (!asset) return null;
4028
4250
  const kind = asset.kind === "audio" ? "audio" : "video";
4029
- const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _125 => _125.tracks, 'access', _126 => _126.find, 'call', _127 => _127((t) => t.kind === kind && !t.locked), 'optionalAccess', _128 => _128.id])));
4251
+ const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _138 => _138.tracks, 'access', _139 => _139.find, 'call', _140 => _140((t) => t.kind === kind && !t.locked), 'optionalAccess', _141 => _141.id])));
4030
4252
  if (!track) return null;
4031
4253
  return { op: "add_clip", track, clip: { type: "media", asset: asset.id, ...options.start !== void 0 ? { start: options.start } : {} }, ...options.ripple ? { ripple: true } : {}, ...options.mode && options.mode !== "refuse" ? { mode: options.mode } : {} };
4032
4254
  }
@@ -4041,7 +4263,7 @@ function probeVideoMedia(src, kind, timeout = 15e3) {
4041
4263
  return new Promise((resolve, reject) => {
4042
4264
  if (typeof document === "undefined") return reject(new Error("Media can only be probed in a browser."));
4043
4265
  const timer = setTimeout(() => reject(new Error(`"${src}" took too long to load.`)), timeout);
4044
- const done = (probe) => {
4266
+ const done2 = (probe) => {
4045
4267
  clearTimeout(timer);
4046
4268
  resolve(probe);
4047
4269
  };
@@ -4051,7 +4273,7 @@ function probeVideoMedia(src, kind, timeout = 15e3) {
4051
4273
  };
4052
4274
  if (kind === "image") {
4053
4275
  const img = new Image();
4054
- img.onload = () => done({ kind, width: img.naturalWidth, height: img.naturalHeight });
4276
+ img.onload = () => done2({ kind, width: img.naturalWidth, height: img.naturalHeight });
4055
4277
  img.onerror = failed;
4056
4278
  img.src = src;
4057
4279
  return;
@@ -4061,7 +4283,7 @@ function probeVideoMedia(src, kind, timeout = 15e3) {
4061
4283
  el.onloadedmetadata = () => {
4062
4284
  const duration = Number.isFinite(el.duration) ? Math.round(el.duration * 1e3) : void 0;
4063
4285
  const v = el;
4064
- done({ kind, ...duration ? { duration } : {}, ...kind === "video" && v.videoWidth ? { width: v.videoWidth, height: v.videoHeight } : {} });
4286
+ done2({ kind, ...duration ? { duration } : {}, ...kind === "video" && v.videoWidth ? { width: v.videoWidth, height: v.videoHeight } : {} });
4065
4287
  };
4066
4288
  el.onerror = failed;
4067
4289
  el.src = src;
@@ -4075,25 +4297,25 @@ var KEY_LABELS = {
4075
4297
  scale: { label: "Scale", step: 0.05 },
4076
4298
  rotation: { label: "Rotation", step: 1 }
4077
4299
  };
4078
- var animatableOf = (clip, property) => _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access', _129 => _129.transform, 'optionalAccess', _130 => _130[property]]) : property === "volume" ? clip.type === "media" || clip.type === "sequence" ? clip.volume : void 0 : clip.opacity;
4300
+ var animatableOf = (clip, property) => _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access', _142 => _142.transform, 'optionalAccess', _143 => _143[property]]) : property === "volume" ? clip.type === "media" || clip.type === "sequence" ? clip.volume : void 0 : clip.opacity;
4079
4301
  var playheadInClip = (clip, time) => Math.round(Math.min(clip.duration, Math.max(0, time - clip.start)));
4080
4302
  function videoKeyframeRows(project, clipId, time) {
4081
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, clipId);
4303
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, clipId);
4082
4304
  if (!at) return [];
4083
4305
  const { clip } = at;
4084
- const asset = clip.type === "media" ? _chunkIGPEBXUDcjs.videoAssetMap.call(void 0, project).get(clip.asset) : void 0;
4085
- const visual = !(_optionalChain([asset, 'optionalAccess', _131 => _131.kind]) === "audio" || at.track.kind === "audio");
4086
- const audible = clip.type === "media" && _chunkIGPEBXUDcjs.videoAssetHasSound.call(void 0, asset) || clip.type === "sequence";
4087
- const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES : []];
4306
+ const asset = clip.type === "media" ? _chunk5T3H7CGGcjs.videoAssetMap.call(void 0, project).get(clip.asset) : void 0;
4307
+ const visual = !(_optionalChain([asset, 'optionalAccess', _144 => _144.kind]) === "audio" || at.track.kind === "audio");
4308
+ const audible = clip.type === "media" && _chunk5T3H7CGGcjs.videoAssetHasSound.call(void 0, asset) || clip.type === "sequence";
4309
+ const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES : []];
4088
4310
  const clipTime = playheadInClip(clip, time);
4089
4311
  return properties.map((property) => {
4090
4312
  const prop = animatableOf(clip, property);
4091
- const keys = _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, prop) ? prop.keys : [];
4092
- const limits = _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_LIMITS[property];
4313
+ const keys = _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, prop) ? prop.keys : [];
4314
+ const limits = _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_LIMITS[property];
4093
4315
  return {
4094
4316
  property,
4095
4317
  ...KEY_LABELS[property],
4096
- value: Math.round(_chunkIGPEBXUDcjs.videoValueAt.call(void 0, prop, clipTime, limits.default) * 1e3) / 1e3,
4318
+ value: Math.round(_chunk5T3H7CGGcjs.videoValueAt.call(void 0, prop, clipTime, limits.default) * 1e3) / 1e3,
4097
4319
  keyed: keys.length > 0,
4098
4320
  keys: keys.length,
4099
4321
  onKey: keys.some((k) => Math.abs(k.t - clipTime) < 0.5),
@@ -4104,44 +4326,44 @@ function videoKeyframeRows(project, clipId, time) {
4104
4326
  });
4105
4327
  }
4106
4328
  function plainValueEdit(clip, property, value) {
4107
- if (!_chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property))
4329
+ if (!_chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property))
4108
4330
  return value === void 0 ? { op: "update_clip", clip: clip.id, remove: [property] } : { op: "update_clip", clip: clip.id, set: { [property]: value } };
4109
4331
  const transform = { ...clip.transform, [property]: value };
4110
4332
  if (value === void 0) delete transform[property];
4111
4333
  return Object.keys(transform).length ? { op: "update_clip", clip: clip.id, set: { transform } } : { op: "update_clip", clip: clip.id, remove: ["transform"] };
4112
4334
  }
4113
4335
  function videoKeyframeValueEdit(project, clipId, property, time, value) {
4114
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, clipId);
4336
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, clipId);
4115
4337
  if (!at) return null;
4116
4338
  const prop = animatableOf(at.clip, property);
4117
- if (!_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, prop)) return plainValueEdit(at.clip, property, value);
4339
+ if (!_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, prop)) return plainValueEdit(at.clip, property, value);
4118
4340
  if (value === void 0) return null;
4119
- return { op: "set_keyframes", clip: clipId, property, keys: _chunkIGPEBXUDcjs.setVideoKey.call(void 0, prop, { t: playheadInClip(at.clip, time), v: value }, _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_LIMITS[property].default).keys };
4341
+ return { op: "set_keyframes", clip: clipId, property, keys: _chunk5T3H7CGGcjs.setVideoKey.call(void 0, prop, { t: playheadInClip(at.clip, time), v: value }, _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_LIMITS[property].default).keys };
4120
4342
  }
4121
4343
  function videoKeyframeToggleEdit(project, clipId, property, time) {
4122
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, clipId);
4344
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, clipId);
4123
4345
  if (!at) return null;
4124
4346
  const prop = animatableOf(at.clip, property);
4125
4347
  const t = playheadInClip(at.clip, time);
4126
- const fallback = _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_LIMITS[property].default;
4127
- if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, prop)) {
4348
+ const fallback = _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_LIMITS[property].default;
4349
+ if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, prop)) {
4128
4350
  const key = prop.keys.find((k) => Math.abs(k.t - t) < 0.5);
4129
4351
  if (key) {
4130
- const rest = _chunkIGPEBXUDcjs.removeVideoKey.call(void 0, prop, key.t);
4131
- return _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
4352
+ const rest = _chunk5T3H7CGGcjs.removeVideoKey.call(void 0, prop, key.t);
4353
+ return _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
4132
4354
  }
4133
4355
  }
4134
- const v = _chunkIGPEBXUDcjs.videoValueAt.call(void 0, prop, t, fallback);
4135
- return { op: "set_keyframes", clip: clipId, property, keys: _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, prop) ? _chunkIGPEBXUDcjs.setVideoKey.call(void 0, prop, { t, v }, fallback).keys : [{ t, v }] };
4356
+ const v = _chunk5T3H7CGGcjs.videoValueAt.call(void 0, prop, t, fallback);
4357
+ return { op: "set_keyframes", clip: clipId, property, keys: _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, prop) ? _chunk5T3H7CGGcjs.setVideoKey.call(void 0, prop, { t, v }, fallback).keys : [{ t, v }] };
4136
4358
  }
4137
4359
  function videoLutEdits(project, clips, lut) {
4138
4360
  const edits = [];
4139
4361
  for (const id of clips) {
4140
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, id);
4362
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, id);
4141
4363
  if (!at) continue;
4142
4364
  const { lut: current, ...rest } = _nullishCoalesce(at.clip.grade, () => ( {}));
4143
4365
  if (!lut && !current) continue;
4144
- const grade = _chunkIGPEBXUDcjs.normalizeVideoGrade.call(void 0, lut ? { ...rest, lut } : rest);
4366
+ const grade = _chunk5T3H7CGGcjs.normalizeVideoGrade.call(void 0, lut ? { ...rest, lut } : rest);
4145
4367
  edits.push(grade ? { op: "update_clip", clip: id, set: { grade } } : { op: "update_clip", clip: id, remove: ["grade"] });
4146
4368
  }
4147
4369
  return edits;
@@ -4162,9 +4384,9 @@ function videoAddAdjustmentEdits(project, time, options = {}) {
4162
4384
  const duration = _nullishCoalesce(options.duration, () => ( 3e3));
4163
4385
  const start = Math.max(0, time);
4164
4386
  const top = project.tracks[0];
4165
- const free = top && top.kind === "video" && !top.locked && !top.clips.some((c) => c.start < start + duration && _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) > start);
4387
+ const free = top && top.kind === "video" && !top.locked && !top.clips.some((c) => c.start < start + duration && _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) > start);
4166
4388
  const edits = [];
4167
- let track = _optionalChain([top, 'optionalAccess', _132 => _132.id]);
4389
+ let track = _optionalChain([top, 'optionalAccess', _145 => _145.id]);
4168
4390
  if (!free) {
4169
4391
  const ids = new Set(project.tracks.map((t) => t.id));
4170
4392
  let n = 1;
@@ -4181,8 +4403,8 @@ function videoMaskEdit(clip, mask) {
4181
4403
  function videoSkinProtectionEdits(project, clips, amount) {
4182
4404
  const edits = [];
4183
4405
  for (const id of clips) {
4184
- const clip = _optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, project, id), 'optionalAccess', _133 => _133.clip]);
4185
- const lut = _optionalChain([clip, 'optionalAccess', _134 => _134.grade, 'optionalAccess', _135 => _135.lut]);
4406
+ const clip = _optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, project, id), 'optionalAccess', _146 => _146.clip]);
4407
+ const lut = _optionalChain([clip, 'optionalAccess', _147 => _147.grade, 'optionalAccess', _148 => _148.lut]);
4186
4408
  if (!clip || !lut) continue;
4187
4409
  const { preserveSkinTones: _p, ...rest } = lut;
4188
4410
  const k = Math.min(1, Math.max(0, amount));
@@ -4215,7 +4437,7 @@ var RIPPLE = {
4215
4437
  };
4216
4438
  var MODE = {
4217
4439
  type: "string",
4218
- enum: [..._chunkIGPEBXUDcjs.VIDEO_PLACEMENT_MODES],
4440
+ enum: [..._chunk5T3H7CGGcjs.VIDEO_PLACEMENT_MODES],
4219
4441
  description: 'What to do with clips already where it lands: "refuse" (default) fails with the next free place; "overwrite" cuts, trims or removes what is underneath on that track; "insert" cuts everything across the start and pushes later material along by its length on this track and every sync-locked track.'
4220
4442
  };
4221
4443
  var DELTA = (what) => ({ type: "number", description: `${what}, in milliseconds of timeline time: positive is later, negative earlier. It is clamped to what the media and neighbours allow; the result says how far it went.` });
@@ -4232,11 +4454,11 @@ var TRANSFORM = object(
4232
4454
  );
4233
4455
  var TRANSITION = object(
4234
4456
  {
4235
- type: { type: "string", enum: _chunkIGPEBXUDcjs.VIDEO_TRANSITION_TYPES.filter((t) => t !== "effect"), description: "crossfade (this clip fades up over the one before), dip (down into a colour and up out of it), wipe (an edge travels across revealing this clip), push (this clip slides in and pushes the one before out), slide (this clip slides in over the one before) or iris (a circle opens from the centre). For a transition effect from the effects provider use set_video_effect_transition." },
4457
+ type: { type: "string", enum: _chunk5T3H7CGGcjs.VIDEO_TRANSITION_TYPES.filter((t) => t !== "effect"), description: "crossfade (this clip fades up over the one before), dip (down into a colour and up out of it), wipe (an edge travels across revealing this clip), push (this clip slides in and pushes the one before out), slide (this clip slides in over the one before) or iris (a circle opens from the centre). For a transition effect from the effects provider use set_video_effect_transition." },
4236
4458
  duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms, centred on the cut. Every type but dip needs half of it in media past the cut on both sides (handles); a dip needs none." },
4237
4459
  color: COLOR("For dip: the colour passed through (default black)"),
4238
- direction: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
4239
- audioCurve: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fades through it: default equal-power for every type but dip (steady loudness while the two sounds overlap), linear for dip; or s-curve, exponential, logarithmic." }
4460
+ direction: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
4461
+ audioCurve: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fades through it: default equal-power for every type but dip (steady loudness while the two sounds overlap), linear for dip; or s-curve, exponential, logarithmic." }
4240
4462
  },
4241
4463
  ["type", "duration"],
4242
4464
  "A transition from the clip that ends where this one starts on the same track."
@@ -4246,7 +4468,7 @@ var LUT_STRENGTH = { type: "number", minimum: 0, maximum: 1, description: "How m
4246
4468
  var SKIN = { type: "number", minimum: 0, maximum: 1, description: "How much of the LUT's change to hold back on skin tones, 0 (none, the default) to 1 (skin keeps its colour); 0.5-0.8 keeps faces natural under a heavy look. Applied in the preview and frame renders; ffmpeg's lut3d cannot, so the export notes it." };
4247
4469
  var GRADE = object(
4248
4470
  {
4249
- ...Object.fromEntries(_chunkIGPEBXUDcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
4471
+ ...Object.fromEntries(_chunk5T3H7CGGcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
4250
4472
  lut: object({ src: LUT_SRC, strength: LUT_STRENGTH, name: { type: "string", minLength: 1, description: "A label for the look." }, preserveSkinTones: SKIN }, ["src"], "A 3D LUT applied after the other settings (set_video_lut checks the file first).")
4251
4473
  },
4252
4474
  [],
@@ -4254,7 +4476,7 @@ var GRADE = object(
4254
4476
  );
4255
4477
  var ANIMATION = (when) => object(
4256
4478
  {
4257
- effect: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_EFFECTS], description: "fade; rise (up into place) or drop (down into place); slide-left / slide-right (moving that way); zoom (grows into place); pop (grows past its size and settles). Each also fades; an exit plays the movement backwards." },
4479
+ effect: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_EFFECTS], description: "fade; rise (up into place) or drop (down into place); slide-left / slide-right (moving that way); zoom (grows into place); pop (grows past its size and settles). Each also fades; an exit plays the movement backwards." },
4258
4480
  duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default 500)." }
4259
4481
  },
4260
4482
  ["effect"],
@@ -4264,11 +4486,11 @@ var CLIP_COMMON = {
4264
4486
  name: { type: "string", description: "A label for the clip." },
4265
4487
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0\u20131 (default 1). A number replaces any keyframes; set_video_keyframes animates it." },
4266
4488
  transform: TRANSFORM,
4267
- fit: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
4489
+ fit: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
4268
4490
  grade: GRADE,
4269
4491
  animateIn: ANIMATION("How the picture enters, from the clip's start (on top of any fade in). Titles usually rise, pop or fade in."),
4270
4492
  animateOut: ANIMATION("How the picture leaves, ending at the clip's end."),
4271
- blend: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_BLEND_MODES], description: "How the picture mixes with what is beneath it, as CSS mix-blend-mode (default normal): multiply darkens (shadows, textures), screen and add lighten (light leaks, flares, glows), overlay and soft-light add contrast, difference and exclusion invert." },
4493
+ blend: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_BLEND_MODES], description: "How the picture mixes with what is beneath it, as CSS mix-blend-mode (default normal): multiply darkens (shadows, textures), screen and add lighten (light leaks, flares, glows), overlay and soft-light add contrast, difference and exclusion invert." },
4272
4494
  fadeIn: MS("Fade up from nothing (picture and sound) over this long"),
4273
4495
  fadeOut: MS("Fade down to nothing over this long")
4274
4496
  };
@@ -4277,8 +4499,8 @@ var MEDIA_FIELDS = {
4277
4499
  speed: { type: "number", minimum: 0.05, maximum: 20, description: "Playback speed (default 1). Changing it keeps the stretch of source, so the clip gets shorter or longer." },
4278
4500
  volume: { type: "number", minimum: 0, maximum: 4, description: "Gain (1 = unchanged, default 1). A number replaces any keyframes; set_video_keyframes animates it." },
4279
4501
  muted: { type: "boolean", description: "Silence this clip (default false)." },
4280
- fadeInCurve: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade in (default linear; the picture always fades linearly): linear, equal-power (steady loudness, best for crossfades), s-curve (gentle at both ends), exponential (slow start, natural from silence) or logarithmic (fast start)." },
4281
- fadeOutCurve: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
4502
+ fadeInCurve: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade in (default linear; the picture always fades linearly): linear, equal-power (steady loudness, best for crossfades), s-curve (gentle at both ends), exponential (slow start, natural from silence) or logarithmic (fast start)." },
4503
+ fadeOutCurve: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
4282
4504
  };
4283
4505
  var TEXT_FIELDS = {
4284
4506
  text: { type: "string", minLength: 1, description: `The title's text ("\\n" breaks lines).` },
@@ -4327,7 +4549,7 @@ var ASSET_FIELDS = {
4327
4549
  };
4328
4550
  var KEY_PROPERTY = {
4329
4551
  type: "string",
4330
- enum: [..._chunkIGPEBXUDcjs.VIDEO_KEYFRAME_PROPERTIES],
4552
+ enum: [..._chunk5T3H7CGGcjs.VIDEO_KEYFRAME_PROPERTIES],
4331
4553
  description: "Which property: opacity (0\u20131), volume (media only, 0\u20134 gain), x / y (pixels from the frame's centre, right / down), scale (1 = fitted size) or rotation (degrees clockwise)."
4332
4554
  };
4333
4555
  var KEYS = {
@@ -4342,7 +4564,7 @@ var KEYS = {
4342
4564
  ease: {
4343
4565
  description: "How the value moves from this key to the next (default linear): linear, hold (stays, then jumps at the next key), ease-in, ease-out, ease-in-out, or CSS cubic-bezier points [x1, y1, x2, y2] with x1 and x2 in 0\u20131.",
4344
4566
  anyOf: [
4345
- { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_EASE_NAMES] },
4567
+ { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_EASE_NAMES] },
4346
4568
  { type: "array", items: { type: "number" }, minItems: 4, maxItems: 4 }
4347
4569
  ]
4348
4570
  }
@@ -4371,19 +4593,19 @@ var describeVideoTracks = (tracks) => tracks.map((t, index) => ({
4371
4593
  ...t.locked ? { locked: true } : {},
4372
4594
  ...t.syncLocked === false ? { syncLocked: false } : {},
4373
4595
  ...t.volume !== void 0 ? { volume: t.volume } : {},
4374
- clips: _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, t).map((c) => ({ ...c, end: _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkIGPEBXUDcjs.videoClipSourceRange.call(void 0, c) } : {} }))
4596
+ clips: _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, t).map((c) => ({ ...c, end: _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunk5T3H7CGGcjs.videoClipSourceRange.call(void 0, c) } : {} }))
4375
4597
  }));
4376
- var videoSequenceUsers = (project, id) => _chunkIGPEBXUDcjs.allVideoTracks.call(void 0, project).flatMap(
4377
- ({ sequence, track }) => track.clips.flatMap((c) => c.type === "sequence" && c.sequence === id ? [{ clip: c.id, ...sequence ? { inSequence: sequence } : {}, track: track.id, start: c.start, end: _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c), source: _chunkIGPEBXUDcjs.videoClipSourceRange.call(void 0, c) }] : [])
4598
+ var videoSequenceUsers = (project, id) => _chunk5T3H7CGGcjs.allVideoTracks.call(void 0, project).flatMap(
4599
+ ({ sequence, track }) => track.clips.flatMap((c) => c.type === "sequence" && c.sequence === id ? [{ clip: c.id, ...sequence ? { inSequence: sequence } : {}, track: track.id, start: c.start, end: _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c), source: _chunk5T3H7CGGcjs.videoClipSourceRange.call(void 0, c) }] : [])
4378
4600
  );
4379
4601
  function describeVideoSequence(project, sequence, tracks = true) {
4380
- const cycle = _chunkIGPEBXUDcjs.findVideoSequenceCycle.call(void 0, project, sequence.id);
4602
+ const cycle = _chunk5T3H7CGGcjs.findVideoSequenceCycle.call(void 0, project, sequence.id);
4381
4603
  return {
4382
4604
  id: sequence.id,
4383
4605
  ...sequence.name ? { name: sequence.name } : {},
4384
- duration: _chunkIGPEBXUDcjs.videoSequenceDuration.call(void 0, sequence),
4606
+ duration: _chunk5T3H7CGGcjs.videoSequenceDuration.call(void 0, sequence),
4385
4607
  clipCount: sequence.tracks.reduce((n, t) => n + t.clips.length, 0),
4386
- nests: _chunkIGPEBXUDcjs.videoSequenceChildren.call(void 0, sequence),
4608
+ nests: _chunk5T3H7CGGcjs.videoSequenceChildren.call(void 0, sequence),
4387
4609
  usedBy: videoSequenceUsers(project, sequence.id),
4388
4610
  ...cycle ? { cycle } : {},
4389
4611
  ...tracks ? { tracks: describeVideoTracks(sequence.tracks) } : { trackCount: sequence.tracks.length }
@@ -4395,11 +4617,11 @@ function describeVideoProject(project) {
4395
4617
  width: project.width,
4396
4618
  height: project.height,
4397
4619
  fps: project.fps,
4398
- duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, project),
4620
+ duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, project),
4399
4621
  ...project.background ? { background: project.background } : {},
4400
4622
  assets: project.assets.map(videoAssetOut),
4401
4623
  tracks: describeVideoTracks(project.tracks),
4402
- ..._optionalChain([project, 'access', _136 => _136.sequences, 'optionalAccess', _137 => _137.length]) ? { sequences: project.sequences.map((q) => describeVideoSequence(project, q, false)) } : {},
4624
+ ..._optionalChain([project, 'access', _149 => _149.sequences, 'optionalAccess', _150 => _150.length]) ? { sequences: project.sequences.map((q) => describeVideoSequence(project, q, false)) } : {},
4403
4625
  markers: _nullishCoalesce(project.markers, () => ( []))
4404
4626
  };
4405
4627
  }
@@ -4412,7 +4634,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4412
4634
  const project = () => controller.getProject();
4413
4635
  const outcome = (result, extra = {}) => {
4414
4636
  if (!result.ok) throw new Error(result.error);
4415
- return { ...extra, duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, result.project), issues: issueSummary(result.issues) };
4637
+ return { ...extra, duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, result.project), issues: issueSummary(result.issues) };
4416
4638
  };
4417
4639
  const apply = (edits, label, extra) => {
4418
4640
  const result = controller.apply(edits, label);
@@ -4421,19 +4643,19 @@ function createVideoEditorToolProvider(controller, options = {}) {
4421
4643
  const clipOut = (p, id) => {
4422
4644
  for (const t of p.tracks) {
4423
4645
  const c = t.clips.find((x) => x.id === id);
4424
- if (c) return { track: t.id, ...c, end: _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkIGPEBXUDcjs.videoClipSourceRange.call(void 0, c) } : {} };
4646
+ if (c) return { track: t.id, ...c, end: _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunk5T3H7CGGcjs.videoClipSourceRange.call(void 0, c) } : {} };
4425
4647
  }
4426
4648
  return null;
4427
4649
  };
4428
4650
  const placed = (o) => ({
4429
- ..._optionalChain([o, 'access', _138 => _138.created, 'optionalAccess', _139 => _139.length]) ? { created: o.created } : {},
4430
- ..._optionalChain([o, 'access', _140 => _140.trimmed, 'optionalAccess', _141 => _141.length]) ? { trimmed: o.trimmed } : {},
4431
- ..._optionalChain([o, 'access', _142 => _142.removed, 'optionalAccess', _143 => _143.length]) ? { removed: o.removed } : {},
4651
+ ..._optionalChain([o, 'access', _151 => _151.created, 'optionalAccess', _152 => _152.length]) ? { created: o.created } : {},
4652
+ ..._optionalChain([o, 'access', _153 => _153.trimmed, 'optionalAccess', _154 => _154.length]) ? { trimmed: o.trimmed } : {},
4653
+ ..._optionalChain([o, 'access', _155 => _155.removed, 'optionalAccess', _156 => _156.length]) ? { removed: o.removed } : {},
4432
4654
  ...o.rippled ? { rippled: o.rippled } : {}
4433
4655
  });
4434
4656
  const keysOut = (p, clip, property) => {
4435
4657
  const c = clipOut(p, clip);
4436
- const value = _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess', _144 => _144.transform, 'optionalAccess', _145 => _145[property]]) : _optionalChain([c, 'optionalAccess', _146 => _146[property]]);
4658
+ const value = _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess', _157 => _157.transform, 'optionalAccess', _158 => _158[property]]) : _optionalChain([c, 'optionalAccess', _159 => _159[property]]);
4437
4659
  return typeof value === "object" ? { keys: value.keys } : { keys: [], value: _nullishCoalesce(value, () => ( null)) };
4438
4660
  };
4439
4661
  const getProject = {
@@ -4455,8 +4677,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
4455
4677
  inputSchema: object({ time: MS("Time from the start (default: the playhead)") }),
4456
4678
  annotations: { title: "What plays at a moment", ...READ },
4457
4679
  handler: ({ time }) => {
4458
- const frame = _chunkIGPEBXUDcjs.videoFrameAt.call(void 0, project(), _nullishCoalesce(time, () => ( controller.getState().time)));
4459
- return { ...frame, timecode: _chunkIGPEBXUDcjs.formatVideoTimecode.call(void 0, frame.time, project().fps) };
4680
+ const frame = _chunk5T3H7CGGcjs.videoFrameAt.call(void 0, project(), _nullishCoalesce(time, () => ( controller.getState().time)));
4681
+ return { ...frame, timecode: _chunk5T3H7CGGcjs.formatVideoTimecode.call(void 0, frame.time, project().fps) };
4460
4682
  }
4461
4683
  };
4462
4684
  const listSequences = {
@@ -4484,7 +4706,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4484
4706
  annotations: { title: "Find gaps", ...READ },
4485
4707
  handler: ({ track }) => {
4486
4708
  if (track !== void 0 && !project().tracks.some((t) => t.id === track)) throw new Error(`There is no track "${track}"; the tracks are ${project().tracks.map((t) => `"${t.id}"`).join(", ")}.`);
4487
- return { gaps: _chunkIGPEBXUDcjs.findVideoGaps.call(void 0, project(), track) };
4709
+ return { gaps: _chunk5T3H7CGGcjs.findVideoGaps.call(void 0, project(), track) };
4488
4710
  }
4489
4711
  };
4490
4712
  const checkProject = {
@@ -4511,10 +4733,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
4511
4733
  annotations: { title: "Render a frame", ...READ },
4512
4734
  handler: async ({ time, times, columns, format = "svg" }) => {
4513
4735
  const p = project();
4514
- const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access', _147 => _147.grade, 'optionalAccess', _148 => _148.lut, 'optionalAccess', _149 => _149.src])).filter((x) => !!x)))];
4736
+ const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access', _160 => _160.grade, 'optionalAccess', _161 => _161.lut, 'optionalAccess', _162 => _162.src])).filter((x) => !!x)))];
4515
4737
  const missing = (await Promise.all(lutSrcs.map((src) => controller.luts.load(src).then(() => null, (e) => e.message)))).filter((m) => !!m);
4516
4738
  const svgOptions = { lutFor: (src) => controller.luts.peek(src), ...columns ? { columns } : {} };
4517
- const svg = times ? _chunkIGPEBXUDcjs.videoContactSheetSvg.call(void 0, p, times, svgOptions) : _chunkIGPEBXUDcjs.videoProjectSvg.call(void 0, p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
4739
+ const svg = times ? _chunk5T3H7CGGcjs.videoContactSheetSvg.call(void 0, p, times, svgOptions) : _chunk5T3H7CGGcjs.videoProjectSvg.call(void 0, p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
4518
4740
  const notes = [...missing.map((m) => `${m}; that LUT is left out of the picture.`), ...lutSrcs.length > missing.length ? ["LUTs are drawn approximately in SVG (curves and a colour matrix); the preview and export apply them exactly."] : []];
4519
4741
  if (format === "png") {
4520
4742
  if (!options.rasterize) throw new Error('This host cannot make PNG images; call render_video_frame with format "svg".');
@@ -4604,7 +4826,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4604
4826
  if (play === true) controller.play();
4605
4827
  if (play === false) controller.pause();
4606
4828
  const state = controller.getState();
4607
- return { time: state.time, timecode: _chunkIGPEBXUDcjs.formatVideoTimecode.call(void 0, state.time, p.fps), playing: state.playing, clips: state.current };
4829
+ return { time: state.time, timecode: _chunk5T3H7CGGcjs.formatVideoTimecode.call(void 0, state.time, p.fps), playing: state.playing, clips: state.current };
4608
4830
  }
4609
4831
  };
4610
4832
  const setSettings = {
@@ -4730,7 +4952,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4730
4952
  inputSchema: object(
4731
4953
  {
4732
4954
  clip: CLIP_ID,
4733
- set: object({ ...CLIP_COMMON, ...MEDIA_FIELDS, asset: { ...ASSET_ID, description: "For media: play another asset (same in point)." }, ...TEXT_FIELDS, color: COLOR("Text colour, or a colour clip's fill"), scope: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_ADJUSTMENT_SCOPES], description: "For adjustment clips: which pictures it changes, underneath (default), all or track." }, targetTrack: { ...TRACK_ID, description: 'For adjustment clips with scope "track": the track whose pictures it changes.' } }, [], "Fields to replace (only those that fit the clip's type)."),
4955
+ set: object({ ...CLIP_COMMON, ...MEDIA_FIELDS, asset: { ...ASSET_ID, description: "For media: play another asset (same in point)." }, ...TEXT_FIELDS, color: COLOR("Text colour, or a colour clip's fill"), scope: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_ADJUSTMENT_SCOPES], description: "For adjustment clips: which pictures it changes, underneath (default), all or track." }, targetTrack: { ...TRACK_ID, description: 'For adjustment clips with scope "track": the track whose pictures it changes.' } }, [], "Fields to replace (only those that fit the clip's type)."),
4734
4956
  remove: { type: "array", items: { type: "string", enum: ["name", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "in", "speed", "volume", "muted", "fontSize", "fontFamily", "fontWeight", "background", "scope", "targetTrack"] }, description: 'Fields to reset to their defaults (an adjustment clip going from scope "track" to another scope must also remove targetTrack).' }
4735
4957
  },
4736
4958
  ["clip"]
@@ -4749,10 +4971,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
4749
4971
  const gradeTargets = (ids) => {
4750
4972
  const p = project();
4751
4973
  for (const id of ids) {
4752
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, p, id);
4974
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, p, id);
4753
4975
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
4754
4976
  const { clip } = at;
4755
- if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access', _150 => _150.assets, 'access', _151 => _151.find, 'call', _152 => _152((a) => a.id === clip.asset), 'optionalAccess', _153 => _153.kind]) === "audio")
4977
+ if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access', _163 => _163.assets, 'access', _164 => _164.find, 'call', _165 => _165((a) => a.id === clip.asset), 'optionalAccess', _166 => _166.kind]) === "audio")
4756
4978
  throw new Error(`Clip "${id}" is sound only; grades change pictures. Pass clips on video tracks.`);
4757
4979
  }
4758
4980
  };
@@ -4763,7 +4985,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4763
4985
  inputSchema: object(
4764
4986
  {
4765
4987
  clips: { type: "array", items: CLIP_ID, minItems: 1, description: "Clips on video tracks to grade." },
4766
- preset: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_GRADE_PRESET_NAMES], description: "The look." },
4988
+ preset: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_GRADE_PRESET_NAMES], description: "The look." },
4767
4989
  amount: { type: "number", minimum: 0, maximum: 1, description: "Strength, 0 (none) to 1 (full, the default); 0.5 is a subtler version." }
4768
4990
  },
4769
4991
  ["clips", "preset"]
@@ -4772,10 +4994,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
4772
4994
  handler: ({ clips, preset, amount }) => {
4773
4995
  gradeTargets(clips);
4774
4996
  const edits = clips.map((clip) => {
4775
- const grade = _chunkIGPEBXUDcjs.videoGradeLook.call(void 0, _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
4997
+ const grade = _chunk5T3H7CGGcjs.videoGradeLook.call(void 0, _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
4776
4998
  return grade ? { op: "update_clip", clip, set: { grade } } : { op: "update_clip", clip, remove: ["grade"] };
4777
4999
  });
4778
- return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _154 => _154.clip, 'access', _155 => _155.grade]), () => ( null)) })) }));
5000
+ return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _167 => _167.clip, 'access', _168 => _168.grade]), () => ( null)) })) }));
4779
5001
  }
4780
5002
  };
4781
5003
  const copyGrade = {
@@ -4786,7 +5008,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4786
5008
  annotations: { title: "Copy a colour grade", ...WRITE_IDEMPOTENT },
4787
5009
  handler: ({ from, to }) => {
4788
5010
  gradeTargets([from, ...to]);
4789
- const grade = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project(), from).clip.grade;
5011
+ const grade = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project(), from).clip.grade;
4790
5012
  const edits = to.map((clip) => grade ? { op: "update_clip", clip, set: { grade: { ...grade } } } : { op: "update_clip", clip, remove: ["grade"] });
4791
5013
  return apply(edits, "Copy grade", () => ({ grade: _nullishCoalesce(grade, () => ( null)), clips: to }));
4792
5014
  }
@@ -4812,7 +5034,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4812
5034
  const lut = await controller.luts.load(src);
4813
5035
  const label = _nullishCoalesce(name, () => ( lut.title));
4814
5036
  const setting = { src, ...strength !== void 0 && strength !== 1 ? { strength } : {}, ...label ? { name: label } : {}, ...preserve_skin_tones ? { preserveSkinTones: preserve_skin_tones } : {} };
4815
- return apply(videoLutEdits(project(), clips, setting), "Apply LUT", (r) => ({ lut: { src, ...lut.title ? { title: lut.title } : {}, size: lut.size }, clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _156 => _156.clip, 'access', _157 => _157.grade]), () => ( null)) })) }));
5037
+ return apply(videoLutEdits(project(), clips, setting), "Apply LUT", (r) => ({ lut: { src, ...lut.title ? { title: lut.title } : {}, size: lut.size }, clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _169 => _169.clip, 'access', _170 => _170.grade]), () => ( null)) })) }));
4816
5038
  }
4817
5039
  };
4818
5040
  const removeLut = {
@@ -4824,9 +5046,9 @@ function createVideoEditorToolProvider(controller, options = {}) {
4824
5046
  handler: ({ clips }) => {
4825
5047
  gradeTargets(clips);
4826
5048
  const p = project();
4827
- const withLut = clips.filter((id) => _optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, p, id), 'access', _158 => _158.clip, 'access', _159 => _159.grade, 'optionalAccess', _160 => _160.lut]));
5049
+ const withLut = clips.filter((id) => _optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, p, id), 'access', _171 => _171.clip, 'access', _172 => _172.grade, 'optionalAccess', _173 => _173.lut]));
4828
5050
  if (!withLut.length) throw new Error(`None of ${clips.map((c) => `"${c}"`).join(", ")} has a LUT; get_video_project shows each clip's grade.`);
4829
- return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _161 => _161.clip, 'access', _162 => _162.grade]), () => ( null)) })) }));
5051
+ return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _174 => _174.clip, 'access', _175 => _175.grade]), () => ( null)) })) }));
4830
5052
  }
4831
5053
  };
4832
5054
  const PROXY_SCALE = { type: "number", exclusiveMinimum: 0, exclusiveMaximum: 1, description: "Proxy size as a fraction of the original: 0.5 (half width and height, the default) or 0.25 for very large footage." };
@@ -4884,7 +5106,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4884
5106
  controller.setPreviewScale(scale);
4885
5107
  const s = controller.getState().previewScale;
4886
5108
  const fixed = s === "full" ? 1 : typeof s === "number" ? s : null;
4887
- const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _163 => _163(a, fixed), 'optionalAccess', _164 => _164.src]), () => ( a.src)), proxy: !!videoAssetProxy(a, fixed) }));
5109
+ const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _176 => _176(a, fixed), 'optionalAccess', _177 => _177.src]), () => ( a.src)), proxy: !!videoAssetProxy(a, fixed) }));
4888
5110
  return { previewScale: s, ...plays ? { plays } : { note: "auto picks the smallest proxy at least as large as the preview canvas shows, so it depends on the preview's size." } };
4889
5111
  }
4890
5112
  };
@@ -4935,7 +5157,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4935
5157
  approximate: parsed.approximate,
4936
5158
  first: list[0],
4937
5159
  last: list[list.length - 1],
4938
- ...a.duration !== void 0 && list[list.length - 1].end > a.duration + _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON ? { warning: `The transcript runs to ${list[list.length - 1].end} ms, past the asset's ${a.duration} ms: is it for this asset?` } : {}
5160
+ ...a.duration !== void 0 && list[list.length - 1].end > a.duration + _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON ? { warning: `The transcript runs to ${list[list.length - 1].end} ms, past the asset's ${a.duration} ms: is it for this asset?` } : {}
4939
5161
  }));
4940
5162
  }
4941
5163
  };
@@ -4953,7 +5175,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4953
5175
  handler: ({ track, from, to, limit }) => {
4954
5176
  const all = timelineWords(track).filter((w) => w.end > (_nullishCoalesce(from, () => ( 0))) && w.start < (_nullishCoalesce(to, () => ( Infinity))));
4955
5177
  const words = all.slice(0, _nullishCoalesce(limit, () => ( 1e3)));
4956
- return { track: _nullishCoalesce(_optionalChain([words, 'access', _165 => _165[0], 'optionalAccess', _166 => _166.track]), () => ( videoTranscriptTrack(project(), track))), text: words.map((w) => w.word).join(" "), words: words.map((w) => ({ word: w.word, start: round(w.start), end: round(w.end), clip: w.clip })), more: all.length > words.length };
5178
+ return { track: _nullishCoalesce(_optionalChain([words, 'access', _178 => _178[0], 'optionalAccess', _179 => _179.track]), () => ( videoTranscriptTrack(project(), track))), text: words.map((w) => w.word).join(" "), words: words.map((w) => ({ word: w.word, start: round(w.start), end: round(w.end), clip: w.clip })), more: all.length > words.length };
4957
5179
  }
4958
5180
  };
4959
5181
  const findText = {
@@ -5006,22 +5228,22 @@ function createVideoEditorToolProvider(controller, options = {}) {
5006
5228
  const bad = ranges.findIndex((r) => !(r.to > r.from));
5007
5229
  if (bad >= 0) throw new Error(`Range ${bad + 1} is empty or backwards (${ranges[bad].from}\u2013${ranges[bad].to} ms); "to" must be after "from".`);
5008
5230
  const merged = mergeVideoRanges(ranges);
5009
- const before = _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, project());
5010
- return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, r.project)), duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, r.project) }));
5231
+ const before = _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, project());
5232
+ return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, r.project)), duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, r.project) }));
5011
5233
  }
5012
5234
  };
5013
5235
  const rampTarget = (id) => {
5014
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project(), id);
5236
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project(), id);
5015
5237
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
5016
5238
  const { clip } = at;
5017
5239
  if (clip.type === "sequence") throw new Error(`Clip "${id}" is a compound clip, which plays its sequence at normal speed; change the speed of the clips inside the sequence instead.`);
5018
- if (clip.type !== "media") throw new Error(`Clip "${id}" is a ${_chunkIGPEBXUDcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to change the speed of; use a video or audio clip.`);
5019
- if (_optionalChain([project, 'call', _167 => _167(), 'access', _168 => _168.assets, 'access', _169 => _169.find, 'call', _170 => _170((a) => a.id === clip.asset), 'optionalAccess', _171 => _171.kind]) === "image") throw new Error(`Clip "${id}" is a still, so it has no motion to change the speed of.`);
5240
+ if (clip.type !== "media") throw new Error(`Clip "${id}" is a ${_chunk5T3H7CGGcjs.videoClipTypeLabel.call(void 0, clip)}, so it has no source to change the speed of; use a video or audio clip.`);
5241
+ if (_optionalChain([project, 'call', _180 => _180(), 'access', _181 => _181.assets, 'access', _182 => _182.find, 'call', _183 => _183((a) => a.id === clip.asset), 'optionalAccess', _184 => _184.kind]) === "image") throw new Error(`Clip "${id}" is a still, so it has no motion to change the speed of.`);
5020
5242
  return clip;
5021
5243
  };
5022
5244
  const rampOut = (r, id) => {
5023
5245
  const outcome2 = r.outcomes[r.outcomes.length - 1];
5024
- return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, r.project) };
5246
+ return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, r.project) };
5025
5247
  };
5026
5248
  const RIPPLE_RAMP = { type: "boolean", description: "Move later material on every sync-locked track by the change in length (default true); false refuses if the clip would overlap the next one." };
5027
5249
  const setSpeedRamp = {
@@ -5052,8 +5274,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
5052
5274
  ),
5053
5275
  annotations: { title: "Ramp the speed", ...WRITE_IDEMPOTENT },
5054
5276
  handler: ({ clip, segments, ripple }) => {
5055
- const edit = _chunkIGPEBXUDcjs.videoSpeedRampEdit.call(void 0, rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
5056
- return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(_chunkIGPEBXUDcjs.videoSpeedRampKeys.call(void 0, segments).source) }));
5277
+ const edit = _chunk5T3H7CGGcjs.videoSpeedRampEdit.call(void 0, rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
5278
+ return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(_chunk5T3H7CGGcjs.videoSpeedRampKeys.call(void 0, segments).source) }));
5057
5279
  }
5058
5280
  };
5059
5281
  const addFreeze = {
@@ -5073,8 +5295,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
5073
5295
  handler: ({ clip, at, duration, ripple }) => {
5074
5296
  const c = rampTarget(clip);
5075
5297
  const t = at - c.start;
5076
- if (t < 0 || t > c.duration) throw new Error(`${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, at)} is outside clip "${clip}" (${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, c.start)}\u2013${_chunkIGPEBXUDcjs.formatVideoSeconds.call(void 0, _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c))}); pick a time inside it.`);
5077
- return apply(_chunkIGPEBXUDcjs.videoFreezeFrameEdit.call(void 0, c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
5298
+ if (t < 0 || t > c.duration) throw new Error(`${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, at)} is outside clip "${clip}" (${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, c.start)}\u2013${_chunk5T3H7CGGcjs.formatVideoSeconds.call(void 0, _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c))}); pick a time inside it.`);
5299
+ return apply(_chunk5T3H7CGGcjs.videoFreezeFrameEdit.call(void 0, c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
5078
5300
  }
5079
5301
  };
5080
5302
  const removeRamp = {
@@ -5247,7 +5469,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
5247
5469
  let from;
5248
5470
  let to;
5249
5471
  if (args.clip !== void 0) {
5250
- const found = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, p, args.clip);
5472
+ const found = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, p, args.clip);
5251
5473
  if (!found) throw new Error(`There is no clip "${args.clip}"; get_video_project lists the clips.`);
5252
5474
  const c = found.clip;
5253
5475
  if (c.type === "sequence") throw new Error(`Clip "${c.id}" is a compound clip; its sound is the mix of its sequence "${c.sequence}", so read the levels of the media in it (list_video_sequences lists its clips and assets).`);
@@ -5257,7 +5479,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
5257
5479
  toSource = (t) => (_nullishCoalesce(c.in, () => ( 0))) + (t - c.start) * speed;
5258
5480
  toOut = (s) => c.start + (s - (_nullishCoalesce(c.in, () => ( 0)))) / speed;
5259
5481
  from = Math.max(c.start, _nullishCoalesce(args.from, () => ( c.start)));
5260
- to = Math.min(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c), _nullishCoalesce(args.to, () => ( _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c))));
5482
+ to = Math.min(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c), _nullishCoalesce(args.to, () => ( _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c))));
5261
5483
  } else {
5262
5484
  asset = p.assets.find((a) => a.id === args.asset);
5263
5485
  if (!asset) throw new Error(`There is no asset "${args.asset}"; the assets are ${p.assets.map((a) => `"${a.id}"`).join(", ") || "none"}.`);
@@ -5338,15 +5560,15 @@ function createVideoEditorToolProvider(controller, options = {}) {
5338
5560
  annotations: { title: "Measure a frame with scopes", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
5339
5561
  handler: async ({ time, bins, columns }) => {
5340
5562
  const p = project();
5341
- const end = _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, p);
5563
+ const end = _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, p);
5342
5564
  const t = _nullishCoalesce(time, () => ( controller.getState().time));
5343
5565
  if (time !== void 0 && time > end) throw new Error(`Time ${time} ms is past the end of the project (${end} ms).`);
5344
5566
  const pixels = await pixelsAt(t);
5345
- return { time: t, timecode: _chunkIGPEBXUDcjs.formatVideoTimecode.call(void 0, t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
5567
+ return { time: t, timecode: _chunk5T3H7CGGcjs.formatVideoTimecode.call(void 0, t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
5346
5568
  }
5347
5569
  };
5348
5570
  const MASK_FIELDS = {
5349
- shape: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_MASK_SHAPES], description: "rectangle (with corner_radius), ellipse, linear (a straight split: the side above the line at rotation 0 shows) or polygon (points)." },
5571
+ shape: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_MASK_SHAPES], description: "rectangle (with corner_radius), ellipse, linear (a straight split: the side above the line at rotation 0 shows) or polygon (points)." },
5350
5572
  x: { type: "number", description: "Centre across the clip's picture, 0 (left edge) to 1 (right edge); default 0.5." },
5351
5573
  y: { type: "number", description: "Centre down the clip's picture, 0 (top) to 1 (bottom); default 0.5." },
5352
5574
  width: { type: "number", minimum: 0, description: "Width as a fraction of the picture's width (default 0.5). Unused by linear." },
@@ -5366,10 +5588,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
5366
5588
  track: { ...TRACK_ID, description: 'A video track to put it on; tracks below it are "underneath".' },
5367
5589
  start: MS("Where it starts on the timeline (default: the end of the track)"),
5368
5590
  duration: { type: "number", exclusiveMinimum: 0, description: "How long it lasts, in ms (default 3000)." },
5369
- scope: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_ADJUSTMENT_SCOPES], description: "Which pictures it changes: underneath (default), all or track." },
5591
+ scope: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_ADJUSTMENT_SCOPES], description: "Which pictures it changes: underneath (default), all or track." },
5370
5592
  target_track: { ...TRACK_ID, description: 'For scope "track" (required then): the track whose pictures it changes.' },
5371
5593
  grade: GRADE,
5372
- preset: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_GRADE_PRESET_NAMES], description: "A named look to start from (grade settings given override it)." },
5594
+ preset: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_GRADE_PRESET_NAMES], description: "A named look to start from (grade settings given override it)." },
5373
5595
  amount: { type: "number", minimum: 0, maximum: 1, description: "Strength of the preset, 0\u20131 (default 1)." },
5374
5596
  name: { type: "string", minLength: 1, description: 'A label for the clip (e.g. "Night look").' },
5375
5597
  id: { type: "string", minLength: 1, description: 'Your own id for the clip (default: a fresh one such as "c7").' },
@@ -5383,13 +5605,13 @@ function createVideoEditorToolProvider(controller, options = {}) {
5383
5605
  if (t && t.kind !== "video") throw new Error(`Track "${track}" is an audio track; adjustment clips change pictures, so put it on a video track.`);
5384
5606
  if (scope === "track" && !target_track) throw new Error('Scope "track" needs target_track: the id of the track whose pictures it changes.');
5385
5607
  if (target_track !== void 0 && scope !== "track") throw new Error('target_track is only for scope "track"; leave it out or set scope to "track".');
5386
- const look = { ...preset ? _chunkIGPEBXUDcjs.videoGradePreset.call(void 0, preset, _nullishCoalesce(amount, () => ( 1))) : {}, ..._nullishCoalesce(grade, () => ( {})) };
5608
+ const look = { ...preset ? _chunk5T3H7CGGcjs.videoGradePreset.call(void 0, preset, _nullishCoalesce(amount, () => ( 1))) : {}, ..._nullishCoalesce(grade, () => ( {})) };
5387
5609
  const clip = { type: "adjustment", ...id ? { id } : {}, ...name ? { name } : {}, ...start !== void 0 ? { start } : {}, duration: _nullishCoalesce(duration, () => ( 3e3)), ...scope ? { scope } : {}, ...target_track ? { targetTrack: target_track } : {}, ...Object.keys(look).length ? { grade: look } : {} };
5388
5610
  return apply({ op: "add_clip", track, clip, mode }, "Add adjustment clip", (r) => ({ clip: clipOut(r.project, r.outcomes[0].clip), ...placed(r.outcomes[0]), ...Object.keys(look).length ? {} : { hint: "It changes nothing yet: give it a grade (update_video_clip), effects (apply_effect) or a mask." } }));
5389
5611
  }
5390
5612
  };
5391
5613
  const maskTarget = (id) => {
5392
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project(), id);
5614
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project(), id);
5393
5615
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
5394
5616
  if (at.track.kind !== "video") throw new Error(`Clip "${id}" is on audio track "${at.track.id}"; masks cut pictures, so pass a clip on a video track.`);
5395
5617
  return at;
@@ -5431,13 +5653,13 @@ function createVideoEditorToolProvider(controller, options = {}) {
5431
5653
  gradeTargets(clips);
5432
5654
  const edits = [];
5433
5655
  for (const id of clips) {
5434
- const clip = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, project(), id).clip;
5435
- const lut = _optionalChain([clip, 'access', _172 => _172.grade, 'optionalAccess', _173 => _173.lut]);
5656
+ const clip = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, project(), id).clip;
5657
+ const lut = _optionalChain([clip, 'access', _185 => _185.grade, 'optionalAccess', _186 => _186.lut]);
5436
5658
  if (!lut) throw new Error(`Clip "${id}" has no LUT to protect skin from; add one with set_video_lut first.`);
5437
5659
  const { preserveSkinTones: _p, ...rest } = lut;
5438
5660
  edits.push({ op: "update_clip", clip: id, set: { grade: { ...clip.grade, lut: amount > 0 ? { ...rest, preserveSkinTones: amount } : rest } } });
5439
5661
  }
5440
- return apply(edits, amount > 0 ? "Protect skin tones" : "Stop protecting skin tones", (r) => ({ clips: clips.map((id) => ({ id, lut: _nullishCoalesce(_optionalChain([_chunkIGPEBXUDcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _174 => _174.clip, 'access', _175 => _175.grade, 'optionalAccess', _176 => _176.lut]), () => ( null)) })) }));
5662
+ return apply(edits, amount > 0 ? "Protect skin tones" : "Stop protecting skin tones", (r) => ({ clips: clips.map((id) => ({ id, lut: _nullishCoalesce(_optionalChain([_chunk5T3H7CGGcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _187 => _187.clip, 'access', _188 => _188.grade, 'optionalAccess', _189 => _189.lut]), () => ( null)) })) }));
5441
5663
  }
5442
5664
  };
5443
5665
  const planOut = (plan) => ({
@@ -5490,7 +5712,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
5490
5712
  handler: ({ plan }) => {
5491
5713
  const r = controller.applyPlan(plan);
5492
5714
  if (!r.ok) throw new Error(r.error);
5493
- return { plan: r.plan.id, title: r.plan.title, stale: r.stale, outcomes: r.outcomes, duration: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, r.project), issues: issueSummary(r.issues) };
5715
+ return { plan: r.plan.id, title: r.plan.title, stale: r.stale, outcomes: r.outcomes, duration: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, r.project), issues: issueSummary(r.issues) };
5494
5716
  }
5495
5717
  };
5496
5718
  const discardPlan = {
@@ -5526,12 +5748,96 @@ function createVideoEditorToolProvider(controller, options = {}) {
5526
5748
  }, options.playbackSurface);
5527
5749
  }
5528
5750
 
5751
+ // src/video-editor/camera-tools.ts
5752
+ var ROLE = {
5753
+ type: "string",
5754
+ enum: ["transition", "hold"],
5755
+ description: 'transition: the move the camera makes into the clip from its start (a glide, whip pan, punch zoom, cut), from "from" to "framing". hold: the move it makes across the rest of the clip (a Ken Burns drift, a crash zoom), at "framing".'
5756
+ };
5757
+ var FRAMING = (what) => ({
5758
+ anyOf: [
5759
+ {
5760
+ type: "object",
5761
+ properties: {
5762
+ zoom: { type: "number", exclusiveMinimum: 0, description: "Zoom on the picture as placed (1 = the whole picture, 2 = half of it fills the frame). Default 1." },
5763
+ x: { type: "number", description: "Point the camera centres on, pixels right of the frame's centre. Default 0." },
5764
+ y: { type: "number", description: "Point the camera centres on, pixels below the frame's centre. Default 0." }
5765
+ },
5766
+ additionalProperties: false
5767
+ },
5768
+ { type: "null" }
5769
+ ],
5770
+ description: `${what} null removes it (the whole picture). Left out, the clip keeps the one it has.`
5771
+ });
5772
+ 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 } : {} });
5773
+ var done = (r) => {
5774
+ if (!r.ok) throw new Error(r.error);
5775
+ const { ok: _ok, ...rest } = r;
5776
+ return { ...rest, ...rest.notes.length ? {} : { notes: void 0 } };
5777
+ };
5778
+ function videoCameraMoveTools(controller, ctx) {
5779
+ return [
5780
+ {
5781
+ name: "list_video_camera_moves",
5782
+ title: "List camera moves for clips",
5783
+ 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), description }] }. Give an id to set_clip_camera_move; describe_effect gives a move's controls and presets. Without a provider that has camera moves it returns available: false and the reason.",
5784
+ inputSchema: { type: "object", properties: { role: ROLE }, additionalProperties: false },
5785
+ annotations: { title: "List camera moves for clips", ...ctx.annotations.read },
5786
+ handler: async (args) => {
5787
+ const provider = controller.effectsProvider;
5788
+ if (!_optionalChain([provider, 'optionalAccess', _190 => _190.capabilities, 'access', _191 => _191.supportsCamera]) || !provider.cameraView)
5789
+ return { available: false, reason: provider ? `${provider.name} has no camera moves (capabilities.supportsCamera is not set).` : "No effects provider is registered, so there are no camera moves.", moves: [] };
5790
+ return { available: true, provider: provider.name, moves: (await controller.cameraMoves(args.role)).map(summary) };
5791
+ }
5792
+ },
5793
+ {
5794
+ name: "set_clip_camera_move",
5795
+ title: "Set a clip's camera move",
5796
+ description: `Plays a camera move from list_video_camera_moves on a clip's picture, the clip being the shot: role transition moves from "from" to "framing" over "ms" from the clip's start; role hold plays across the rest of the clip at "framing". The clip's moves are baked into its x, y, scale and rotation keys, one per frame at the project's fps, and a move that cuts keeps two keys at the cut so nothing tweens across it. A clip whose transform is keyed by hand is refused (clear those keys first). The move is checked first: a wrong-role id, an unknown preset or values outside its controls are refused with the moves or presets that fit. One undo step. Returns { clip, camera, keys (per property), cuts (clip ms), windows ({ in, during }: when each move plays), notes (what a clip transform cannot show: tilt, turn, blur) }. After trimming the clip, set the move again to re-bake it.`,
5797
+ inputSchema: {
5798
+ type: "object",
5799
+ properties: {
5800
+ clip: { type: "string", minLength: 1, description: "A clip id with a picture, from get_video_project." },
5801
+ role: ROLE,
5802
+ move: { type: "string", minLength: 1, description: "A camera move id of that role from list_video_camera_moves." },
5803
+ ms: { type: "number", minimum: 0, maximum: _chunkOPSK22DLcjs.CAMERA_MOVE_MAX_MS, description: `How long a transition takes, ms (default the move's durationMs; at most the clip's length). Not for a hold, which plays across the rest of the clip.` },
5804
+ preset: { type: "string", minLength: 1, description: "A preset of the move by name, from describe_effect." },
5805
+ values: ctx.valuesSchema("Control values over the move's defaults (and the preset's), from describe_effect"),
5806
+ from: FRAMING("Where a transition starts."),
5807
+ framing: FRAMING("Where a transition arrives and a hold plays.")
5808
+ },
5809
+ required: ["clip", "role", "move"],
5810
+ additionalProperties: false
5811
+ },
5812
+ annotations: { title: "Set a clip's camera move", ...ctx.annotations.writeIdempotent },
5813
+ handler: async (args) => {
5814
+ ctx.requireProvider();
5815
+ 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 } : {} };
5816
+ return done(await controller.setClipCameraMove(args.clip, args.role, spec, { from: args.from, framing: args.framing }));
5817
+ }
5818
+ },
5819
+ {
5820
+ name: "clear_clip_camera_move",
5821
+ title: "Clear a clip's camera move",
5822
+ description: "Removes a clip's camera move for a role and re-bakes the other one (which needs the provider); with no move left the clip's transform goes back to what it was before the moves. One undo step. Returns { clip, camera (null when none is left), keys, cuts, windows }.",
5823
+ inputSchema: {
5824
+ type: "object",
5825
+ properties: { clip: { type: "string", minLength: 1, description: "A clip id from get_video_project." }, role: ROLE },
5826
+ required: ["clip", "role"],
5827
+ additionalProperties: false
5828
+ },
5829
+ annotations: { title: "Clear a clip's camera move", ...ctx.annotations.destructive },
5830
+ handler: async (args) => done(await controller.clearClipCameraMove(args.clip, args.role))
5831
+ }
5832
+ ];
5833
+ }
5834
+
5529
5835
  // src/video-editor/effect-tools.ts
5530
5836
  function videoClipAppliedEffects(clip) {
5531
5837
  const out = [];
5532
5838
  const ref = (r) => ({ effect: r.effect, ...r.name ? { name: r.name } : {}, ...r.provider ? { provider: r.provider } : {} });
5533
5839
  if (clip.type === "effect") out.push({ id: "generator", ...ref(clip), role: "effect clip", enabled: true, values: _nullishCoalesce(clip.values, () => ( {})) });
5534
- if (_optionalChain([clip, 'access', _177 => _177.transition, 'optionalAccess', _178 => _178.type]) === "effect" && clip.transition.effect) out.push({ id: "transition", ...ref(clip.transition.effect), role: "transition", enabled: true, values: { ..._nullishCoalesce(clip.transition.effect.values, () => ( {})) }, duration: clip.transition.duration });
5840
+ if (_optionalChain([clip, 'access', _192 => _192.transition, 'optionalAccess', _193 => _193.type]) === "effect" && clip.transition.effect) out.push({ id: "transition", ...ref(clip.transition.effect), role: "transition", enabled: true, values: { ..._nullishCoalesce(clip.transition.effect.values, () => ( {})) }, duration: clip.transition.duration });
5535
5841
  (_nullishCoalesce(clip.effects, () => ( []))).forEach((e, index) => out.push({ id: e.id, ...ref(e), role: "clip effect", enabled: e.enabled !== false, ...e.opacity !== void 0 ? { opacity: e.opacity } : {}, values: _nullishCoalesce(e.values, () => ( {})), index }));
5536
5842
  return out;
5537
5843
  }
@@ -5544,7 +5850,7 @@ var KEYS2 = {
5544
5850
  properties: {
5545
5851
  t: { type: "number", description: "Clip-relative time in ms (0 = the clip's start)." },
5546
5852
  v: { type: "number", description: "The control's value at t, within its range from describe_effect." },
5547
- ease: { anyOf: [{ type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_EASE_NAMES] }, { type: "array", items: { type: "number" }, minItems: 4, maxItems: 4 }], description: "How the value moves to the next key: linear (default), hold, ease-in, ease-out, ease-in-out, or CSS cubic-bezier [x1, y1, x2, y2]." }
5853
+ ease: { anyOf: [{ type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_EASE_NAMES] }, { type: "array", items: { type: "number" }, minItems: 4, maxItems: 4 }], description: "How the value moves to the next key: linear (default), hold, ease-in, ease-out, ease-in-out, or CSS cubic-bezier [x1, y1, x2, y2]." }
5548
5854
  },
5549
5855
  required: ["t", "v"],
5550
5856
  additionalProperties: false
@@ -5558,7 +5864,7 @@ function createVideoEffectsToolProvider(controller, options = {}) {
5558
5864
  return controller.readOnlyReason();
5559
5865
  };
5560
5866
  const clipOf = (id) => {
5561
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, controller.getProject(), id);
5867
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, controller.getProject(), id);
5562
5868
  if (!at) {
5563
5869
  const ids = controller.getProject().tracks.flatMap((t) => t.clips.map((c) => c.id));
5564
5870
  throw new Error(`There is no clip "${id}"; the clips are ${ids.map((c) => `"${c}"`).join(", ") || "none"} (get_video_project lists them).`);
@@ -5568,10 +5874,10 @@ function createVideoEffectsToolProvider(controller, options = {}) {
5568
5874
  const result = (r, target, instance, extra = {}) => {
5569
5875
  if (!r.ok) throw new Error(r.error);
5570
5876
  const effects = videoClipAppliedEffects(clipOf(target));
5571
- const effect = _nullishCoalesce(effects.find((e) => e.id === (_nullishCoalesce(instance, () => ( _optionalChain([r, 'access', _179 => _179.effect, 'optionalAccess', _180 => _180.id]))))), () => ( (r.effect ? { id: r.effect.id, effect: r.effect.effect, role: "clip effect", enabled: r.effect.enabled !== false, values: _nullishCoalesce(r.effect.values, () => ( {})) } : effects[0])));
5877
+ const effect = _nullishCoalesce(effects.find((e) => e.id === (_nullishCoalesce(instance, () => ( _optionalChain([r, 'access', _194 => _194.effect, 'optionalAccess', _195 => _195.id]))))), () => ( (r.effect ? { id: r.effect.id, effect: r.effect.effect, role: "clip effect", enabled: r.effect.enabled !== false, values: _nullishCoalesce(r.effect.values, () => ( {})) } : effects[0])));
5572
5878
  return { target, effect, effects, ...extra };
5573
5879
  };
5574
- return withVideoPlayback(_chunk5MQOBTNPcjs.createEffectToolProvider.call(void 0, {
5880
+ return withVideoPlayback(_chunkOPSK22DLcjs.createEffectToolProvider.call(void 0, {
5575
5881
  id: _nullishCoalesce(options.id, () => ( "video-effects")),
5576
5882
  namespace: options.namespace,
5577
5883
  title: "Video effects",
@@ -5616,6 +5922,7 @@ function createVideoEffectsToolProvider(controller, options = {}) {
5616
5922
  },
5617
5923
  subscribe: (notify) => controller.subscribe(() => notify()),
5618
5924
  extraTools: (ctx) => [
5925
+ ...videoCameraMoveTools(controller, ctx),
5619
5926
  {
5620
5927
  name: "add_video_effect_clip",
5621
5928
  title: "Add an effect clip",
@@ -5629,7 +5936,7 @@ function createVideoEffectsToolProvider(controller, options = {}) {
5629
5936
  duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default: the effect's own length, else 5000)." },
5630
5937
  values: ctx.valuesSchema("Control values over the effect's defaults", true),
5631
5938
  name: { type: "string", minLength: 1, description: "A label for the clip (default: the effect's name)." },
5632
- mode: { type: "string", enum: [..._chunkIGPEBXUDcjs.VIDEO_PLACEMENT_MODES], description: "What to do with clips already there: refuse (default), overwrite or insert." }
5939
+ mode: { type: "string", enum: [..._chunk5T3H7CGGcjs.VIDEO_PLACEMENT_MODES], description: "What to do with clips already there: refuse (default), overwrite or insert." }
5633
5940
  },
5634
5941
  required: ["track", "effect"],
5635
5942
  additionalProperties: false
@@ -5688,8 +5995,8 @@ function createVideoEffectsToolProvider(controller, options = {}) {
5688
5995
  if (args.effect === "generator") {
5689
5996
  const clip = clipOf(args.clip);
5690
5997
  if (clip.type !== "effect") throw new Error(`Clip "${args.clip}" is not an effect clip; give the id of one of its effects (list_applied_effects).`);
5691
- const was = _optionalChain([clip, 'access', _181 => _181.values, 'optionalAccess', _182 => _182[args.control]]);
5692
- const plain = keys === null ? _chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, was) ? _optionalChain([was, 'access', _183 => _183.keys, 'access', _184 => _184[0], 'optionalAccess', _185 => _185.v]) : was : { keys: [...keys].sort((a, b) => a.t - b.t) };
5998
+ const was = _optionalChain([clip, 'access', _196 => _196.values, 'optionalAccess', _197 => _197[args.control]]);
5999
+ const plain = keys === null ? _chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, was) ? _optionalChain([was, 'access', _198 => _198.keys, 'access', _199 => _199[0], 'optionalAccess', _200 => _200.v]) : was : { keys: [...keys].sort((a, b) => a.t - b.t) };
5693
6000
  if (plain === void 0) throw new Error(`"${args.control}" has no value to keep; give keys instead.`);
5694
6001
  r = await controller.updateEffectValues(args.clip, "generator", { [args.control]: plain });
5695
6002
  } else r = await controller.setClipEffectKeyframes(args.clip, args.effect, args.control, keys);
@@ -5767,7 +6074,7 @@ function createVideoDialogueToolProvider(controller, options = {}) {
5767
6074
  const r = controller.proposePlan({ title, description: "Cuts fillers, long pauses and stutters found in the transcript, closing up every sync-locked track.", edits: videoRemoveRangesEdits(cuts), ranges: cuts.map((d) => ({ from: d.from, to: d.to, text: d.text, reason: d.kind })), source: "plan_video_dialogue_cleanup" });
5768
6075
  if (!r.ok) throw new Error(r.error);
5769
6076
  const p = r.plan;
5770
- return { plan: { id: p.id, title: p.title, summary: p.summary, text: describeVideoEditPlan(p), cuts: cuts.length }, durationNow: _chunkIGPEBXUDcjs.videoProjectDuration.call(void 0, controller.getProject()), hint: `Nothing changed yet. Show the user the plan, then call apply_video_edit_plan with plan "${p.id}" (or discard_video_edit_plan).` };
6077
+ return { plan: { id: p.id, title: p.title, summary: p.summary, text: describeVideoEditPlan(p), cuts: cuts.length }, durationNow: _chunk5T3H7CGGcjs.videoProjectDuration.call(void 0, controller.getProject()), hint: `Nothing changed yet. Show the user the plan, then call apply_video_edit_plan with plan "${p.id}" (or discard_video_edit_plan).` };
5771
6078
  }
5772
6079
  };
5773
6080
  return withVideoPlayback(
@@ -5814,7 +6121,7 @@ function createVideoMusicToolProvider(controller, options = {}) {
5814
6121
  };
5815
6122
  const project = () => controller.getProject();
5816
6123
  const soundClip = (p, id) => {
5817
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, p, id);
6124
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, p, id);
5818
6125
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
5819
6126
  const c = at.clip;
5820
6127
  if (c.type !== "media") throw new Error(`Clip "${id}" is a ${c.type} clip and has no sound of its own; pass a video or audio clip.`);
@@ -5830,8 +6137,8 @@ function createVideoMusicToolProvider(controller, options = {}) {
5830
6137
  const { clip, asset: asset2 } = soundClip(p, args.clip);
5831
6138
  const speed = _nullishCoalesce(clip.speed, () => ( 1));
5832
6139
  const from2 = Math.max(clip.start, _nullishCoalesce(args.from, () => ( clip.start)));
5833
- const to2 = Math.min(_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip), _nullishCoalesce(args.to, () => ( _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip))));
5834
- if (!(to2 > from2)) throw new Error(`The stretch is empty (${from2}\u2013${to2} ms); "from" and "to" must be inside the clip (${clip.start}\u2013${_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, clip)} ms) with "to" after "from".`);
6140
+ const to2 = Math.min(_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip), _nullishCoalesce(args.to, () => ( _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip))));
6141
+ if (!(to2 > from2)) throw new Error(`The stretch is empty (${from2}\u2013${to2} ms); "from" and "to" must be inside the clip (${clip.start}\u2013${_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, clip)} ms) with "to" after "from".`);
5835
6142
  return { asset: asset2, from: (_nullishCoalesce(clip.in, () => ( 0))) + (from2 - clip.start) * speed, to: (_nullishCoalesce(clip.in, () => ( 0))) + (to2 - clip.start) * speed, out: (s) => clip.start + (s - (_nullishCoalesce(clip.in, () => ( 0)))) / speed };
5836
6143
  }
5837
6144
  const asset = p.assets.find((a) => a.id === args.asset);
@@ -5873,7 +6180,7 @@ function createVideoMusicToolProvider(controller, options = {}) {
5873
6180
  handler: async ({ clips, target, ceiling, replace }) => {
5874
6181
  const p = project();
5875
6182
  const targets = clips.map((id) => soundClip(p, id));
5876
- for (const t of targets) if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, t.clip.volume) && !replace) throw new Error(`Clip "${t.clip.id}" has volume keyframes, which a constant gain would replace; pass replace: true, or remove them first.`);
6183
+ for (const t of targets) if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, t.clip.volume) && !replace) throw new Error(`Clip "${t.clip.id}" has volume keyframes, which a constant gain would replace; pass replace: true, or remove them first.`);
5877
6184
  const results = [];
5878
6185
  const edits = [];
5879
6186
  for (const { clip, asset } of targets) {
@@ -5918,7 +6225,7 @@ function createVideoMusicToolProvider(controller, options = {}) {
5918
6225
  handler: async (args) => {
5919
6226
  const p = project();
5920
6227
  const music = args.music.map((id) => soundClip(p, id));
5921
- for (const m of music) if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, m.clip.volume) && !args.replace) throw new Error(`Music clip "${m.clip.id}" already has volume keyframes; pass replace: true to replace them, or remove them first.`);
6228
+ for (const m of music) if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, m.clip.volume) && !args.replace) throw new Error(`Music clip "${m.clip.id}" already has volume keyframes; pass replace: true to replace them, or remove them first.`);
5922
6229
  const transcriptTrack = videoTranscriptTrack(p, args.dialogue_track);
5923
6230
  const mode = _nullishCoalesce(args.speech, () => ( (transcriptTrack && videoTimelineTranscript(p, { track: transcriptTrack }).length ? "transcript" : "audio")));
5924
6231
  let ranges = [];
@@ -5931,7 +6238,7 @@ function createVideoMusicToolProvider(controller, options = {}) {
5931
6238
  const track = p.tracks.find((t) => t.id === args.dialogue_track);
5932
6239
  if (!track) throw new Error(`There is no track "${args.dialogue_track}".`);
5933
6240
  const musicIds = new Set(music.map((m) => m.clip.id));
5934
- for (const c of _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track)) {
6241
+ for (const c of _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track)) {
5935
6242
  if (c.type !== "media" || musicIds.has(c.id)) continue;
5936
6243
  const asset = p.assets.find((a) => a.id === c.asset);
5937
6244
  if (!asset || asset.kind === "image" || asset.hasAudio === false) continue;
@@ -5942,10 +6249,10 @@ function createVideoMusicToolProvider(controller, options = {}) {
5942
6249
  let at = c.start;
5943
6250
  for (const s of silences) {
5944
6251
  const a = c.start + (s.start - src0) / speed;
5945
- if (a - at > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) ranges.push({ from: at, to: a });
6252
+ if (a - at > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) ranges.push({ from: at, to: a });
5946
6253
  at = c.start + (s.end - src0) / speed;
5947
6254
  }
5948
- if (_chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) - at > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) ranges.push({ from: at, to: _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, c) });
6255
+ if (_chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) - at > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) ranges.push({ from: at, to: _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, c) });
5949
6256
  }
5950
6257
  if (!ranges.length) throw new Error(`Track "${args.dialogue_track}" has no sound above -40 dBFS, so there is no speech to duck under.`);
5951
6258
  }
@@ -6008,7 +6315,7 @@ function createVideoMusicToolProvider(controller, options = {}) {
6008
6315
  if (!beats.length) throw new Error(`No beats were found in "${args.music}"; try a lower sensitivity, or pass beats.`);
6009
6316
  } else beats = [...args.beats].sort((a, b) => a - b);
6010
6317
  const tolerance = _nullishCoalesce(args.tolerance, () => ( 150));
6011
- const clips = _chunkIGPEBXUDcjs.sortedVideoClips.call(void 0, track);
6318
+ const clips = _chunk5T3H7CGGcjs.sortedVideoClips.call(void 0, track);
6012
6319
  const edits = [];
6013
6320
  const ranges = [];
6014
6321
  const skipped = [];
@@ -6016,8 +6323,8 @@ function createVideoMusicToolProvider(controller, options = {}) {
6016
6323
  for (let i = 0; i + 1 < clips.length; i++) {
6017
6324
  const left = clips[i];
6018
6325
  const right = clips[i + 1];
6019
- const cut = _chunkIGPEBXUDcjs.videoClipEnd.call(void 0, left);
6020
- if (Math.abs(right.start - cut) > _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON) continue;
6326
+ const cut = _chunk5T3H7CGGcjs.videoClipEnd.call(void 0, left);
6327
+ if (Math.abs(right.start - cut) > _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON) continue;
6021
6328
  const beat = nearestVideoBeat(beats, cut, tolerance);
6022
6329
  if (beat === null) {
6023
6330
  skipped.push({ cut: round4(cut), reason: `no beat within ${tolerance} ms` });
@@ -6092,7 +6399,7 @@ function videoClipEffectDocument(clip, instance, providerId) {
6092
6399
  const values = {};
6093
6400
  const tracks = {};
6094
6401
  for (const [control, v] of Object.entries(_nullishCoalesce(effect.values, () => ( {})))) {
6095
- if (_chunkIGPEBXUDcjs.isVideoKeyframes.call(void 0, v)) {
6402
+ if (_chunk5T3H7CGGcjs.isVideoKeyframes.call(void 0, v)) {
6096
6403
  values[control] = v.keys[0].v;
6097
6404
  tracks[control] = v.keys.map((k) => ({ time: k.t, value: k.v, ...k.ease && k.ease !== "linear" ? { easing: videoEaseToAnimationEasing(k.ease) } : {} }));
6098
6405
  } else values[control] = v;
@@ -6133,10 +6440,10 @@ function videoEffectValuesFromDocument(doc) {
6133
6440
  async function openVideoClipEffectAuthoring(controller, clip, instance, options = {}) {
6134
6441
  const provider = controller.effectsProvider;
6135
6442
  if (!provider) throw new Error("No effects provider is registered, so the effect cannot be opened for authoring; register one with setEffectsProvider.");
6136
- const at = _chunkIGPEBXUDcjs.findVideoClip.call(void 0, controller.getProject(), clip);
6443
+ const at = _chunk5T3H7CGGcjs.findVideoClip.call(void 0, controller.getProject(), clip);
6137
6444
  if (!at) throw new Error(`There is no clip "${clip}".`);
6138
6445
  const doc = videoClipEffectDocument(at.clip, instance, provider.id);
6139
- const session = await _chunkK5GXW5TRcjs.createEffectAuthoringSession.call(void 0, { document: doc }, { ...options, provider });
6446
+ const session = await _chunkC73U5UI3cjs.createEffectAuthoringSession.call(void 0, { document: doc }, { ...options, provider });
6140
6447
  return {
6141
6448
  clip,
6142
6449
  instance,
@@ -6477,4 +6784,12 @@ function createVideoEditorDocument(controller) {
6477
6784
 
6478
6785
 
6479
6786
 
6480
- exports.TranscriptVideoController = TranscriptVideoController; exports.VIDEO_ADJUSTMENT_SCOPES = _chunkIGPEBXUDcjs.VIDEO_ADJUSTMENT_SCOPES; exports.VIDEO_ADJUSTMENT_SCOPE_LABELS = VIDEO_ADJUSTMENT_SCOPE_LABELS; exports.VIDEO_BLEND_MODES = _chunkIGPEBXUDcjs.VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = _chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = _chunkIGPEBXUDcjs.VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = _chunkIGPEBXUDcjs.VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_FILLERS = VIDEO_DEFAULT_FILLERS; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_DISFLUENCY_KINDS = VIDEO_DISFLUENCY_KINDS; exports.VIDEO_EASE_NAMES = _chunkIGPEBXUDcjs.VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_EFFECT_PLACES = _chunkIGPEBXUDcjs.VIDEO_EFFECT_PLACES; exports.VIDEO_FADE_CURVES = _chunkIGPEBXUDcjs.VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = _chunkIGPEBXUDcjs.VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = _chunkIGPEBXUDcjs.VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = _chunkIGPEBXUDcjs.VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = _chunkIGPEBXUDcjs.VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = _chunkIGPEBXUDcjs.VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LOUDNESS_HOP = VIDEO_LOUDNESS_HOP; exports.VIDEO_LUT_MAX_SIZE = _chunkIGPEBXUDcjs.VIDEO_LUT_MAX_SIZE; exports.VIDEO_MASK_DEFAULTS = _chunkIGPEBXUDcjs.VIDEO_MASK_DEFAULTS; exports.VIDEO_MASK_SHAPES = _chunkIGPEBXUDcjs.VIDEO_MASK_SHAPES; exports.VIDEO_MASK_SHAPE_LABELS = VIDEO_MASK_SHAPE_LABELS; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = _chunkIGPEBXUDcjs.VIDEO_PLACEMENT_MODES; exports.VIDEO_PREVIEW_SCALE_OPTIONS = VIDEO_PREVIEW_SCALE_OPTIONS; exports.VIDEO_PROXY_SCALES = VIDEO_PROXY_SCALES; exports.VIDEO_SCOPE_KINDS = VIDEO_SCOPE_KINDS; exports.VIDEO_TIME_EPSILON = _chunkIGPEBXUDcjs.VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = _chunkIGPEBXUDcjs.VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = _chunkIGPEBXUDcjs.VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = _chunkIGPEBXUDcjs.VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoEffectsEngine = _chunkIGPEBXUDcjs.VideoEffectsEngine; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = _chunkIGPEBXUDcjs.VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = _chunkIGPEBXUDcjs.allVideoClipIds; exports.allVideoTracks = _chunkIGPEBXUDcjs.allVideoTracks; exports.animationEasingToVideoEase = animationEasingToVideoEase; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = _chunkIGPEBXUDcjs.applyVideoGrade; exports.applyVideoLut = _chunkIGPEBXUDcjs.applyVideoLut; exports.applyVideoLutToPixels = _chunkIGPEBXUDcjs.applyVideoLutToPixels; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoEffectPlace = _chunkIGPEBXUDcjs.checkVideoEffectPlace; exports.checkVideoEffectValues = _chunkIGPEBXUDcjs.checkVideoEffectValues; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = _chunkIGPEBXUDcjs.checkVideoTimeRemap; exports.createVideoDialogueToolProvider = createVideoDialogueToolProvider; exports.createVideoEditorDocument = createVideoEditorDocument; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoEffectsToolProvider = createVideoEffectsToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoMusicToolProvider = createVideoMusicToolProvider; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoEditPlan = describeVideoEditPlan; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.detectVideoDisfluencies = detectVideoDisfluencies; exports.diffVideoProjects = diffVideoProjects; exports.drawVideoFrame = _chunkIGPEBXUDcjs.drawVideoFrame; exports.ffmpegFilterValue = _chunkIGPEBXUDcjs.ffmpegFilterValue; exports.findVideoAudioBeats = findVideoAudioBeats; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = _chunkIGPEBXUDcjs.findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = _chunkIGPEBXUDcjs.findVideoGaps; exports.findVideoRepetitions = findVideoRepetitions; exports.findVideoSequenceClip = _chunkIGPEBXUDcjs.findVideoSequenceClip; exports.findVideoSequenceCycle = _chunkIGPEBXUDcjs.findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = _chunkIGPEBXUDcjs.formatVideoSeconds; exports.formatVideoTimecode = _chunkIGPEBXUDcjs.formatVideoTimecode; exports.formatVideoTimecodeFrames = _chunkIGPEBXUDcjs.formatVideoTimecodeFrames; exports.isVideoDropFrameRate = _chunkIGPEBXUDcjs.isVideoDropFrameRate; exports.isVideoKeyframes = _chunkIGPEBXUDcjs.isVideoKeyframes; exports.measureVideoLoudness = measureVideoLoudness; exports.mergeVideoRanges = mergeVideoRanges; exports.mixEffectPixels = _chunkIGPEBXUDcjs.mixEffectPixels; exports.nearestVideoBeat = nearestVideoBeat; exports.nextFreeVideoSlot = _chunkIGPEBXUDcjs.nextFreeVideoSlot; exports.normalizeVideoClipMask = _chunkIGPEBXUDcjs.normalizeVideoClipMask; exports.normalizeVideoGrade = _chunkIGPEBXUDcjs.normalizeVideoGrade; exports.normalizeVideoGradeLut = _chunkIGPEBXUDcjs.normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.openVideoClipEffectAuthoring = openVideoClipEffectAuthoring; exports.overEffectPixels = _chunkIGPEBXUDcjs.overEffectPixels; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoClipEffects = parseVideoClipEffects; exports.parseVideoClipMask = parseVideoClipMask; exports.parseVideoCubeLut = _chunkIGPEBXUDcjs.parseVideoCubeLut; exports.parseVideoEffectRef = parseVideoEffectRef; exports.parseVideoEffectValues = parseVideoEffectValues; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = _chunkIGPEBXUDcjs.parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRef = parseVideoTimeRef; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = _chunkIGPEBXUDcjs.placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoEdits = planVideoEdits; exports.planVideoPrefetch = planVideoPrefetch; exports.planVideoToolPlayback = planVideoToolPlayback; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = _chunkIGPEBXUDcjs.removeVideoKey; exports.renderVideoFrameExact = _chunkIGPEBXUDcjs.renderVideoFrameExact; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = _chunkIGPEBXUDcjs.retimeVideoAnimatable; exports.setVideoKey = _chunkIGPEBXUDcjs.setVideoKey; exports.snapToVideoFrame = _chunkIGPEBXUDcjs.snapToVideoFrame; exports.snapVideoTime = _chunkIGPEBXUDcjs.snapVideoTime; exports.sortVideoKeys = _chunkIGPEBXUDcjs.sortVideoKeys; exports.sortedVideoClips = _chunkIGPEBXUDcjs.sortedVideoClips; exports.splitVideoAnimatable = _chunkIGPEBXUDcjs.splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = _chunkIGPEBXUDcjs.toVideoEdl; exports.toVideoFfmpeg = _chunkIGPEBXUDcjs.toVideoFfmpeg; exports.toVideoLoudnessMeasure = _chunkIGPEBXUDcjs.toVideoLoudnessMeasure; exports.videoAddAdjustmentEdits = videoAddAdjustmentEdits; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = _chunkIGPEBXUDcjs.videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = _chunkIGPEBXUDcjs.videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioLoudness = videoAudioLoudness; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoAuthorableEffects = videoAuthorableEffects; exports.videoCacheEvictions = videoCacheEvictions; exports.videoChroma = videoChroma; exports.videoClipAfter = _chunkIGPEBXUDcjs.videoClipAfter; exports.videoClipAnimated = _chunkIGPEBXUDcjs.videoClipAnimated; exports.videoClipAnimationProperties = _chunkIGPEBXUDcjs.videoClipAnimationProperties; exports.videoClipAnimationSpans = _chunkIGPEBXUDcjs.videoClipAnimationSpans; exports.videoClipAppliedEffects = videoClipAppliedEffects; exports.videoClipBefore = _chunkIGPEBXUDcjs.videoClipBefore; exports.videoClipEffectDocument = videoClipEffectDocument; exports.videoClipEffectUses = _chunkIGPEBXUDcjs.videoClipEffectUses; exports.videoClipEnd = _chunkIGPEBXUDcjs.videoClipEnd; exports.videoClipHandles = _chunkIGPEBXUDcjs.videoClipHandles; exports.videoClipHeading = videoClipHeading; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = _chunkIGPEBXUDcjs.videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = _chunkIGPEBXUDcjs.videoClipSoundGain; exports.videoClipSourceRange = _chunkIGPEBXUDcjs.videoClipSourceRange; exports.videoClipSourceTime = _chunkIGPEBXUDcjs.videoClipSourceTime; exports.videoClipSpeed = _chunkIGPEBXUDcjs.videoClipSpeed; exports.videoClipSpeedAt = _chunkIGPEBXUDcjs.videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipTypeLabel = _chunkIGPEBXUDcjs.videoClipTypeLabel; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = _chunkIGPEBXUDcjs.videoClipsAt; exports.videoContactSheetSvg = _chunkIGPEBXUDcjs.videoContactSheetSvg; exports.videoCutsWithMargin = videoCutsWithMargin; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoDuckingKeys = videoDuckingKeys; exports.videoEaseBezier = _chunkIGPEBXUDcjs.videoEaseBezier; exports.videoEaseProgress = _chunkIGPEBXUDcjs.videoEaseProgress; exports.videoEaseToAnimationEasing = videoEaseToAnimationEasing; exports.videoEffectFrameTime = _chunkIGPEBXUDcjs.videoEffectFrameTime; exports.videoEffectLayerKey = _chunkIGPEBXUDcjs.videoEffectLayerKey; exports.videoEffectValuesAt = _chunkIGPEBXUDcjs.videoEffectValuesAt; exports.videoEffectValuesFromDocument = videoEffectValuesFromDocument; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = _chunkIGPEBXUDcjs.videoFadeCurveGain; exports.videoFfmpegUnsupportedEffects = _chunkIGPEBXUDcjs.videoFfmpegUnsupportedEffects; exports.videoFfmpegUnsupportedFeatures = _chunkIGPEBXUDcjs.videoFfmpegUnsupportedFeatures; exports.videoFrameAt = _chunkIGPEBXUDcjs.videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = _chunkIGPEBXUDcjs.videoFrameDuration; exports.videoFrameLeafLayers = _chunkIGPEBXUDcjs.videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = _chunkIGPEBXUDcjs.videoFrameToSvg; exports.videoFrames = _chunkIGPEBXUDcjs.videoFrames; exports.videoFreezeFrameEdit = _chunkIGPEBXUDcjs.videoFreezeFrameEdit; exports.videoGradeCssFilter = _chunkIGPEBXUDcjs.videoGradeCssFilter; exports.videoGradeFfmpegFilters = _chunkIGPEBXUDcjs.videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = _chunkIGPEBXUDcjs.videoGradeGainsFilterId; exports.videoGradeLook = _chunkIGPEBXUDcjs.videoGradeLook; exports.videoGradePreset = _chunkIGPEBXUDcjs.videoGradePreset; exports.videoGradeStepMatrix = _chunkIGPEBXUDcjs.videoGradeStepMatrix; exports.videoGradeStepSvgValues = _chunkIGPEBXUDcjs.videoGradeStepSvgValues; exports.videoGradeSteps = _chunkIGPEBXUDcjs.videoGradeSteps; exports.videoGradeSvgDefs = _chunkIGPEBXUDcjs.videoGradeSvgDefs; exports.videoGradeSvgFilter = _chunkIGPEBXUDcjs.videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = _chunkIGPEBXUDcjs.videoHourFrames; exports.videoIrisRadius = _chunkIGPEBXUDcjs.videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyframeBreakpoints = _chunkIGPEBXUDcjs.videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = _chunkIGPEBXUDcjs.videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = _chunkIGPEBXUDcjs.videoKeysOf; exports.videoLayerMask = _chunkIGPEBXUDcjs.videoLayerMask; exports.videoLayersUseEffects = _chunkIGPEBXUDcjs.videoLayersUseEffects; exports.videoLayersWithoutTransitionEffects = _chunkIGPEBXUDcjs.videoLayersWithoutTransitionEffects; exports.videoLoudnessEnergy = videoLoudnessEnergy; exports.videoLoudnessGain = videoLoudnessGain; exports.videoLoudnessOf = videoLoudnessOf; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = _chunkIGPEBXUDcjs.videoLutFromFunction; exports.videoLutSvgApproximation = _chunkIGPEBXUDcjs.videoLutSvgApproximation; exports.videoLutSvgPrimitives = _chunkIGPEBXUDcjs.videoLutSvgPrimitives; exports.videoLutToCube = _chunkIGPEBXUDcjs.videoLutToCube; exports.videoMaskContains = _chunkIGPEBXUDcjs.videoMaskContains; exports.videoMaskEdit = videoMaskEdit; exports.videoMaskPolygon = _chunkIGPEBXUDcjs.videoMaskPolygon; exports.videoMaskSvgPath = _chunkIGPEBXUDcjs.videoMaskSvgPath; exports.videoOverlap = _chunkIGPEBXUDcjs.videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = _chunkIGPEBXUDcjs.videoProjectDuration; exports.videoProjectEffects = _chunkIGPEBXUDcjs.videoProjectEffects; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = _chunkIGPEBXUDcjs.videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = _chunkIGPEBXUDcjs.videoSequenceChildren; exports.videoSequenceDuration = _chunkIGPEBXUDcjs.videoSequenceDuration; exports.videoSequenceMap = _chunkIGPEBXUDcjs.videoSequenceMap; exports.videoShellQuote = _chunkIGPEBXUDcjs.videoShellQuote; exports.videoSkinProtectionEdits = videoSkinProtectionEdits; exports.videoSkinToneWeight = _chunkIGPEBXUDcjs.videoSkinToneWeight; exports.videoSlowMotionRamp = _chunkIGPEBXUDcjs.videoSlowMotionRamp; exports.videoSnapPoints = _chunkIGPEBXUDcjs.videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeechRanges = videoSpeechRanges; exports.videoSpeedRampEdit = _chunkIGPEBXUDcjs.videoSpeedRampEdit; exports.videoSpeedRampKeys = _chunkIGPEBXUDcjs.videoSpeedRampKeys; exports.videoTextStyle = _chunkIGPEBXUDcjs.videoTextStyle; exports.videoTimeRef = videoTimeRef; exports.videoTimeRemapBreakpoints = _chunkIGPEBXUDcjs.videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = _chunkIGPEBXUDcjs.videoTimeRemapSpan; exports.videoTimecodeFrames = _chunkIGPEBXUDcjs.videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = _chunkIGPEBXUDcjs.videoTitleFrame; exports.videoTrackSyncLocked = _chunkIGPEBXUDcjs.videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = _chunkIGPEBXUDcjs.videoTransformAt; exports.videoTransitionAudioCurve = _chunkIGPEBXUDcjs.videoTransitionAudioCurve; exports.videoTransitionEase = _chunkIGPEBXUDcjs.videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = _chunkIGPEBXUDcjs.videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = _chunkIGPEBXUDcjs.videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange; exports.withVideoPlayback = withVideoPlayback;
6787
+
6788
+
6789
+
6790
+
6791
+
6792
+
6793
+
6794
+
6795
+ exports.TranscriptVideoController = TranscriptVideoController; exports.VIDEO_ADJUSTMENT_SCOPES = _chunk5T3H7CGGcjs.VIDEO_ADJUSTMENT_SCOPES; exports.VIDEO_ADJUSTMENT_SCOPE_LABELS = VIDEO_ADJUSTMENT_SCOPE_LABELS; exports.VIDEO_BLEND_MODES = _chunk5T3H7CGGcjs.VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = _chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = _chunk5T3H7CGGcjs.VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = _chunk5T3H7CGGcjs.VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_FILLERS = VIDEO_DEFAULT_FILLERS; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_DISFLUENCY_KINDS = VIDEO_DISFLUENCY_KINDS; exports.VIDEO_EASE_NAMES = _chunk5T3H7CGGcjs.VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_EFFECT_PLACES = _chunk5T3H7CGGcjs.VIDEO_EFFECT_PLACES; exports.VIDEO_FADE_CURVES = _chunk5T3H7CGGcjs.VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = _chunk5T3H7CGGcjs.VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = _chunk5T3H7CGGcjs.VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = _chunk5T3H7CGGcjs.VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = _chunk5T3H7CGGcjs.VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = _chunk5T3H7CGGcjs.VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LOUDNESS_HOP = VIDEO_LOUDNESS_HOP; exports.VIDEO_LUT_MAX_SIZE = _chunk5T3H7CGGcjs.VIDEO_LUT_MAX_SIZE; exports.VIDEO_MASK_DEFAULTS = _chunk5T3H7CGGcjs.VIDEO_MASK_DEFAULTS; exports.VIDEO_MASK_SHAPES = _chunk5T3H7CGGcjs.VIDEO_MASK_SHAPES; exports.VIDEO_MASK_SHAPE_LABELS = VIDEO_MASK_SHAPE_LABELS; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = _chunk5T3H7CGGcjs.VIDEO_PLACEMENT_MODES; exports.VIDEO_PREVIEW_SCALE_OPTIONS = VIDEO_PREVIEW_SCALE_OPTIONS; exports.VIDEO_PROXY_SCALES = VIDEO_PROXY_SCALES; exports.VIDEO_SCOPE_KINDS = VIDEO_SCOPE_KINDS; exports.VIDEO_TIME_EPSILON = _chunk5T3H7CGGcjs.VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = _chunk5T3H7CGGcjs.VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = _chunk5T3H7CGGcjs.VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = _chunk5T3H7CGGcjs.VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoEffectsEngine = _chunk5T3H7CGGcjs.VideoEffectsEngine; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = _chunk5T3H7CGGcjs.VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = _chunk5T3H7CGGcjs.allVideoClipIds; exports.allVideoTracks = _chunk5T3H7CGGcjs.allVideoTracks; exports.animationEasingToVideoEase = animationEasingToVideoEase; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = _chunk5T3H7CGGcjs.applyVideoGrade; exports.applyVideoLut = _chunk5T3H7CGGcjs.applyVideoLut; exports.applyVideoLutToPixels = _chunk5T3H7CGGcjs.applyVideoLutToPixels; exports.bakeVideoClipCamera = bakeVideoClipCamera; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoEffectPlace = _chunk5T3H7CGGcjs.checkVideoEffectPlace; exports.checkVideoEffectValues = _chunk5T3H7CGGcjs.checkVideoEffectValues; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = _chunk5T3H7CGGcjs.checkVideoTimeRemap; exports.createVideoDialogueToolProvider = createVideoDialogueToolProvider; exports.createVideoEditorDocument = createVideoEditorDocument; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoEffectsToolProvider = createVideoEffectsToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoMusicToolProvider = createVideoMusicToolProvider; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoEditPlan = describeVideoEditPlan; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.detectVideoDisfluencies = detectVideoDisfluencies; exports.diffVideoProjects = diffVideoProjects; exports.drawVideoFrame = _chunk5T3H7CGGcjs.drawVideoFrame; exports.ffmpegFilterValue = _chunk5T3H7CGGcjs.ffmpegFilterValue; exports.findVideoAudioBeats = findVideoAudioBeats; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = _chunk5T3H7CGGcjs.findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = _chunk5T3H7CGGcjs.findVideoGaps; exports.findVideoRepetitions = findVideoRepetitions; exports.findVideoSequenceClip = _chunk5T3H7CGGcjs.findVideoSequenceClip; exports.findVideoSequenceCycle = _chunk5T3H7CGGcjs.findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = _chunk5T3H7CGGcjs.formatVideoSeconds; exports.formatVideoTimecode = _chunk5T3H7CGGcjs.formatVideoTimecode; exports.formatVideoTimecodeFrames = _chunk5T3H7CGGcjs.formatVideoTimecodeFrames; exports.isVideoDropFrameRate = _chunk5T3H7CGGcjs.isVideoDropFrameRate; exports.isVideoKeyframes = _chunk5T3H7CGGcjs.isVideoKeyframes; exports.measureVideoLoudness = measureVideoLoudness; exports.mergeVideoRanges = mergeVideoRanges; exports.mixEffectPixels = _chunk5T3H7CGGcjs.mixEffectPixels; exports.nearestVideoBeat = nearestVideoBeat; exports.nextFreeVideoSlot = _chunk5T3H7CGGcjs.nextFreeVideoSlot; exports.normalizeVideoClipMask = _chunk5T3H7CGGcjs.normalizeVideoClipMask; exports.normalizeVideoGrade = _chunk5T3H7CGGcjs.normalizeVideoGrade; exports.normalizeVideoGradeLut = _chunk5T3H7CGGcjs.normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.openVideoClipEffectAuthoring = openVideoClipEffectAuthoring; exports.overEffectPixels = _chunk5T3H7CGGcjs.overEffectPixels; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoClipCamera = parseVideoClipCamera; exports.parseVideoClipEffects = parseVideoClipEffects; exports.parseVideoClipMask = parseVideoClipMask; exports.parseVideoCubeLut = _chunk5T3H7CGGcjs.parseVideoCubeLut; exports.parseVideoEffectRef = parseVideoEffectRef; exports.parseVideoEffectValues = parseVideoEffectValues; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = _chunk5T3H7CGGcjs.parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRef = parseVideoTimeRef; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = _chunk5T3H7CGGcjs.placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoEdits = planVideoEdits; exports.planVideoPrefetch = planVideoPrefetch; exports.planVideoToolPlayback = planVideoToolPlayback; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = _chunk5T3H7CGGcjs.removeVideoKey; exports.renderVideoFrameExact = _chunk5T3H7CGGcjs.renderVideoFrameExact; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = _chunk5T3H7CGGcjs.retimeVideoAnimatable; exports.setVideoKey = _chunk5T3H7CGGcjs.setVideoKey; exports.snapToVideoFrame = _chunk5T3H7CGGcjs.snapToVideoFrame; exports.snapVideoTime = _chunk5T3H7CGGcjs.snapVideoTime; exports.sortVideoKeys = _chunk5T3H7CGGcjs.sortVideoKeys; exports.sortedVideoClips = _chunk5T3H7CGGcjs.sortedVideoClips; exports.splitVideoAnimatable = _chunk5T3H7CGGcjs.splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = _chunk5T3H7CGGcjs.toVideoEdl; exports.toVideoFfmpeg = _chunk5T3H7CGGcjs.toVideoFfmpeg; exports.toVideoLoudnessMeasure = _chunk5T3H7CGGcjs.toVideoLoudnessMeasure; exports.videoAddAdjustmentEdits = videoAddAdjustmentEdits; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = _chunk5T3H7CGGcjs.videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = _chunk5T3H7CGGcjs.videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioLoudness = videoAudioLoudness; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoAuthorableEffects = videoAuthorableEffects; exports.videoCacheEvictions = videoCacheEvictions; exports.videoCameraBase = videoCameraBase; exports.videoCameraMoveTools = videoCameraMoveTools; exports.videoCameraView = videoCameraView; exports.videoChroma = videoChroma; exports.videoClipAfter = _chunk5T3H7CGGcjs.videoClipAfter; exports.videoClipAnimated = _chunk5T3H7CGGcjs.videoClipAnimated; exports.videoClipAnimationProperties = _chunk5T3H7CGGcjs.videoClipAnimationProperties; exports.videoClipAnimationSpans = _chunk5T3H7CGGcjs.videoClipAnimationSpans; exports.videoClipAppliedEffects = videoClipAppliedEffects; exports.videoClipBefore = _chunk5T3H7CGGcjs.videoClipBefore; exports.videoClipCameraMove = videoClipCameraMove; exports.videoClipEffectDocument = videoClipEffectDocument; exports.videoClipEffectUses = _chunk5T3H7CGGcjs.videoClipEffectUses; exports.videoClipEnd = _chunk5T3H7CGGcjs.videoClipEnd; exports.videoClipHandles = _chunk5T3H7CGGcjs.videoClipHandles; exports.videoClipHeading = videoClipHeading; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = _chunk5T3H7CGGcjs.videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = _chunk5T3H7CGGcjs.videoClipSoundGain; exports.videoClipSourceRange = _chunk5T3H7CGGcjs.videoClipSourceRange; exports.videoClipSourceTime = _chunk5T3H7CGGcjs.videoClipSourceTime; exports.videoClipSpeed = _chunk5T3H7CGGcjs.videoClipSpeed; exports.videoClipSpeedAt = _chunk5T3H7CGGcjs.videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipTypeLabel = _chunk5T3H7CGGcjs.videoClipTypeLabel; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = _chunk5T3H7CGGcjs.videoClipsAt; exports.videoContactSheetSvg = _chunk5T3H7CGGcjs.videoContactSheetSvg; exports.videoCutsWithMargin = videoCutsWithMargin; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoDuckingKeys = videoDuckingKeys; exports.videoEaseBezier = _chunk5T3H7CGGcjs.videoEaseBezier; exports.videoEaseProgress = _chunk5T3H7CGGcjs.videoEaseProgress; exports.videoEaseToAnimationEasing = videoEaseToAnimationEasing; exports.videoEffectFrameTime = _chunk5T3H7CGGcjs.videoEffectFrameTime; exports.videoEffectLayerKey = _chunk5T3H7CGGcjs.videoEffectLayerKey; exports.videoEffectValuesAt = _chunk5T3H7CGGcjs.videoEffectValuesAt; exports.videoEffectValuesFromDocument = videoEffectValuesFromDocument; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = _chunk5T3H7CGGcjs.videoFadeCurveGain; exports.videoFfmpegUnsupportedEffects = _chunk5T3H7CGGcjs.videoFfmpegUnsupportedEffects; exports.videoFfmpegUnsupportedFeatures = _chunk5T3H7CGGcjs.videoFfmpegUnsupportedFeatures; exports.videoFrameAt = _chunk5T3H7CGGcjs.videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = _chunk5T3H7CGGcjs.videoFrameDuration; exports.videoFrameLeafLayers = _chunk5T3H7CGGcjs.videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = _chunk5T3H7CGGcjs.videoFrameToSvg; exports.videoFrames = _chunk5T3H7CGGcjs.videoFrames; exports.videoFreezeFrameEdit = _chunk5T3H7CGGcjs.videoFreezeFrameEdit; exports.videoGradeCssFilter = _chunk5T3H7CGGcjs.videoGradeCssFilter; exports.videoGradeFfmpegFilters = _chunk5T3H7CGGcjs.videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = _chunk5T3H7CGGcjs.videoGradeGainsFilterId; exports.videoGradeLook = _chunk5T3H7CGGcjs.videoGradeLook; exports.videoGradePreset = _chunk5T3H7CGGcjs.videoGradePreset; exports.videoGradeStepMatrix = _chunk5T3H7CGGcjs.videoGradeStepMatrix; exports.videoGradeStepSvgValues = _chunk5T3H7CGGcjs.videoGradeStepSvgValues; exports.videoGradeSteps = _chunk5T3H7CGGcjs.videoGradeSteps; exports.videoGradeSvgDefs = _chunk5T3H7CGGcjs.videoGradeSvgDefs; exports.videoGradeSvgFilter = _chunk5T3H7CGGcjs.videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = _chunk5T3H7CGGcjs.videoHourFrames; exports.videoIrisRadius = _chunk5T3H7CGGcjs.videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyTimesProblem = _chunk5T3H7CGGcjs.videoKeyTimesProblem; exports.videoKeyframeBreakpoints = _chunk5T3H7CGGcjs.videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = _chunk5T3H7CGGcjs.videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = _chunk5T3H7CGGcjs.videoKeysOf; exports.videoLayerMask = _chunk5T3H7CGGcjs.videoLayerMask; exports.videoLayersUseEffects = _chunk5T3H7CGGcjs.videoLayersUseEffects; exports.videoLayersWithoutTransitionEffects = _chunk5T3H7CGGcjs.videoLayersWithoutTransitionEffects; exports.videoLoudnessEnergy = videoLoudnessEnergy; exports.videoLoudnessGain = videoLoudnessGain; exports.videoLoudnessOf = videoLoudnessOf; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = _chunk5T3H7CGGcjs.videoLutFromFunction; exports.videoLutSvgApproximation = _chunk5T3H7CGGcjs.videoLutSvgApproximation; exports.videoLutSvgPrimitives = _chunk5T3H7CGGcjs.videoLutSvgPrimitives; exports.videoLutToCube = _chunk5T3H7CGGcjs.videoLutToCube; exports.videoMaskContains = _chunk5T3H7CGGcjs.videoMaskContains; exports.videoMaskEdit = videoMaskEdit; exports.videoMaskPolygon = _chunk5T3H7CGGcjs.videoMaskPolygon; exports.videoMaskSvgPath = _chunk5T3H7CGGcjs.videoMaskSvgPath; exports.videoOverlap = _chunk5T3H7CGGcjs.videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = _chunk5T3H7CGGcjs.videoProjectDuration; exports.videoProjectEffects = _chunk5T3H7CGGcjs.videoProjectEffects; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = _chunk5T3H7CGGcjs.videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = _chunk5T3H7CGGcjs.videoSequenceChildren; exports.videoSequenceDuration = _chunk5T3H7CGGcjs.videoSequenceDuration; exports.videoSequenceMap = _chunk5T3H7CGGcjs.videoSequenceMap; exports.videoShellQuote = _chunk5T3H7CGGcjs.videoShellQuote; exports.videoSkinProtectionEdits = videoSkinProtectionEdits; exports.videoSkinToneWeight = _chunk5T3H7CGGcjs.videoSkinToneWeight; exports.videoSlowMotionRamp = _chunk5T3H7CGGcjs.videoSlowMotionRamp; exports.videoSnapPoints = _chunk5T3H7CGGcjs.videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeechRanges = videoSpeechRanges; exports.videoSpeedRampEdit = _chunk5T3H7CGGcjs.videoSpeedRampEdit; exports.videoSpeedRampKeys = _chunk5T3H7CGGcjs.videoSpeedRampKeys; exports.videoTextStyle = _chunk5T3H7CGGcjs.videoTextStyle; exports.videoTimeRef = videoTimeRef; exports.videoTimeRemapBreakpoints = _chunk5T3H7CGGcjs.videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = _chunk5T3H7CGGcjs.videoTimeRemapSpan; exports.videoTimecodeFrames = _chunk5T3H7CGGcjs.videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = _chunk5T3H7CGGcjs.videoTitleFrame; exports.videoTrackSyncLocked = _chunk5T3H7CGGcjs.videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = _chunk5T3H7CGGcjs.videoTransformAt; exports.videoTransformOfView = videoTransformOfView; exports.videoTransitionAudioCurve = _chunk5T3H7CGGcjs.videoTransitionAudioCurve; exports.videoTransitionEase = _chunk5T3H7CGGcjs.videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = _chunk5T3H7CGGcjs.videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = _chunk5T3H7CGGcjs.videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange; exports.withVideoPlayback = withVideoPlayback;