@pixerate/editor 0.123.0 → 0.124.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 (116) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.js +3 -3
  4. package/dist/animation/index.d.cts +2 -1
  5. package/dist/animation/index.d.ts +2 -1
  6. package/dist/animation-editor/index.cjs.map +1 -1
  7. package/dist/animation-editor/index.d.cts +11 -733
  8. package/dist/animation-editor/index.d.ts +11 -733
  9. package/dist/animation-editor/index.js.map +1 -1
  10. package/dist/{bezier-C-W9LFyD.d.cts → bezier-CBzKKDjl.d.cts} +2 -66
  11. package/dist/{bezier-DQZE5dxA.d.ts → bezier-CWv6LQal.d.ts} +2 -66
  12. package/dist/{brushstrokeRender-M4S65DHT.cjs → brushstrokeRender-EELTV7U4.cjs} +8 -8
  13. package/dist/{brushstrokeRender-M4S65DHT.cjs.map → brushstrokeRender-EELTV7U4.cjs.map} +1 -1
  14. package/dist/{brushstrokeRender-CDDRSV2W.js → brushstrokeRender-LRV7GXGD.js} +3 -3
  15. package/dist/canvas/index.cjs +6 -6
  16. package/dist/canvas/index.d.cts +10 -6
  17. package/dist/canvas/index.d.ts +10 -6
  18. package/dist/canvas/index.js +1 -1
  19. package/dist/{chunk-TVXFHE4T.js → chunk-64PYNEHJ.js} +45 -12
  20. package/dist/chunk-64PYNEHJ.js.map +1 -0
  21. package/dist/{chunk-2IW3BWRT.cjs → chunk-7LQO6OHH.cjs} +2 -2
  22. package/dist/{chunk-2IW3BWRT.cjs.map → chunk-7LQO6OHH.cjs.map} +1 -1
  23. package/dist/chunk-IOXKXQNW.cjs +178 -0
  24. package/dist/chunk-IOXKXQNW.cjs.map +1 -0
  25. package/dist/{chunk-SMJGE7HM.cjs → chunk-IWSMDQE5.cjs} +523 -39
  26. package/dist/chunk-IWSMDQE5.cjs.map +1 -0
  27. package/dist/{chunk-KMBC4HNV.js → chunk-J67OLQUQ.js} +2 -2
  28. package/dist/{chunk-6CJRDJCU.cjs → chunk-PEHYWUVV.cjs} +176 -111
  29. package/dist/chunk-PEHYWUVV.cjs.map +1 -0
  30. package/dist/chunk-TGKT5QAB.js +178 -0
  31. package/dist/chunk-TGKT5QAB.js.map +1 -0
  32. package/dist/chunk-TK53AB4Q.cjs +215 -0
  33. package/dist/chunk-TK53AB4Q.cjs.map +1 -0
  34. package/dist/chunk-VFAKN46Z.js +215 -0
  35. package/dist/chunk-VFAKN46Z.js.map +1 -0
  36. package/dist/{chunk-6ZBR4J62.js → chunk-WATAQ2Z2.js} +79 -14
  37. package/dist/chunk-WATAQ2Z2.js.map +1 -0
  38. package/dist/{chunk-IPFRWILU.js → chunk-YVVSTD3B.js} +499 -15
  39. package/dist/chunk-YVVSTD3B.js.map +1 -0
  40. package/dist/{chunk-RLRUAPBJ.cjs → chunk-Z6OUCS2K.cjs} +47 -14
  41. package/dist/chunk-Z6OUCS2K.cjs.map +1 -0
  42. package/dist/effects/index.cjs +588 -0
  43. package/dist/effects/index.cjs.map +1 -0
  44. package/dist/effects/index.d.cts +131 -0
  45. package/dist/effects/index.d.ts +131 -0
  46. package/dist/effects/index.js +588 -0
  47. package/dist/effects/index.js.map +1 -0
  48. package/dist/evaluate-2S3vSPLy.d.cts +55 -0
  49. package/dist/evaluate-CfmT6xA3.d.ts +55 -0
  50. package/dist/{export-DfjzHAJI.d.ts → export-8RnlngAv.d.ts} +534 -128
  51. package/dist/{export-Dv0-ZVrV.d.ts → export-BzSRXyH6.d.cts} +390 -5
  52. package/dist/{export-Dv0-ZVrV.d.cts → export-DM3h7QEI.d.ts} +390 -5
  53. package/dist/{export-lU5qSpHE.d.cts → export-TqXMOlDt.d.cts} +534 -128
  54. package/dist/flair-CxB3fOcU.d.ts +739 -0
  55. package/dist/flair-D7BxyBwL.d.cts +739 -0
  56. package/dist/gradient-KDfCvhuj.d.cts +66 -0
  57. package/dist/gradient-KDfCvhuj.d.ts +66 -0
  58. package/dist/helpers-777mC6dc.d.cts +253 -0
  59. package/dist/helpers-DX2_7L5t.d.ts +253 -0
  60. package/dist/image-editor/index.cjs +1307 -805
  61. package/dist/image-editor/index.cjs.map +1 -1
  62. package/dist/image-editor/index.d.cts +39 -182
  63. package/dist/image-editor/index.d.ts +39 -182
  64. package/dist/image-editor/index.js +508 -6
  65. package/dist/image-editor/index.js.map +1 -1
  66. package/dist/{opentype-p8Xxf-Wh.d.ts → opentype-14PDI5D2.d.ts} +1 -1
  67. package/dist/{opentype-BV7wWatY.d.cts → opentype-D80AVmMu.d.cts} +1 -1
  68. package/dist/paint/index.cjs +2 -2
  69. package/dist/paint/index.d.cts +32 -10
  70. package/dist/paint/index.d.ts +32 -10
  71. package/dist/paint/index.js +1 -1
  72. package/dist/paint-editor/index.cjs +10 -8
  73. package/dist/paint-editor/index.cjs.map +1 -1
  74. package/dist/paint-editor/index.d.cts +11 -5
  75. package/dist/paint-editor/index.d.ts +11 -5
  76. package/dist/paint-editor/index.js +4 -2
  77. package/dist/paint-editor/index.js.map +1 -1
  78. package/dist/parameters/index.d.cts +4 -184
  79. package/dist/parameters/index.d.ts +4 -184
  80. package/dist/{pathfinder-IxcyhO00.d.cts → pathfinder-C0UoFypx.d.cts} +1 -1
  81. package/dist/{pathfinder-StVChJOT.d.ts → pathfinder-DjISxkUv.d.ts} +1 -1
  82. package/dist/{player-DrcP2xqj.d.cts → player-CBtEoU2x.d.cts} +2 -54
  83. package/dist/{player-DV4Jujdq.d.ts → player-cGLrngL_.d.ts} +2 -54
  84. package/dist/{svg-BtND4TJu.d.cts → svg-BDrjRnL1.d.cts} +3 -2
  85. package/dist/{svg-BfVXG7hL.d.ts → svg-C-vZ3q50.d.ts} +3 -2
  86. package/dist/tools/index.cjs +2 -2
  87. package/dist/tools/index.cjs.map +1 -1
  88. package/dist/tools/index.js +3 -3
  89. package/dist/tools-C7JtLYzo.d.ts +126 -0
  90. package/dist/tools-DHKGHiSK.d.cts +126 -0
  91. package/dist/{types-fuXEme9j.d.ts → types-BcX7sCsn.d.ts} +2 -2
  92. package/dist/{types-DJF3Ghn5.d.cts → types-CznabG7m.d.cts} +2 -2
  93. package/dist/types-D3-J3TFf.d.ts +185 -0
  94. package/dist/types-DMcf_z4J.d.cts +185 -0
  95. package/dist/vector/index.d.cts +10 -10
  96. package/dist/vector/index.d.ts +10 -10
  97. package/dist/video-editor/index.cjs +749 -277
  98. package/dist/video-editor/index.cjs.map +1 -1
  99. package/dist/video-editor/index.d.cts +265 -138
  100. package/dist/video-editor/index.d.ts +265 -138
  101. package/dist/video-editor/index.js +490 -18
  102. package/dist/video-editor/index.js.map +1 -1
  103. package/dist/{warp-BjmAgQwq.d.cts → warp-CH9MM435.d.cts} +1 -1
  104. package/dist/{warp-Ca5fedzS.d.ts → warp-k_PdtXOG.d.ts} +1 -1
  105. package/package.json +6 -1
  106. package/skills/pixerate-image-editor/SKILL.md +7 -0
  107. package/skills/pixerate-image-editor/references/provider-effects.md +35 -0
  108. package/skills/pixerate-video-editor/SKILL.md +39 -1
  109. package/dist/chunk-6CJRDJCU.cjs.map +0 -1
  110. package/dist/chunk-6ZBR4J62.js.map +0 -1
  111. package/dist/chunk-IPFRWILU.js.map +0 -1
  112. package/dist/chunk-RLRUAPBJ.cjs.map +0 -1
  113. package/dist/chunk-SMJGE7HM.cjs.map +0 -1
  114. package/dist/chunk-TVXFHE4T.js.map +0 -1
  115. /package/dist/{brushstrokeRender-CDDRSV2W.js.map → brushstrokeRender-LRV7GXGD.js.map} +0 -0
  116. /package/dist/{chunk-KMBC4HNV.js.map → chunk-J67OLQUQ.js.map} +0 -0
@@ -119,7 +119,30 @@
119
119
 
120
120
 
121
121
 
122
- var _chunkSMJGE7HMcjs = require('../chunk-SMJGE7HM.cjs');
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+ var _chunkIWSMDQE5cjs = require('../chunk-IWSMDQE5.cjs');
138
+
139
+
140
+ var _chunkTK53AB4Qcjs = require('../chunk-TK53AB4Q.cjs');
141
+
142
+
143
+
144
+ var _chunkIOXKXQNWcjs = require('../chunk-IOXKXQNW.cjs');
145
+ require('../chunk-RIWPYSKU.cjs');
123
146
 
124
147
 
125
148
  var _chunkWAJQKWQUcjs = require('../chunk-WAJQKWQU.cjs');
@@ -169,7 +192,7 @@ function parseVideoEase(v, path) {
169
192
  if (v[0] < 0 || v[0] > 1 || v[2] < 0 || v[2] > 1) fail(path, "must have x1 and x2 between 0 and 1");
170
193
  return [v[0], v[1], v[2], v[3]];
171
194
  }
172
- return oneOf(v, _chunkSMJGE7HMcjs.VIDEO_EASE_NAMES, path);
195
+ return oneOf(v, _chunkIWSMDQE5cjs.VIDEO_EASE_NAMES, path);
173
196
  }
174
197
  function parseVideoKeyframes(v, path, { min, max } = {}) {
175
198
  if (!isObject(v)) return fail(path, "must be a number or keyframes { keys: [{ t, v, ease }] }");
@@ -207,7 +230,7 @@ function parseVideoTimeRemap(v, speed, path) {
207
230
  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)");
208
231
  if (speed !== void 0 && speed !== 1) fail(path, 'cannot be used with a speed; a ramp sets the speed itself (remove "speed")');
209
232
  try {
210
- _chunkSMJGE7HMcjs.checkVideoTimeRemap.call(void 0, remap, path);
233
+ _chunkIWSMDQE5cjs.checkVideoTimeRemap.call(void 0, remap, path);
211
234
  } catch (e) {
212
235
  throw new Error(e.message.replace(/\.?$/, "."));
213
236
  }
@@ -217,17 +240,17 @@ function parseVideoClipAnimation(v, path) {
217
240
  if (v === void 0) return void 0;
218
241
  if (!isObject(v)) return fail(path, "must be an object { effect, duration }");
219
242
  return compact({
220
- effect: oneOf(v.effect, _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
243
+ effect: oneOf(v.effect, _chunkIWSMDQE5cjs.VIDEO_CLIP_ANIMATION_EFFECTS, `${path}.effect`, false),
221
244
  duration: num(v.duration, `${path}.duration`, { optional: true, positive: true })
222
245
  });
223
246
  }
224
247
  function parseVideoGrade(v, path) {
225
248
  if (v === void 0) return void 0;
226
249
  if (!isObject(v)) return fail(path, "must be an object such as { exposure, contrast, saturation }");
227
- const known = /* @__PURE__ */ new Set([..._chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
250
+ const known = /* @__PURE__ */ new Set([..._chunkIWSMDQE5cjs.VIDEO_GRADE_CONTROLS.map((c) => c.key), "lut"]);
228
251
  const unknown = Object.keys(v).find((k) => !known.has(k));
229
252
  if (unknown) fail(`${path}.${unknown}`, `is not a grade setting; use ${[...known].join(", ")}`);
230
- return compact({ ...Object.fromEntries(_chunkSMJGE7HMcjs.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`) });
253
+ return compact({ ...Object.fromEntries(_chunkIWSMDQE5cjs.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`) });
231
254
  }
232
255
  function parseVideoGradeLut(v, path) {
233
256
  if (v === void 0) return void 0;
@@ -239,13 +262,52 @@ function parseVideoGradeLut(v, path) {
239
262
  function parseVideoTransition(v, path) {
240
263
  if (v === void 0) return void 0;
241
264
  if (!isObject(v)) return fail(path, "must be an object { type, duration }");
265
+ const type = oneOf(v.type, _chunkIWSMDQE5cjs.VIDEO_TRANSITION_TYPES, `${path}.type`, false);
266
+ if (type === "effect" && v.effect === void 0) fail(`${path}.effect`, 'is required for an effect transition: { effect: "<effect id>", values }');
267
+ if (type !== "effect" && v.effect !== void 0) fail(`${path}.effect`, 'is only for transitions of type "effect"');
242
268
  return compact({
243
- type: oneOf(v.type, _chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES, `${path}.type`, false),
269
+ type,
244
270
  duration: num(v.duration, `${path}.duration`, { positive: true }),
245
271
  color: str(v.color, `${path}.color`, true),
246
- direction: oneOf(v.direction, _chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
247
- audioCurve: oneOf(v.audioCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.audioCurve`)
272
+ direction: oneOf(v.direction, _chunkIWSMDQE5cjs.VIDEO_WIPE_DIRECTIONS, `${path}.direction`),
273
+ audioCurve: oneOf(v.audioCurve, _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES, `${path}.audioCurve`),
274
+ effect: v.effect === void 0 ? void 0 : parseVideoEffectRef(v.effect, `${path}.effect`, false)
275
+ });
276
+ }
277
+ var isEffectValue = (x) => typeof x === "string" || typeof x === "boolean" || typeof x === "number" && Number.isFinite(x) || Array.isArray(x) && x.every((n) => typeof n === "number" && Number.isFinite(n));
278
+ function parseVideoEffectValues(v, path, keyframes = true) {
279
+ if (v === void 0) return void 0;
280
+ if (!isObject(v)) return fail(path, "must be an object of control values from describe_effect");
281
+ const out = {};
282
+ for (const [k, x] of Object.entries(v)) {
283
+ if (isEffectValue(x)) out[k] = Array.isArray(x) ? [...x] : x;
284
+ else if (keyframes && isObject(x)) out[k] = parseVideoKeyframes(x, `${path}.${k}`);
285
+ else fail(`${path}.${k}`, keyframes ? "must be a number, string, true / false, a list of numbers, or keyframes { keys }" : "must be a number, string, true / false or a list of numbers");
286
+ }
287
+ return out;
288
+ }
289
+ function parseVideoEffectRef(v, path, keyframes = true) {
290
+ if (!isObject(v)) return fail(path, "must be an object { effect, values }");
291
+ const unknown = Object.keys(v).find((k) => !["effect", "provider", "name", "values"].includes(k));
292
+ if (unknown) fail(`${path}.${unknown}`, "is not an effect field; use effect, provider, name, values");
293
+ return compact({ effect: str(v.effect, `${path}.effect`), provider: str(v.provider, `${path}.provider`, true), name: str(v.name, `${path}.name`, true), values: parseVideoEffectValues(v.values, `${path}.values`, keyframes) });
294
+ }
295
+ function parseVideoClipEffects(v, path) {
296
+ if (v === void 0) return void 0;
297
+ if (!Array.isArray(v)) return fail(path, "must be a list of effects { id, effect, values }");
298
+ const ids = /* @__PURE__ */ new Set();
299
+ const out = v.map((e, i) => {
300
+ const at = `${path}[${i}]`;
301
+ if (!isObject(e)) return fail(at, "must be an object { id, effect, values }");
302
+ const unknown = Object.keys(e).find((k) => !["id", "effect", "provider", "name", "values", "enabled", "opacity"].includes(k));
303
+ if (unknown) fail(`${at}.${unknown}`, "is not a clip effect field; use id, effect, provider, name, values, enabled, opacity");
304
+ const id = str(e.id, `${at}.id`);
305
+ if (ids.has(id)) fail(`${at}.id`, `repeats "${id}"; each effect on a clip needs its own id`);
306
+ ids.add(id);
307
+ const { effect, provider, name, values } = parseVideoEffectRef({ effect: e.effect, provider: e.provider, name: e.name, values: e.values }, at);
308
+ return compact({ id, effect, provider, name, values, enabled: bool(e.enabled, `${at}.enabled`), opacity: parseVideoAnimatable(e.opacity, `${at}.opacity`, { optional: true, min: 0, max: 1 }) });
248
309
  });
310
+ return out.length ? out : void 0;
249
311
  }
250
312
  function parseVideoTranscriptWords(v, path) {
251
313
  if (v === void 0) return void 0;
@@ -301,7 +363,7 @@ function parseVideoAssetProxies(v, path) {
301
363
  }
302
364
  function parseVideoClip(v, path = "clip") {
303
365
  if (!isObject(v)) return fail(path, "must be an object");
304
- const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), _chunkSMJGE7HMcjs.VIDEO_CLIP_TYPES, `${path}.type`, false);
366
+ const type = oneOf(_nullishCoalesce(v.type, () => ( "media")), _chunkIWSMDQE5cjs.VIDEO_CLIP_TYPES, `${path}.type`, false);
305
367
  const base = {
306
368
  id: str(v.id, `${path}.id`),
307
369
  name: str(v.name, `${path}.name`, true),
@@ -309,14 +371,15 @@ function parseVideoClip(v, path = "clip") {
309
371
  duration: num(v.duration, `${path}.duration`, { positive: true }),
310
372
  opacity: parseVideoAnimatable(v.opacity, `${path}.opacity`, { optional: true, min: 0, max: 1 }),
311
373
  transform: parseVideoTransform(v.transform, `${path}.transform`),
312
- fit: oneOf(v.fit, _chunkSMJGE7HMcjs.VIDEO_FITS, `${path}.fit`),
313
- blend: oneOf(v.blend, _chunkSMJGE7HMcjs.VIDEO_BLEND_MODES, `${path}.blend`),
374
+ fit: oneOf(v.fit, _chunkIWSMDQE5cjs.VIDEO_FITS, `${path}.fit`),
375
+ blend: oneOf(v.blend, _chunkIWSMDQE5cjs.VIDEO_BLEND_MODES, `${path}.blend`),
314
376
  grade: parseVideoGrade(v.grade, `${path}.grade`),
315
377
  animateIn: parseVideoClipAnimation(v.animateIn, `${path}.animateIn`),
316
378
  animateOut: parseVideoClipAnimation(v.animateOut, `${path}.animateOut`),
317
379
  fadeIn: num(v.fadeIn, `${path}.fadeIn`, { optional: true, min: 0 }),
318
380
  fadeOut: num(v.fadeOut, `${path}.fadeOut`, { optional: true, min: 0 }),
319
- transition: parseVideoTransition(v.transition, `${path}.transition`)
381
+ transition: parseVideoTransition(v.transition, `${path}.transition`),
382
+ effects: parseVideoClipEffects(v.effects, `${path}.effects`)
320
383
  };
321
384
  if (type === "media")
322
385
  return compact({
@@ -328,8 +391,8 @@ function parseVideoClip(v, path = "clip") {
328
391
  volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
329
392
  muted: bool(v.muted, `${path}.muted`),
330
393
  timeRemap: parseVideoTimeRemap(v.timeRemap, v.speed, `${path}.timeRemap`),
331
- fadeInCurve: oneOf(v.fadeInCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
332
- fadeOutCurve: oneOf(v.fadeOutCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
394
+ fadeInCurve: oneOf(v.fadeInCurve, _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
395
+ fadeOutCurve: oneOf(v.fadeOutCurve, _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
333
396
  });
334
397
  if (type === "sequence") {
335
398
  for (const key of ["speed", "timeRemap"])
@@ -341,8 +404,8 @@ function parseVideoClip(v, path = "clip") {
341
404
  in: num(v.in, `${path}.in`, { optional: true, min: 0 }),
342
405
  volume: parseVideoAnimatable(v.volume, `${path}.volume`, { optional: true, min: 0, max: 4 }),
343
406
  muted: bool(v.muted, `${path}.muted`),
344
- fadeInCurve: oneOf(v.fadeInCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
345
- fadeOutCurve: oneOf(v.fadeOutCurve, _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
407
+ fadeInCurve: oneOf(v.fadeInCurve, _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES, `${path}.fadeInCurve`),
408
+ fadeOutCurve: oneOf(v.fadeOutCurve, _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES, `${path}.fadeOutCurve`)
346
409
  });
347
410
  }
348
411
  if (type === "text")
@@ -356,6 +419,10 @@ function parseVideoClip(v, path = "clip") {
356
419
  fontWeight: num(v.fontWeight, `${path}.fontWeight`, { optional: true, min: 100, max: 1e3 }),
357
420
  background: str(v.background, `${path}.background`, true)
358
421
  });
422
+ if (type === "effect") {
423
+ const ref = parseVideoEffectRef({ effect: v.effect, provider: v.provider, name: v.name === void 0 ? void 0 : v.name, values: v.values }, path);
424
+ return compact({ type, ...base, ...ref, name: base.name });
425
+ }
359
426
  return compact({ type, ...base, color: str(v.color, `${path}.color`) });
360
427
  }
361
428
  function parseVideoTrack(v, path = "track") {
@@ -449,9 +516,9 @@ function createVideoProject(options = {}) {
449
516
  // src/video-editor/check.ts
450
517
  function videoClipKeyframes(clip) {
451
518
  const out = [
452
- { property: "opacity", keys: _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, clip.opacity) },
453
- { property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, clip.volume) : [] },
454
- ..._chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _2 => _2.transform, 'optionalAccess', _3 => _3[p]])) }))
519
+ { property: "opacity", keys: _chunkIWSMDQE5cjs.videoKeysOf.call(void 0, clip.opacity) },
520
+ { property: "volume", keys: clip.type === "media" || clip.type === "sequence" ? _chunkIWSMDQE5cjs.videoKeysOf.call(void 0, clip.volume) : [] },
521
+ ..._chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES.map((p) => ({ property: p, keys: _chunkIWSMDQE5cjs.videoKeysOf.call(void 0, _optionalChain([clip, 'access', _2 => _2.transform, 'optionalAccess', _3 => _3[p]])) }))
455
522
  ];
456
523
  return out.filter((o) => o.keys.length);
457
524
  }
@@ -478,8 +545,8 @@ var VIDEO_ISSUE_CODES = [
478
545
  var videoIssueKey = (i) => [i.code, _nullishCoalesce(i.sequence, () => ( "")), _nullishCoalesce(i.track, () => ( "")), _nullishCoalesce(i.clip, () => ( "")), _nullishCoalesce(i.asset, () => ( "")), _nullishCoalesce(i.marker, () => ( ""))].join("|");
479
546
  function checkVideoProject(project) {
480
547
  const issues = [];
481
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
482
- const sequences = _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, project);
548
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, project);
549
+ const sequences = _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, project);
483
550
  const used = /* @__PURE__ */ new Set();
484
551
  const usedSequences = /* @__PURE__ */ new Set();
485
552
  const cycles = /* @__PURE__ */ new Map();
@@ -487,7 +554,7 @@ function checkVideoProject(project) {
487
554
  if ((asset.kind === "video" || asset.kind === "audio") && asset.duration === void 0)
488
555
  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.` });
489
556
  const checkTrack = (track, sequence) => {
490
- const clips = _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track);
557
+ const clips = _chunkIWSMDQE5cjs.sortedVideoClips.call(void 0, track);
491
558
  const where = sequence ? ` in sequence "${sequence}"` : "";
492
559
  for (let i = 0; i < clips.length; i++) {
493
560
  const clip = clips[i];
@@ -497,13 +564,13 @@ function checkVideoProject(project) {
497
564
  const seq = sequences.get(clip.sequence);
498
565
  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.` });
499
566
  else {
500
- if (!cycles.has(seq.id)) cycles.set(seq.id, _chunkSMJGE7HMcjs.findVideoSequenceCycle.call(void 0, project, seq.id));
567
+ if (!cycles.has(seq.id)) cycles.set(seq.id, _chunkIWSMDQE5cjs.findVideoSequenceCycle.call(void 0, project, seq.id));
501
568
  const cycle = cycles.get(seq.id);
502
569
  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.` });
503
- const length = _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, seq);
504
- const range = _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, clip);
505
- if (range.out > length + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
506
- issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, range.out)} of sequence "${seq.id}", which is only ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, length)} long; shorten the clip or move its in point.` });
570
+ const length = _chunkIWSMDQE5cjs.videoSequenceDuration.call(void 0, seq);
571
+ const range = _chunkIWSMDQE5cjs.videoClipSourceRange.call(void 0, clip);
572
+ if (range.out > length + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
573
+ issues.push({ code: "source-overrun", severity: "error", ...at, message: `Compound clip "${clip.id}" plays to ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, range.out)} of sequence "${seq.id}", which is only ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, length)} long; shorten the clip or move its in point.` });
507
574
  }
508
575
  } else if (clip.type === "media") {
509
576
  used.add(clip.asset);
@@ -512,28 +579,28 @@ function checkVideoProject(project) {
512
579
  else {
513
580
  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.` });
514
581
  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.` });
515
- const range = _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, clip);
516
- if (asset.duration !== void 0 && range.out > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
517
- issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, range.out)} of "${asset.id}", which is only ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, asset.duration)} long; shorten the clip or move its in point.` });
582
+ const range = _chunkIWSMDQE5cjs.videoClipSourceRange.call(void 0, clip);
583
+ if (asset.duration !== void 0 && range.out > asset.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
584
+ issues.push({ code: "source-overrun", severity: "error", ...at, message: `Clip "${clip.id}" plays to ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, range.out)} of "${asset.id}", which is only ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, asset.duration)} long; shorten the clip or move its in point.` });
518
585
  }
519
586
  } 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.` });
520
587
  const next = clips[i + 1];
521
- if (next && next.start < _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
522
- issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, next.start)}; move one of them.` });
523
- if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
588
+ if (next && next.start < _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip) - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
589
+ issues.push({ code: "overlap", severity: "error", ...at, message: `Clips "${clip.id}" and "${next.id}" overlap on track "${track.id}"${where} from ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, next.start)}; move one of them.` });
590
+ if ((_nullishCoalesce(clip.fadeIn, () => ( 0))) + (_nullishCoalesce(clip.fadeOut, () => ( 0))) > clip.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
524
591
  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.` });
525
- const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0);
526
- if (anim > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
592
+ const anim = (clip.animateIn ? _nullishCoalesce(clip.animateIn.duration, () => ( _chunkIWSMDQE5cjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0) + (clip.animateOut ? _nullishCoalesce(clip.animateOut.duration, () => ( _chunkIWSMDQE5cjs.VIDEO_CLIP_ANIMATION_DURATION)) : 0);
593
+ if (anim > clip.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
527
594
  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.` });
528
595
  for (const which of ["animateIn", "animateOut"]) {
529
596
  const a = clip[which];
530
597
  if (!a) continue;
531
- const keyed = _chunkSMJGE7HMcjs.videoClipAnimationProperties.call(void 0, a).filter((p) => _chunkSMJGE7HMcjs.videoKeysOf.call(void 0, p === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _4 => _4.transform, 'optionalAccess', _5 => _5[p]])).length);
598
+ const keyed = _chunkIWSMDQE5cjs.videoClipAnimationProperties.call(void 0, a).filter((p) => _chunkIWSMDQE5cjs.videoKeysOf.call(void 0, p === "opacity" ? clip.opacity : _optionalChain([clip, 'access', _4 => _4.transform, 'optionalAccess', _5 => _5[p]])).length);
532
599
  if (keyed.length)
533
600
  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.` });
534
601
  }
535
602
  for (const { property, keys } of videoClipKeyframes(clip)) {
536
- const outside = keys.filter((k) => k.t < -_chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || k.t > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON);
603
+ const outside = keys.filter((k) => k.t < -_chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON || k.t > clip.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON);
537
604
  if (outside.length)
538
605
  issues.push({
539
606
  code: "keyframes-outside-clip",
@@ -544,20 +611,20 @@ function checkVideoProject(project) {
544
611
  }
545
612
  if (clip.transition) {
546
613
  const d = clip.transition.duration;
547
- const before = _chunkSMJGE7HMcjs.videoClipBefore.call(void 0, track, clip);
614
+ const before = _chunkIWSMDQE5cjs.videoClipBefore.call(void 0, track, clip);
548
615
  if (!before) {
549
616
  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.` });
550
617
  continue;
551
618
  }
552
- if (d > clip.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || d > before.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
619
+ if (d > clip.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON || d > before.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) {
553
620
  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.` });
554
621
  continue;
555
622
  }
556
623
  if (clip.transition.type === "dip") continue;
557
- const outgoing = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, before, assets, sequences).after;
558
- const incoming = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, clip, assets, sequences).before;
624
+ const outgoing = _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, before, assets, sequences).after;
625
+ const incoming = _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, clip, assets, sequences).before;
559
626
  const half = d / 2;
560
- if (outgoing < half - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || incoming < half - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
627
+ if (outgoing < half - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON || incoming < half - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) {
561
628
  const fits = 2 * Math.min(outgoing, incoming);
562
629
  issues.push({
563
630
  code: "transition-handles",
@@ -574,9 +641,9 @@ function checkVideoProject(project) {
574
641
  for (const sequence of _nullishCoalesce(project.sequences, () => ( [])))
575
642
  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.` });
576
643
  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.` });
577
- const end = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project);
644
+ const end = _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, project);
578
645
  for (const marker of _nullishCoalesce(project.markers, () => ( [])))
579
- if (marker.time > end + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, marker.time)} is past the end (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}).` });
646
+ if (marker.time > end + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) issues.push({ code: "marker-past-end", severity: "note", marker: marker.id, message: `Marker "${marker.id}" at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, marker.time)} is past the end (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, end)}).` });
580
647
  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." });
581
648
  const rank = { error: 0, warning: 1, note: 2 };
582
649
  return issues.sort((a, b) => rank[a.severity] - rank[b.severity]);
@@ -630,7 +697,7 @@ function mergeSpans(spans) {
630
697
  const out = [];
631
698
  for (const [from, to] of [...spans].sort((a, b) => a[0] - b[0])) {
632
699
  const last = out[out.length - 1];
633
- if (last && from <= last[1] + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
700
+ if (last && from <= last[1] + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) last[1] = Math.max(last[1], to);
634
701
  else out.push([from, to]);
635
702
  }
636
703
  return out;
@@ -644,16 +711,16 @@ function clipAnimatables(clip) {
644
711
  // A speed ramp is keys in clip time too, so trims and splits keep it on the same frames of source.
645
712
  { get: () => c.timeRemap, set: (v) => c.timeRemap = v }
646
713
  ];
647
- for (const p of _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access', _6 => _6.transform, 'optionalAccess', _7 => _7[p]]), set: (v) => c.transform && (c.transform[p] = v) });
714
+ for (const p of _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES) out.push({ get: () => _optionalChain([c, 'access', _6 => _6.transform, 'optionalAccess', _7 => _7[p]]), set: (v) => c.transform && (c.transform[p] = v) });
648
715
  return out;
649
716
  }
650
717
  function retimeClipKeys(clip, fn) {
651
718
  for (const a of clipAnimatables(clip)) {
652
719
  const v = a.get();
653
- if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, v)) a.set(fn(v));
720
+ if (_chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, v)) a.set(fn(v));
654
721
  }
655
722
  }
656
- var OPTIONAL_CLIP_FIELDS = ["name", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "transition", "in", "speed", "timeRemap", "volume", "muted", "color", "fontSize", "fontFamily", "fontWeight", "background"];
723
+ var OPTIONAL_CLIP_FIELDS = ["name", "effects", "values", "provider", "opacity", "transform", "fit", "blend", "grade", "animateIn", "animateOut", "fadeIn", "fadeOut", "fadeInCurve", "fadeOutCurve", "transition", "in", "speed", "timeRemap", "volume", "muted", "color", "fontSize", "fontFamily", "fontWeight", "background"];
657
724
  var TIME_FIELDS = { slip_clip: ["delta"], roll_edit: ["delta"], slide_clip: ["delta"], lift_range: ["from", "to"], extract_range: ["from", "to"], split_at: ["at"] };
658
725
  var Editor = (_class = class {
659
726
  constructor(p) {;_class.prototype.__init.call(this);
@@ -667,8 +734,8 @@ var Editor = (_class = class {
667
734
  return t;
668
735
  }
669
736
  clip(id) {
670
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, this.p, id);
671
- const nested = at ? null : _chunkSMJGE7HMcjs.findVideoSequenceClip.call(void 0, this.p, id);
737
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, this.p, id);
738
+ const nested = at ? null : _chunkIWSMDQE5cjs.findVideoSequenceClip.call(void 0, this.p, id);
672
739
  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).`);
673
740
  if (!at) {
674
741
  const ids = this.p.tracks.flatMap((t) => t.clips.map((c) => c.id));
@@ -685,10 +752,10 @@ var Editor = (_class = class {
685
752
  return a;
686
753
  }
687
754
  fits(track, start, duration, ignore, what) {
688
- const hit = _chunkSMJGE7HMcjs.videoOverlap.call(void 0, track, start, start + duration, ignore);
755
+ const hit = _chunkIWSMDQE5cjs.videoOverlap.call(void 0, track, start, start + duration, ignore);
689
756
  if (hit) {
690
- const free = _chunkSMJGE7HMcjs.nextFreeVideoSlot.call(void 0, track, start, duration, ignore);
691
- refuse(`${what} at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, start + duration)} would overlap clip "${hit.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, hit))}) on track "${track.id}"; the next free place is ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
757
+ const free = _chunkIWSMDQE5cjs.nextFreeVideoSlot.call(void 0, track, start, duration, ignore);
758
+ refuse(`${what} at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, start)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, start + duration)} would overlap clip "${hit.id}" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, hit))}) on track "${track.id}"; the next free place is ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, free)}, or use mode "insert" to push later clips along or "overwrite" to replace what is there.`);
692
759
  }
693
760
  }
694
761
  kindFits(track, clip) {
@@ -704,14 +771,14 @@ var Editor = (_class = class {
704
771
  /** Moves every clip on `track` starting at or after `from` by `delta`. */
705
772
  shift(track, from, delta, except = /* @__PURE__ */ new Set()) {
706
773
  if (!delta) return;
707
- for (const c of track.clips) if (!except.has(c.id) && c.start >= from - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
774
+ for (const c of track.clips) if (!except.has(c.id) && c.start >= from - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) c.start = Math.max(0, c.start + delta);
708
775
  track.clips.sort((a, b) => a.start - b.start);
709
776
  }
710
777
  get frame() {
711
778
  return 1e3 / this.p.fps;
712
779
  }
713
780
  ids() {
714
- return _chunkSMJGE7HMcjs.allVideoClipIds.call(void 0, this.p);
781
+ return _chunkIWSMDQE5cjs.allVideoClipIds.call(void 0, this.p);
715
782
  }
716
783
  /**
717
784
  * The tracks a ripple on `sources` moves, top to bottom: the sources, and every unlocked
@@ -719,8 +786,8 @@ var Editor = (_class = class {
719
786
  */
720
787
  rippleTracks(sources) {
721
788
  const set = new Set(sources);
722
- if ([...set].some(_chunkSMJGE7HMcjs.videoTrackSyncLocked)) {
723
- for (const t of this.p.tracks) if (_chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, t) && !t.locked) set.add(t);
789
+ if ([...set].some(_chunkIWSMDQE5cjs.videoTrackSyncLocked)) {
790
+ for (const t of this.p.tracks) if (_chunkIWSMDQE5cjs.videoTrackSyncLocked.call(void 0, t) && !t.locked) set.add(t);
724
791
  }
725
792
  return this.p.tracks.filter((t) => set.has(t));
726
793
  }
@@ -737,7 +804,7 @@ var Editor = (_class = class {
737
804
  return open;
738
805
  }
739
806
  range(from, to) {
740
- if (!(to - from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)) refuse(`"to" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, to)}) must be after "from" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, from)}).`);
807
+ if (!(to - from > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)) refuse(`"to" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, to)}) must be after "from" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, from)}).`);
741
808
  }
742
809
  /** Moves a media or compound clip's in point by `delta` of timeline time (stills, titles and colours have none). */
743
810
  moveIn(clip, delta) {
@@ -746,18 +813,18 @@ var Editor = (_class = class {
746
813
  if (clip.in < 1e-9) delete clip.in;
747
814
  return;
748
815
  }
749
- if (clip.type !== "media" || _optionalChain([_chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p), 'access', _9 => _9.get, 'call', _10 => _10(clip.asset), 'optionalAccess', _11 => _11.kind]) === "image") return;
750
- clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip));
816
+ if (clip.type !== "media" || _optionalChain([_chunkIWSMDQE5cjs.videoAssetMap.call(void 0, this.p), 'access', _9 => _9.get, 'call', _10 => _10(clip.asset), 'optionalAccess', _11 => _11.kind]) === "image") return;
817
+ clip.in = Math.max(0, (_nullishCoalesce(clip.in, () => ( 0))) + delta * _chunkIWSMDQE5cjs.videoClipSpeed.call(void 0, clip));
751
818
  if (clip.in < 1e-9) delete clip.in;
752
819
  }
753
820
  /** Moves a clip's head `delta` later in time (start, in point and keys); the caller sets start and duration. */
754
821
  trimHead(clip, delta) {
755
822
  if (!isRamped(clip)) this.moveIn(clip, delta);
756
- retimeClipKeys(clip, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, -delta));
823
+ retimeClipKeys(clip, (v) => _chunkIWSMDQE5cjs.retimeVideoAnimatable.call(void 0, v, -delta));
757
824
  }
758
825
  /** Cuts `clip` at `at` (inside it): the left part keeps the id, the right part is returned. */
759
826
  cut(track, clip, at, id) {
760
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
827
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip);
761
828
  const right = { ...structuredClone(clip), id: _nullishCoalesce(id, () => ( freshId(`${clip.id}-`, this.ids()))), start: at, duration: end - at };
762
829
  delete right.transition;
763
830
  delete right.fadeIn;
@@ -765,9 +832,9 @@ var Editor = (_class = class {
765
832
  delete right.animateIn;
766
833
  const leftValues = clipAnimatables(clip);
767
834
  clipAnimatables(right).forEach((r, i) => {
768
- const [l, rr] = _chunkSMJGE7HMcjs.splitVideoAnimatable.call(void 0, leftValues[i].get(), at - clip.start);
769
- if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, l)) leftValues[i].set(l);
770
- if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, rr)) r.set(rr);
835
+ const [l, rr] = _chunkIWSMDQE5cjs.splitVideoAnimatable.call(void 0, leftValues[i].get(), at - clip.start);
836
+ if (_chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, l)) leftValues[i].set(l);
837
+ if (_chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, rr)) r.set(rr);
771
838
  });
772
839
  if (!isRamped(right)) this.moveIn(right, at - clip.start);
773
840
  clip.duration = at - clip.start;
@@ -781,7 +848,7 @@ var Editor = (_class = class {
781
848
  /** Cuts every clip on `tracks` that runs across `at`; returns the new right-hand parts. */
782
849
  cutAcross(tracks, at) {
783
850
  const made = [];
784
- for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) > at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
851
+ for (const t of tracks) for (const c of [...t.clips]) if (c.start < at - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON && _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c) > at + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) made.push(this.cut(t, c, at));
785
852
  return made;
786
853
  }
787
854
  /**
@@ -799,10 +866,10 @@ var Editor = (_class = class {
799
866
  */
800
867
  close(tracks, from, to) {
801
868
  for (const t of tracks) {
802
- const hit = _chunkSMJGE7HMcjs.videoOverlap.call(void 0, t, from, to);
869
+ const hit = _chunkIWSMDQE5cjs.videoOverlap.call(void 0, t, from, to);
803
870
  if (hit)
804
871
  refuse(
805
- `Rippling out ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, from)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.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.`
872
+ `Rippling out ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, from)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, to)} would pull track "${t.id}" out of sync: clip "${hit.id}" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, hit.start)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, _chunkIWSMDQE5cjs.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.`
806
873
  );
807
874
  }
808
875
  for (const t of tracks) this.shift(t, to, from - to);
@@ -814,10 +881,10 @@ var Editor = (_class = class {
814
881
  clear(track, from, to, report) {
815
882
  for (const c of [...track.clips]) {
816
883
  const start = c.start;
817
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c);
818
- if (end <= from + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || start >= to - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) continue;
819
- const coversHead = start >= from - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON;
820
- const coversTail = end <= to + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON;
884
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c);
885
+ if (end <= from + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON || start >= to - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) continue;
886
+ const coversHead = start >= from - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON;
887
+ const coversTail = end <= to + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON;
821
888
  if (coversHead && coversTail) {
822
889
  track.clips = track.clips.filter((x) => x !== c);
823
890
  report.removed.push(c.id);
@@ -840,8 +907,8 @@ var Editor = (_class = class {
840
907
  /** Clamps a slip, roll or slide to `[lo, hi]`, refusing when it cannot move that way at all. */
841
908
  clamp(delta, lo, hi, why) {
842
909
  const applied = Math.min(Math.max(delta, Math.min(0, lo)), Math.max(0, hi));
843
- if (Math.abs(delta) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && Math.abs(applied) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(why());
844
- return Math.abs(applied) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON ? 0 : applied;
910
+ if (Math.abs(delta) > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON && Math.abs(applied) <= _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(why());
911
+ return Math.abs(applied) <= _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON ? 0 : applied;
845
912
  }
846
913
  /** Places a clip on a track by `mode`, returning what it cut, trimmed, removed and rippled. */
847
914
  place(track, clip, mode, outcome) {
@@ -851,14 +918,14 @@ var Editor = (_class = class {
851
918
  outcome.rippled = tracks.map((t) => t.id);
852
919
  } else if (mode === "overwrite") {
853
920
  const report = { removed: [], trimmed: [], created: [] };
854
- this.clear(track, clip.start, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip), report);
921
+ this.clear(track, clip.start, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip), report);
855
922
  Object.assign(outcome, report);
856
923
  } else this.fits(track, clip.start, clip.duration, /* @__PURE__ */ new Set([clip.id]), `Clip "${clip.id}"`);
857
924
  track.clips.push(clip);
858
925
  track.clips.sort((a, b) => a.start - b.start);
859
926
  }
860
927
  placement(mode, ripple) {
861
- if (mode !== void 0 && !_chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${_chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
928
+ if (mode !== void 0 && !_chunkIWSMDQE5cjs.VIDEO_PLACEMENT_MODES.includes(mode)) refuse(`"mode" must be ${_chunkIWSMDQE5cjs.VIDEO_PLACEMENT_MODES.map((m) => `"${m}"`).join(", ")}.`);
862
929
  if (ripple && mode !== void 0 && mode !== "insert") refuse(`"ripple" means mode "insert", so it cannot go with mode "${mode}"; pass one or the other.`);
863
930
  return _nullishCoalesce(mode, () => ( (ripple ? "insert" : "refuse")));
864
931
  }
@@ -895,7 +962,7 @@ var Editor = (_class = class {
895
962
  }
896
963
  case "remove_asset": {
897
964
  const asset = this.asset(e.asset);
898
- const users = _chunkSMJGE7HMcjs.allVideoTracks.call(void 0, this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
965
+ const users = _chunkIWSMDQE5cjs.allVideoTracks.call(void 0, this.p).flatMap(({ track: t }) => t.clips.filter((c) => c.type === "media" && c.asset === asset.id).map((c) => c.id));
899
966
  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.`);
900
967
  this.p.assets = this.p.assets.filter((a) => a !== asset);
901
968
  return this.outcomes.push({ op: e.op, asset: asset.id });
@@ -948,12 +1015,12 @@ var Editor = (_class = class {
948
1015
  else draft.duration = (asset.duration - (_nullishCoalesce(draft.in, () => ( 0)))) / (_nullishCoalesce(draft.speed, () => ( 1)));
949
1016
  if (!(draft.duration > 0)) refuse(`"in" (${draft.in} ms) is at or past the end of "${asset.id}" (${asset.duration} ms).`);
950
1017
  } else if (draft.type === "sequence") {
951
- const length = _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
1018
+ const length = _chunkIWSMDQE5cjs.videoSequenceDuration.call(void 0, _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p).get(draft.sequence)) - (_nullishCoalesce(draft.in, () => ( 0)));
952
1019
  if (!(length > 0)) refuse(`"in" (${_nullishCoalesce(draft.in, () => ( 0))} ms) is at or past the end of sequence "${draft.sequence}".`);
953
1020
  draft.duration = length;
954
1021
  } else draft.duration = VIDEO_DEFAULT_TITLE_DURATION;
955
1022
  }
956
- const end = _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track).reduce((m, c) => Math.max(m, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c)), 0);
1023
+ const end = _chunkIWSMDQE5cjs.sortedVideoClips.call(void 0, track).reduce((m, c) => Math.max(m, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c)), 0);
957
1024
  draft.start ??= end;
958
1025
  const clip = parseVideoClip(draft, "clip");
959
1026
  const outcome = { op: e.op, clip: clip.id, track: track.id };
@@ -978,20 +1045,20 @@ var Editor = (_class = class {
978
1045
  case "trim_clip": {
979
1046
  const { track, clip } = this.clip(e.clip);
980
1047
  this.unlocked(track);
981
- const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
982
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
1048
+ const speed = _chunkIWSMDQE5cjs.videoClipSpeed.call(void 0, clip);
1049
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip);
983
1050
  const minimum = 1e3 / this.p.fps;
984
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
1051
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, this.p);
985
1052
  if (e.edge === "start") {
986
1053
  const delta = e.to - clip.start;
987
- if (clip.duration - delta < minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}.`);
1054
+ if (clip.duration - delta < minimum - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(`Trimming the start to ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it ends at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, end)}.`);
988
1055
  if (clip.type === "media" && !isRamped(clip) || clip.type === "sequence") {
989
1056
  const sourceIn = (_nullishCoalesce(clip.in, () => ( 0))) + delta * speed;
990
- if (sourceIn < -_chunkSMJGE7HMcjs.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 ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
1057
+ if (sourceIn < -_chunkIWSMDQE5cjs.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 ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, clip.start - (_nullishCoalesce(clip.in, () => ( 0))) / speed)}).`);
991
1058
  clip.in = Math.max(0, sourceIn);
992
1059
  if (clip.in === 0) delete clip.in;
993
1060
  }
994
- retimeClipKeys(clip, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, -delta));
1061
+ retimeClipKeys(clip, (v) => _chunkIWSMDQE5cjs.retimeVideoAnimatable.call(void 0, v, -delta));
995
1062
  if (e.ripple) {
996
1063
  const tracks = this.rippleTracks([track]);
997
1064
  if (delta > 0) {
@@ -1012,17 +1079,17 @@ var Editor = (_class = class {
1012
1079
  }
1013
1080
  } else {
1014
1081
  const duration = e.to - clip.start;
1015
- if (duration < minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start)}.`);
1082
+ if (duration < minimum - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(`Trimming the end to ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, e.to)} would leave "${clip.id}" shorter than a frame; it starts at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, clip.start)}.`);
1016
1083
  if (clip.type === "media" && !isRamped(clip)) {
1017
1084
  const asset = assets.get(clip.asset);
1018
1085
  const out = (_nullishCoalesce(clip.in, () => ( 0))) + duration * speed;
1019
- if (_optionalChain([asset, 'optionalAccess', _12 => _12.duration]) !== void 0 && out > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
1020
- refuse(`"${clip.id}" can end at most at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
1086
+ if (_optionalChain([asset, 'optionalAccess', _12 => _12.duration]) !== void 0 && out > asset.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
1087
+ refuse(`"${clip.id}" can end at most at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, clip.start + (asset.duration - (_nullishCoalesce(clip.in, () => ( 0)))) / speed)}, where "${asset.id}" runs out.`);
1021
1088
  }
1022
1089
  if (clip.type === "sequence") {
1023
- const seq = _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p).get(clip.sequence);
1024
- const length = seq ? _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, seq) : Infinity;
1025
- if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
1090
+ const seq = _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p).get(clip.sequence);
1091
+ const length = seq ? _chunkIWSMDQE5cjs.videoSequenceDuration.call(void 0, seq) : Infinity;
1092
+ if ((_nullishCoalesce(clip.in, () => ( 0))) + duration > length + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(`"${clip.id}" can end at most at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, clip.start + length - (_nullishCoalesce(clip.in, () => ( 0))))}, where sequence "${clip.sequence}" ends.`);
1026
1093
  }
1027
1094
  if (e.ripple) {
1028
1095
  const tracks = this.rippleTracks([track]);
@@ -1044,9 +1111,9 @@ var Editor = (_class = class {
1044
1111
  case "split_clip": {
1045
1112
  const { track, clip } = this.clip(e.clip);
1046
1113
  this.unlocked(track);
1047
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
1114
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip);
1048
1115
  const minimum = 1e3 / this.p.fps;
1049
- if (e.at < clip.start + minimum - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON || e.at > end - minimum + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, e.at)} is not inside "${clip.id}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, clip.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, end)}), at least a frame from either end.`);
1116
+ if (e.at < clip.start + minimum - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON || e.at > end - minimum + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(`${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, e.at)} is not inside "${clip.id}" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, clip.start)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, end)}), at least a frame from either end.`);
1050
1117
  if (e.id !== void 0 && this.ids().includes(e.id)) refuse(`There is already a clip "${e.id}".`);
1051
1118
  const right = this.cut(track, clip, e.at, e.id);
1052
1119
  return this.outcomes.push({ op: e.op, clips: [clip.id, right.id], clip: right.id, track: track.id });
@@ -1057,12 +1124,12 @@ var Editor = (_class = class {
1057
1124
  for (const track of new Set(found.map((f) => f.track))) track.clips = track.clips.filter((c) => !found.some((f) => f.clip === c));
1058
1125
  if (!e.ripple) return this.outcomes.push({ op: e.op, clips: found.map((f) => f.clip.id) });
1059
1126
  const rippled = /* @__PURE__ */ new Set();
1060
- const groups = [...new Set(found.map((f) => f.track))].filter((t) => !_chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, t)).map((t) => [t]);
1061
- if (found.some((f) => _chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, f.track))) groups.push(found.filter((f) => _chunkSMJGE7HMcjs.videoTrackSyncLocked.call(void 0, f.track)).map((f) => f.track));
1127
+ const groups = [...new Set(found.map((f) => f.track))].filter((t) => !_chunkIWSMDQE5cjs.videoTrackSyncLocked.call(void 0, t)).map((t) => [t]);
1128
+ if (found.some((f) => _chunkIWSMDQE5cjs.videoTrackSyncLocked.call(void 0, f.track))) groups.push(found.filter((f) => _chunkIWSMDQE5cjs.videoTrackSyncLocked.call(void 0, f.track)).map((f) => f.track));
1062
1129
  for (const sources of groups) {
1063
1130
  const tracks = this.rippleTracks(sources);
1064
1131
  tracks.forEach((t) => rippled.add(t));
1065
- const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, f.clip)]));
1132
+ const spans = mergeSpans(found.filter((f) => sources.includes(f.track)).map((f) => [f.clip.start, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, f.clip)]));
1066
1133
  for (const [from, to] of spans.reverse()) this.close(tracks, from, to);
1067
1134
  }
1068
1135
  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) });
@@ -1078,7 +1145,7 @@ var Editor = (_class = class {
1078
1145
  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.");
1079
1146
  let stretch = 1;
1080
1147
  if (at.clip.type === "media" && !("duration" in set)) {
1081
- const was = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, at.clip);
1148
+ const was = _chunkIWSMDQE5cjs.videoClipSpeed.call(void 0, at.clip);
1082
1149
  const now = "speed" in set ? set.speed : _optionalChain([e, 'access', _13 => _13.remove, 'optionalAccess', _14 => _14.includes, 'call', _15 => _15("speed")]) ? 1 : was;
1083
1150
  if (now !== was) {
1084
1151
  set.duration = at.clip.duration * was / now;
@@ -1086,7 +1153,7 @@ var Editor = (_class = class {
1086
1153
  }
1087
1154
  }
1088
1155
  const next = { ...structuredClone(at.clip), ...set };
1089
- if (stretch !== 1) retimeClipKeys(next, (v) => _chunkSMJGE7HMcjs.retimeVideoAnimatable.call(void 0, v, 0, stretch));
1156
+ if (stretch !== 1) retimeClipKeys(next, (v) => _chunkIWSMDQE5cjs.retimeVideoAnimatable.call(void 0, v, 0, stretch));
1090
1157
  for (const k of _nullishCoalesce(e.remove, () => ( []))) delete next[k];
1091
1158
  const clip = parseVideoClip(next, "set");
1092
1159
  if (clip.type === "media" && clip.asset !== at.clip.asset) this.kindFits(at.track, clip);
@@ -1099,17 +1166,17 @@ var Editor = (_class = class {
1099
1166
  const { track, clip } = this.clip(e.clip);
1100
1167
  this.unlocked(track);
1101
1168
  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.`);
1102
- if (clip.type !== "media") refuse(`Clip "${clip.id}" is a ${clip.type === "text" ? "title" : "colour"}, so it has no source to ramp; only video and audio clips change speed.`);
1169
+ if (clip.type !== "media") refuse(`Clip "${clip.id}" is a ${clip.type === "text" ? "title" : clip.type === "effect" ? "effect clip" : "colour"}, so it has no source to ramp; only video and audio clips change speed.`);
1103
1170
  const asset = this.asset(clip.asset);
1104
1171
  if (asset.kind === "image") refuse(`Clip "${clip.id}" is a still ("${asset.id}"), so it has no motion to ramp.`);
1105
1172
  const media = clip;
1106
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, media);
1173
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, media);
1107
1174
  const duration = _nullishCoalesce(e.duration, () => ( media.duration));
1108
- if (!(duration >= 1e3 / this.p.fps - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
1175
+ if (!(duration >= 1e3 / this.p.fps - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)) refuse(`"duration" must be at least a frame (${Math.ceil(1e3 / this.p.fps)} ms).`);
1109
1176
  if (e.keys === null) {
1110
1177
  if (!media.timeRemap) refuse(`Clip "${clip.id}" has no speed ramp to remove.`);
1111
1178
  const from = (_nullishCoalesce(media.in, () => ( 0))) + media.timeRemap.keys[0].v;
1112
- if (asset.duration !== void 0 && from + duration > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
1179
+ if (asset.duration !== void 0 && from + duration > asset.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
1113
1180
  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.`);
1114
1181
  delete media.timeRemap;
1115
1182
  media.in = from;
@@ -1117,17 +1184,17 @@ var Editor = (_class = class {
1117
1184
  } else {
1118
1185
  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).');
1119
1186
  const remap = parseVideoTimeRemap({ keys: e.keys }, void 0, "keys");
1120
- remap.keys = _chunkSMJGE7HMcjs.sortVideoKeys.call(void 0, remap.keys);
1121
- _chunkSMJGE7HMcjs.checkVideoTimeRemap.call(void 0, remap, "keys");
1122
- const span = _chunkSMJGE7HMcjs.videoTimeRemapSpan.call(void 0, remap);
1123
- if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON)
1187
+ remap.keys = _chunkIWSMDQE5cjs.sortVideoKeys.call(void 0, remap.keys);
1188
+ _chunkIWSMDQE5cjs.checkVideoTimeRemap.call(void 0, remap, "keys");
1189
+ const span = _chunkIWSMDQE5cjs.videoTimeRemapSpan.call(void 0, remap);
1190
+ if (asset.duration !== void 0 && (_nullishCoalesce(media.in, () => ( 0))) + span.to > asset.duration + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON)
1124
1191
  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.`);
1125
1192
  media.timeRemap = remap;
1126
1193
  delete media.speed;
1127
1194
  }
1128
1195
  const newEnd = media.start + duration;
1129
1196
  const outcome = { op: e.op, clip: clip.id, track: track.id };
1130
- if (Math.abs(newEnd - end) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
1197
+ if (Math.abs(newEnd - end) > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) {
1131
1198
  if (e.ripple) {
1132
1199
  const tracks = this.rippleTracks([track]);
1133
1200
  if (newEnd < end) {
@@ -1156,11 +1223,11 @@ var Editor = (_class = class {
1156
1223
  case "slip_clip": {
1157
1224
  const { track, clip } = this.clip(e.clip);
1158
1225
  this.unlocked(track);
1159
- if (clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${clip.type === "text" ? "title" : "colour"}, so it has no source to slip; only video, audio and compound clips slip.`);
1226
+ if (clip.type !== "media" && clip.type !== "sequence") refuse(`Clip "${clip.id}" is a ${clip.type === "text" ? "title" : clip.type === "effect" ? "effect clip" : "colour"}, so it has no source to slip; only video, audio and compound clips slip.`);
1160
1227
  const source = clip.type === "sequence" ? `sequence "${clip.sequence}"` : `"${this.asset(clip.asset).id}"`;
1161
1228
  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.`);
1162
- const handles = _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, clip, _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p), _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p));
1163
- const { lead, tail } = _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, clip);
1229
+ const handles = _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, clip, _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, this.p), _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p));
1230
+ const { lead, tail } = _chunkIWSMDQE5cjs.videoClipOverhang.call(void 0, track, clip);
1164
1231
  const delta = this.clamp(
1165
1232
  e.delta,
1166
1233
  lead - handles.before,
@@ -1178,13 +1245,13 @@ var Editor = (_class = class {
1178
1245
  this.unlocked(track);
1179
1246
  const L = left.clip;
1180
1247
  const R = right.clip;
1181
- if (Math.abs(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, L) - R.start) > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
1182
- if (Math.abs(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, R) - L.start) <= _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
1183
- refuse(`"${L.id}" ends at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, L))} but "${R.id}" starts at ${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
1248
+ if (Math.abs(_chunkIWSMDQE5cjs.videoClipEnd.call(void 0, L) - R.start) > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) {
1249
+ if (Math.abs(_chunkIWSMDQE5cjs.videoClipEnd.call(void 0, R) - L.start) <= _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) refuse(`"${R.id}" comes before "${L.id}"; pass left "${R.id}" and right "${L.id}".`);
1250
+ refuse(`"${L.id}" ends at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, L))} but "${R.id}" starts at ${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, R.start)}; a roll needs two clips that meet at a cut (use trim_clip to move one edge).`);
1184
1251
  }
1185
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
1186
- const lo = Math.max(-(L.duration - this.frame), -(_chunkSMJGE7HMcjs.videoClipHandles.call(void 0, R, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, R).lead));
1187
- const hi = Math.min(R.duration - this.frame, _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, L, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, L).tail);
1252
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, this.p);
1253
+ const lo = Math.max(-(L.duration - this.frame), -(_chunkIWSMDQE5cjs.videoClipHandles.call(void 0, R, assets, _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p)).before - _chunkIWSMDQE5cjs.videoClipOverhang.call(void 0, track, R).lead));
1254
+ const hi = Math.min(R.duration - this.frame, _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, L, assets, _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p)).after - _chunkIWSMDQE5cjs.videoClipOverhang.call(void 0, track, L).tail);
1188
1255
  const delta = this.clamp(
1189
1256
  e.delta,
1190
1257
  lo,
@@ -1200,18 +1267,18 @@ var Editor = (_class = class {
1200
1267
  case "slide_clip": {
1201
1268
  const { track, clip } = this.clip(e.clip);
1202
1269
  this.unlocked(track);
1203
- const before = _chunkSMJGE7HMcjs.videoClipBefore.call(void 0, track, clip);
1204
- const after = _chunkSMJGE7HMcjs.videoClipAfter.call(void 0, track, clip);
1270
+ const before = _chunkIWSMDQE5cjs.videoClipBefore.call(void 0, track, clip);
1271
+ const after = _chunkIWSMDQE5cjs.videoClipAfter.call(void 0, track, clip);
1205
1272
  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.`);
1206
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, this.p);
1207
- const end = _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip);
1273
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, this.p);
1274
+ const end = _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip);
1208
1275
  const others = track.clips.filter((c) => c !== clip);
1209
1276
  const room = {
1210
- earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) <= clip.start + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c)), 0),
1211
- later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
1277
+ earlier: before ? before.duration - this.frame : clip.start - others.filter((c) => _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c) <= clip.start + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.max(m, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c)), 0),
1278
+ later: after ? after.duration - this.frame : others.filter((c) => c.start >= end - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON).reduce((m, c) => Math.min(m, c.start - end), Infinity)
1212
1279
  };
1213
- const lo = -Math.min(room.earlier, after ? _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, after, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).before - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, after).lead : Infinity);
1214
- const hi = Math.min(room.later, before ? _chunkSMJGE7HMcjs.videoClipHandles.call(void 0, before, assets, _chunkSMJGE7HMcjs.videoSequenceMap.call(void 0, this.p)).after - _chunkSMJGE7HMcjs.videoClipOverhang.call(void 0, track, before).tail : Infinity);
1280
+ const lo = -Math.min(room.earlier, after ? _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, after, assets, _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p)).before - _chunkIWSMDQE5cjs.videoClipOverhang.call(void 0, track, after).lead : Infinity);
1281
+ const hi = Math.min(room.later, before ? _chunkIWSMDQE5cjs.videoClipHandles.call(void 0, before, assets, _chunkIWSMDQE5cjs.videoSequenceMap.call(void 0, this.p)).after - _chunkIWSMDQE5cjs.videoClipOverhang.call(void 0, track, before).tail : Infinity);
1215
1282
  const delta = this.clamp(
1216
1283
  e.delta,
1217
1284
  lo,
@@ -1244,29 +1311,29 @@ var Editor = (_class = class {
1244
1311
  }
1245
1312
  case "split_at": {
1246
1313
  const tracks = this.rangeTracks(e.tracks);
1247
- const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c) > e.at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).map((c) => c.id));
1248
- if (!lefts.length) refuse(`No clip runs across ${_chunkSMJGE7HMcjs.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.`);
1314
+ const lefts = tracks.flatMap((t) => t.clips.filter((c) => c.start < e.at - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON && _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c) > e.at + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON).map((c) => c.id));
1315
+ if (!lefts.length) refuse(`No clip runs across ${_chunkIWSMDQE5cjs.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.`);
1249
1316
  const created = this.cutAcross(tracks, e.at).map((c) => c.id);
1250
1317
  return this.outcomes.push({ op: e.op, clips: lefts, created });
1251
1318
  }
1252
1319
  case "set_keyframes": {
1253
1320
  const { track, clip } = this.clip(e.clip);
1254
1321
  this.unlocked(track);
1255
- if (!_chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${_chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
1322
+ if (!_chunkIWSMDQE5cjs.VIDEO_KEYFRAME_PROPERTIES.includes(e.property)) refuse(`"${e.property}" cannot be keyframed; use one of ${_chunkIWSMDQE5cjs.VIDEO_KEYFRAME_PROPERTIES.join(", ")}.`);
1256
1323
  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.`);
1257
- const limits = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[e.property];
1258
- const transform = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
1324
+ const limits = _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_LIMITS[e.property];
1325
+ const transform = _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES.includes(e.property);
1259
1326
  const c = clip;
1260
1327
  const current = transform ? _optionalChain([c, 'access', _18 => _18.transform, 'optionalAccess', _19 => _19[e.property]]) : c[e.property];
1261
1328
  let value;
1262
1329
  if (e.keys === null) {
1263
- const v = _chunkSMJGE7HMcjs.videoValueAt.call(void 0, current, 0, limits.default);
1264
- value = _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, current) ? v === limits.default ? void 0 : v : current;
1330
+ const v = _chunkIWSMDQE5cjs.videoValueAt.call(void 0, current, 0, limits.default);
1331
+ value = _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, current) ? v === limits.default ? void 0 : v : current;
1265
1332
  } else {
1266
1333
  if (!Array.isArray(e.keys) || !e.keys.length) refuse('"keys" must list at least one key { t, v }; pass null to remove the keyframes.');
1267
1334
  let sorted = [];
1268
1335
  try {
1269
- sorted = _chunkSMJGE7HMcjs.sortVideoKeys.call(void 0, e.keys);
1336
+ sorted = _chunkIWSMDQE5cjs.sortVideoKeys.call(void 0, e.keys);
1270
1337
  } catch (error) {
1271
1338
  refuse(error.message);
1272
1339
  }
@@ -1285,12 +1352,12 @@ var Editor = (_class = class {
1285
1352
  this.unlocked(track);
1286
1353
  let at = 0;
1287
1354
  const moved = [];
1288
- for (const clip of _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track)) {
1289
- if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON && clip.start > at + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) {
1355
+ for (const clip of _chunkIWSMDQE5cjs.sortedVideoClips.call(void 0, track)) {
1356
+ if (clip.start >= (_nullishCoalesce(e.from, () => ( 0))) - _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON && clip.start > at + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) {
1290
1357
  clip.start = Math.max(at, _nullishCoalesce(e.from, () => ( 0)));
1291
1358
  moved.push(clip.id);
1292
1359
  }
1293
- at = Math.max(at, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip));
1360
+ at = Math.max(at, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip));
1294
1361
  }
1295
1362
  return this.outcomes.push({ op: e.op, track: track.id, clips: moved });
1296
1363
  }
@@ -1445,7 +1512,7 @@ function videoClipWaveform(clip, peaks, columns) {
1445
1512
  const step = clip.duration / Math.max(1, n);
1446
1513
  for (let c = 0; c < n; c++) {
1447
1514
  const { min, max } = videoAudioPeakRange(peaks, start + c * step * speed, start + (c + 1) * step * speed);
1448
- const gain = _chunkSMJGE7HMcjs.videoClipSoundGain.call(void 0, clip, (c + 0.5) * step);
1515
+ const gain = _chunkIWSMDQE5cjs.videoClipSoundGain.call(void 0, clip, (c + 0.5) * step);
1449
1516
  out[2 * c] = min * gain;
1450
1517
  out[2 * c + 1] = max * gain;
1451
1518
  }
@@ -2010,7 +2077,7 @@ function videoTranscriptTrack(project, track) {
2010
2077
  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(", ")}.`);
2011
2078
  return track;
2012
2079
  }
2013
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
2080
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, project);
2014
2081
  const transcribed = (t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _21 => _21.get, 'call', _22 => _22(c.asset), 'optionalAccess', _23 => _23.transcript, 'optionalAccess', _24 => _24.length]));
2015
2082
  return _nullishCoalesce(_optionalChain([(_nullishCoalesce(project.tracks.find((t) => t.kind === "audio" && transcribed(t)), () => ( project.tracks.find(transcribed)))), 'optionalAccess', _25 => _25.id]), () => ( null));
2016
2083
  }
@@ -2018,16 +2085,16 @@ function videoTimelineTranscript(project, options = {}) {
2018
2085
  const id = videoTranscriptTrack(project, options.track);
2019
2086
  if (!id) return [];
2020
2087
  const track = project.tracks.find((t) => t.id === id);
2021
- const assets = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project);
2088
+ const assets = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, project);
2022
2089
  const out = [];
2023
- for (const clip of _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, track)) {
2090
+ for (const clip of _chunkIWSMDQE5cjs.sortedVideoClips.call(void 0, track)) {
2024
2091
  if (clip.type !== "media") continue;
2025
2092
  const words = _optionalChain([assets, 'access', _26 => _26.get, 'call', _27 => _27(clip.asset), 'optionalAccess', _28 => _28.transcript]);
2026
2093
  if (!_optionalChain([words, 'optionalAccess', _29 => _29.length])) continue;
2027
- const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
2094
+ const speed = _chunkIWSMDQE5cjs.videoClipSpeed.call(void 0, clip);
2028
2095
  const from = _nullishCoalesce(clip.in, () => ( 0));
2029
2096
  const to = from + clip.duration * speed;
2030
- const toTimeline = (s) => Math.min(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip), Math.max(clip.start, clip.start + (s - from) / speed));
2097
+ const toTimeline = (s) => Math.min(_chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip), Math.max(clip.start, clip.start + (s - from) / speed));
2031
2098
  words.forEach((w, index) => {
2032
2099
  const mid = (w.start + w.end) / 2;
2033
2100
  if (mid < from || mid >= to) return;
@@ -2072,19 +2139,19 @@ function findVideoTranscriptPauses(words, options = {}) {
2072
2139
  let to = b.start - keep;
2073
2140
  if (options.fps) {
2074
2141
  const f = 1e3 / options.fps;
2075
- from = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, Math.ceil(from / f - 1e-9) * f, options.fps);
2076
- to = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, Math.floor(to / f + 1e-9) * f, options.fps);
2142
+ from = _chunkIWSMDQE5cjs.snapToVideoFrame.call(void 0, Math.ceil(from / f - 1e-9) * f, options.fps);
2143
+ to = _chunkIWSMDQE5cjs.snapToVideoFrame.call(void 0, Math.floor(to / f + 1e-9) * f, options.fps);
2077
2144
  }
2078
- if (to - from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
2145
+ if (to - from > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) out.push({ from, to, text: `(pause after "${a.word}")` });
2079
2146
  }
2080
2147
  return out;
2081
2148
  }
2082
2149
  function mergeVideoRanges(ranges) {
2083
- const sorted = ranges.filter((r) => r.to - r.from > _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
2150
+ const sorted = ranges.filter((r) => r.to - r.from > _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON).map((r) => ({ from: r.from, to: r.to })).sort((a, b) => a.from - b.from);
2084
2151
  const out = [];
2085
2152
  for (const r of sorted) {
2086
2153
  const last = out[out.length - 1];
2087
- if (last && r.from <= last.to + _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
2154
+ if (last && r.from <= last.to + _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON) last.to = Math.max(last.to, r.to);
2088
2155
  else out.push(r);
2089
2156
  }
2090
2157
  return out;
@@ -2168,7 +2235,7 @@ function videoProxyFfmpeg(asset, options = {}) {
2168
2235
  output
2169
2236
  ];
2170
2237
  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 } : {} };
2171
- return { asset: asset.id, args, command: ["ffmpeg", ...args].map(_chunkSMJGE7HMcjs.videoShellQuote).join(" "), proxy };
2238
+ return { asset: asset.id, args, command: ["ffmpeg", ...args].map(_chunkIWSMDQE5cjs.videoShellQuote).join(" "), proxy };
2172
2239
  }
2173
2240
  function videoProxyPlan(project, options = {}) {
2174
2241
  const scale = _nullishCoalesce(options.scale, () => ( 0.5));
@@ -2194,7 +2261,7 @@ var videoSourceFrameTime = (frame, fps) => (frame + 0.5) * 1e3 / fps;
2194
2261
  var videoFrameCacheKey = (src, frame) => `${frame}@${src}`;
2195
2262
  function videoFrameRequestsAt(project, time, srcFor = (l) => l.src) {
2196
2263
  const out = [];
2197
- for (const layer of _chunkSMJGE7HMcjs.videoFrameLeafLayers.call(void 0, _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project, time).layers)) {
2264
+ for (const layer of _chunkIWSMDQE5cjs.videoFrameLeafLayers.call(void 0, _chunkIWSMDQE5cjs.videoFrameAt.call(void 0, project, time).layers)) {
2198
2265
  if (layer.type !== "media" || layer.assetKind !== "video") continue;
2199
2266
  const src = srcFor(layer);
2200
2267
  if (!src) continue;
@@ -2451,6 +2518,9 @@ var VideoPreviewEngine = (_class5 = class {
2451
2518
  this.frameCache = options.frameCache !== void 0 ? options.frameCache : _nullishCoalesce(source.frameCache, () => ( null));
2452
2519
  this.unsubscribeFrames = this.frameCache ? this.frameCache.subscribe(() => this.redraw()) : () => {
2453
2520
  };
2521
+ this.effects = options.effects !== void 0 ? options.effects : _nullishCoalesce(source.effectsEngine, () => ( null));
2522
+ this.unsubscribeEffects = this.effects ? this.effects.subscribe(() => this.redraw()) : () => {
2523
+ };
2454
2524
  const pixels = options.pixels !== void 0 ? options.pixels : source.previewPixels;
2455
2525
  this.detachPixels = pixels ? pixels.attach(() => this.readPixels()) : () => {
2456
2526
  };
@@ -2480,6 +2550,8 @@ var VideoPreviewEngine = (_class5 = class {
2480
2550
  __init31() {this.fps = 30}
2481
2551
 
2482
2552
  __init32() {this.scratchCanvases = /* @__PURE__ */ new Map()}
2553
+
2554
+
2483
2555
  /** The canvas's pixels and the frame they show, or `null` when its context cannot be read. */
2484
2556
  readPixels() {
2485
2557
  const ctx = this.ctx;
@@ -2530,7 +2602,7 @@ var VideoPreviewEngine = (_class5 = class {
2530
2602
  if (this.destroyed) return;
2531
2603
  const state = this.source.getState();
2532
2604
  const { project, time, playing } = state;
2533
- const frame = _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project, time);
2605
+ const frame = _chunkIWSMDQE5cjs.videoFrameAt.call(void 0, project, time);
2534
2606
  const scale = resolveVideoPreviewScale(_nullishCoalesce(this.options.previewScale, () => ( state.previewScale)), this.resolutionFor(project.width));
2535
2607
  const assets = new Map(project.assets.map((a) => [a.id, a]));
2536
2608
  this.srcFor = (layer) => videoPreviewSrc(assets.get(_nullishCoalesce(layer.asset, () => ( ""))), scale, layer.src);
@@ -2560,7 +2632,7 @@ var VideoPreviewEngine = (_class5 = class {
2560
2632
  }
2561
2633
  };
2562
2634
  const sounding = new Map(frame.audio.map((a) => [a.clip, a]));
2563
- for (const layer of _chunkSMJGE7HMcjs.videoFrameLeafLayers.call(void 0, frame.layers)) {
2635
+ for (const layer of _chunkIWSMDQE5cjs.videoFrameLeafLayers.call(void 0, frame.layers)) {
2564
2636
  if (layer.type !== "media" || layer.assetKind !== "video" || !layer.src) continue;
2565
2637
  const sound = sounding.get(layer.clip);
2566
2638
  sync(layer.clip, this.srcFor(layer), "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _71 => _71.speed]), () => ( 1)), sound ? sound.gain : null);
@@ -2568,14 +2640,22 @@ var VideoPreviewEngine = (_class5 = class {
2568
2640
  }
2569
2641
  for (const a of sounding.values()) sync(a.clip, a.src, "audio", a.sourceTime, a.speed, a.gain);
2570
2642
  for (const entry of [...this.media.values()]) if (!active.has(entry.clip)) this.release(entry);
2571
- this.draw(frame);
2643
+ this.draw(this.drawable(project, frame));
2644
+ }
2645
+ /** With effects, the frame is drawn at the start of its frame, so effect pictures are cached once per frame. */
2646
+ drawable(project, frame) {
2647
+ if (!_optionalChain([this, 'access', _72 => _72.effects, 'optionalAccess', _73 => _73.available]) || !_chunkIWSMDQE5cjs.videoLayersUseEffects.call(void 0, frame.layers)) return frame;
2648
+ const at = _chunkIWSMDQE5cjs.videoEffectFrameTime.call(void 0, frame.time, project.fps);
2649
+ return at === frame.time ? frame : { ..._chunkIWSMDQE5cjs.videoFrameAt.call(void 0, project, at), time: frame.time };
2572
2650
  }
2573
2651
  redraw() {
2574
2652
  if (this.scheduled || this.destroyed) return;
2575
2653
  this.scheduled = true;
2576
2654
  queueMicrotask(() => {
2577
2655
  this.scheduled = false;
2578
- if (!this.destroyed) this.draw(_chunkSMJGE7HMcjs.videoFrameAt.call(void 0, this.source.getState().project, this.source.getState().time));
2656
+ if (this.destroyed) return;
2657
+ const { project, time } = this.source.getState();
2658
+ this.draw(this.drawable(project, _chunkIWSMDQE5cjs.videoFrameAt.call(void 0, project, time)));
2579
2659
  });
2580
2660
  }
2581
2661
  __init33() {this.sourceFor = (layer) => {
@@ -2586,7 +2666,7 @@ var VideoPreviewEngine = (_class5 = class {
2586
2666
  const entry = this.media.get(layer.clip);
2587
2667
  const ready = !!entry && entry.media.readyState >= 2;
2588
2668
  const cache = this.frameCache;
2589
- const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _72 => _72.src]), () => ( this.srcFor(layer)));
2669
+ const src = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _74 => _74.src]), () => ( this.srcFor(layer)));
2590
2670
  const sourceTime = _nullishCoalesce(layer.sourceTime, () => ( 0));
2591
2671
  if (cache && src && (!this.playing || !ready || entry.media.seeking)) {
2592
2672
  const hit = cache.get(src, sourceTime, this.fps);
@@ -2613,18 +2693,27 @@ var VideoPreviewEngine = (_class5 = class {
2613
2693
  if (this.canvas.height !== h) this.canvas.height = h;
2614
2694
  this.complete = true;
2615
2695
  const sourceFor = (layer) => {
2696
+ if (layer.type === "effect") return null;
2616
2697
  const source = this.sourceFor(layer);
2617
2698
  if (!source) this.complete = false;
2618
2699
  return source;
2619
2700
  };
2620
- _chunkSMJGE7HMcjs.drawVideoFrame.call(void 0, this.ctx, frame, sourceFor, resolution, { defineSvgFilter: this.defineSvgFilter, lutFor: this.lutFor, scratch: this.scratch });
2701
+ _chunkIWSMDQE5cjs.drawVideoFrame.call(void 0, this.ctx, frame, sourceFor, resolution, {
2702
+ defineSvgFilter: this.defineSvgFilter,
2703
+ lutFor: this.lutFor,
2704
+ scratch: this.scratch,
2705
+ effects: this.effects,
2706
+ onEffectWaiting: () => {
2707
+ this.complete = false;
2708
+ }
2709
+ });
2621
2710
  this.drawn = { time: frame.time, complete: this.complete };
2622
- _optionalChain([this, 'access', _73 => _73.options, 'access', _74 => _74.onFrame, 'optionalCall', _75 => _75(frame)]);
2623
- _optionalChain([this, 'access', _76 => _76.pixelsTarget, 'optionalAccess', _77 => _77.drawn, 'call', _78 => _78(frame.time, this.complete)]);
2711
+ _optionalChain([this, 'access', _75 => _75.options, 'access', _76 => _76.onFrame, 'optionalCall', _77 => _77(frame)]);
2712
+ _optionalChain([this, 'access', _78 => _78.pixelsTarget, 'optionalAccess', _79 => _79.drawn, 'call', _80 => _80(frame.time, this.complete)]);
2624
2713
  }
2625
2714
  /** A grade's LUT once loaded; while it loads (or if it fails) the frame is drawn without it and counts as incomplete. */
2626
2715
  __init34() {this.lutFor = (src) => {
2627
- const lut = _optionalChain([this, 'access', _79 => _79.lutCache, 'optionalAccess', _80 => _80.get, 'call', _81 => _81(src)]);
2716
+ const lut = _optionalChain([this, 'access', _81 => _81.lutCache, 'optionalAccess', _82 => _82.get, 'call', _83 => _83(src)]);
2628
2717
  if (!lut) this.complete = false;
2629
2718
  return lut;
2630
2719
  }}
@@ -2668,7 +2757,8 @@ var VideoPreviewEngine = (_class5 = class {
2668
2757
  this.detachPixels();
2669
2758
  this.unsubscribeLuts();
2670
2759
  this.unsubscribeFrames();
2671
- _optionalChain([this, 'access', _82 => _82.filterHost, 'optionalAccess', _83 => _83.remove, 'call', _84 => _84()]);
2760
+ this.unsubscribeEffects();
2761
+ _optionalChain([this, 'access', _84 => _84.filterHost, 'optionalAccess', _85 => _85.remove, 'call', _86 => _86()]);
2672
2762
  this.filterHost = null;
2673
2763
  this.filters.clear();
2674
2764
  this.unsubscribe();
@@ -2689,6 +2779,10 @@ var VideoEditorController = (_class6 = class {
2689
2779
 
2690
2780
  /** The host's frame cache, if it gave one (the preview fills and reads it). */
2691
2781
 
2782
+ /** The effects provider slot (see `setEffectsProvider`). */
2783
+
2784
+ /** Rendered effect pictures for the preview and frame-exact exports. */
2785
+
2692
2786
 
2693
2787
 
2694
2788
  __init38() {this.selection = []}
@@ -2704,14 +2798,17 @@ var VideoEditorController = (_class6 = class {
2704
2798
  constructor(options = {}) {;_class6.prototype.__init37.call(this);_class6.prototype.__init38.call(this);_class6.prototype.__init39.call(this);_class6.prototype.__init40.call(this);_class6.prototype.__init41.call(this);_class6.prototype.__init42.call(this);_class6.prototype.__init43.call(this);_class6.prototype.__init44.call(this);_class6.prototype.__init45.call(this);
2705
2799
  this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkQKLRAA4Tcjs.HistoryManager)()));
2706
2800
  this.audioPeaks = options.audioPeaks instanceof VideoAudioPeaksCache ? options.audioPeaks : new VideoAudioPeaksCache(options.audioPeaks);
2707
- this.luts = options.luts instanceof _chunkSMJGE7HMcjs.VideoLutCache ? options.luts : new (0, _chunkSMJGE7HMcjs.VideoLutCache)(options.luts);
2801
+ this.luts = options.luts instanceof _chunkIWSMDQE5cjs.VideoLutCache ? options.luts : new (0, _chunkIWSMDQE5cjs.VideoLutCache)(options.luts);
2708
2802
  this.frameCache = _nullishCoalesce(options.frameCache, () => ( null));
2803
+ this.effects = new (0, _chunkIOXKXQNWcjs.EffectsSlot)();
2804
+ if (options.effects) this.effects.set(options.effects);
2805
+ this.effectsEngine = new (0, _chunkIWSMDQE5cjs.VideoEffectsEngine)({ slot: this.effects });
2709
2806
  this.project = options.project ? parseVideoProject(options.project) : createVideoProject();
2710
2807
  this.issues = checkVideoProject(this.project);
2711
2808
  this.readOnly = _nullishCoalesce(options.readOnly, () => ( false));
2712
2809
  this.previewScale = checkPreviewScale(_nullishCoalesce(options.previewScale, () => ( "auto")));
2713
2810
  this.onChange = options.onChange;
2714
- this.player = new (0, _chunk477UVMNRcjs.AnimationPlayer)({ clock: options.clock, duration: () => _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project), loop: "none" });
2811
+ this.player = new (0, _chunk477UVMNRcjs.AnimationPlayer)({ clock: options.clock, duration: () => _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, this.project), loop: "none" });
2715
2812
  this.state = this.computeState();
2716
2813
  this.connect();
2717
2814
  }
@@ -2721,12 +2818,14 @@ var VideoEditorController = (_class6 = class {
2721
2818
  this.player.subscribe(() => this.notify()),
2722
2819
  this.history.subscribe(() => {
2723
2820
  if (!this.applying) this.notify();
2724
- })
2821
+ }),
2822
+ this.effects.subscribe(() => this.notify())
2725
2823
  );
2726
2824
  }
2727
2825
  /** Pauses and stops listening to the player and history. Subscribing again reconnects (React StrictMode). */
2728
2826
  destroy() {
2729
2827
  this.player.pause();
2828
+ this.effectsEngine.reset();
2730
2829
  this.unsubscribers.splice(0).forEach((u) => u());
2731
2830
  }
2732
2831
  __init44() {this.getState = () => this.state}
@@ -2746,12 +2845,12 @@ var VideoEditorController = (_class6 = class {
2746
2845
  const h = this.history.getState();
2747
2846
  return {
2748
2847
  project: this.project,
2749
- duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project),
2848
+ duration: _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, this.project),
2750
2849
  time: p.time,
2751
2850
  playing: p.playing,
2752
2851
  loop: p.loop,
2753
2852
  selection: this.selection,
2754
- current: _chunkSMJGE7HMcjs.videoClipsAt.call(void 0, this.project, p.time).map((c) => c.clip.id),
2853
+ current: _chunkIWSMDQE5cjs.videoClipsAt.call(void 0, this.project, p.time).map((c) => c.clip.id),
2755
2854
  issues: this.issues,
2756
2855
  readOnly: this.readOnly,
2757
2856
  error: this.error,
@@ -2760,6 +2859,7 @@ var VideoEditorController = (_class6 = class {
2760
2859
  undoLabel: h.undoName,
2761
2860
  redoLabel: h.redoName,
2762
2861
  previewScale: this.previewScale,
2862
+ effectsProvider: this.effects.provider,
2763
2863
  revision: this.revision
2764
2864
  };
2765
2865
  }
@@ -2782,14 +2882,14 @@ var VideoEditorController = (_class6 = class {
2782
2882
  this.issues = checkVideoProject(project);
2783
2883
  const ids = new Set(project.tracks.flatMap((t) => t.clips.map((c) => c.id)));
2784
2884
  if (this.selection.some((id) => !ids.has(id))) this.selection = this.selection.filter((id) => ids.has(id));
2785
- this.player.setDuration(() => _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, this.project));
2885
+ this.player.setDuration(() => _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, this.project));
2786
2886
  } finally {
2787
2887
  this.applying = false;
2788
2888
  }
2789
2889
  this.notify();
2790
- _optionalChain([this, 'access', _85 => _85.onChange, 'optionalCall', _86 => _86(project)]);
2890
+ _optionalChain([this, 'access', _87 => _87.onChange, 'optionalCall', _88 => _88(project)]);
2791
2891
  }
2792
- commit(label, next) {
2892
+ commit(label, next, merge) {
2793
2893
  const before = this.project;
2794
2894
  this.error = null;
2795
2895
  if (next === before) {
@@ -2803,7 +2903,8 @@ var VideoEditorController = (_class6 = class {
2803
2903
  undo: () => this.setProject(before),
2804
2904
  redo: () => this.setProject(next)
2805
2905
  };
2806
- this.history.execute(command);
2906
+ if (merge) this.history.executeMerged(command, { key: merge });
2907
+ else this.history.execute(command);
2807
2908
  }
2808
2909
  refuse(message) {
2809
2910
  this.error = message;
@@ -2816,14 +2917,15 @@ var VideoEditorController = (_class6 = class {
2816
2917
  }
2817
2918
  /**
2818
2919
  * Applies edits as one undo step, all or nothing (see `applyVideoEdits`). With `dryRun` it
2819
- * reports what would happen and changes nothing.
2920
+ * reports what would happen and changes nothing. Edits with the same `merge` key in a row
2921
+ * (a slider drag) fold into one undo step.
2820
2922
  */
2821
2923
  apply(edits, label = "Edit video", options = {}) {
2822
2924
  const reason = this.readOnlyReason();
2823
2925
  if (reason) return this.refuse(reason);
2824
2926
  const result = applyVideoEdits(this.project, edits);
2825
2927
  if (!result.ok) return options.dryRun ? result : this.refuse(result.error);
2826
- if (!options.dryRun) this.commit(label, result.project);
2928
+ if (!options.dryRun) this.commit(label, result.project, options.merge);
2827
2929
  return result;
2828
2930
  }
2829
2931
  /** Opens a project (JSON or object). `clearHistory` drops the undo stack (opening a file); otherwise it is one undo step. */
@@ -2862,7 +2964,7 @@ var VideoEditorController = (_class6 = class {
2862
2964
  }
2863
2965
  /** Selects clips (unknown ids are dropped). `add` toggles them into the current selection. */
2864
2966
  select(clips, options = {}) {
2865
- const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _87 => _87.filter, 'call', _88 => _88((id) => _chunkSMJGE7HMcjs.findVideoClip.call(void 0, this.project, id))]), () => ( []));
2967
+ const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _89 => _89.filter, 'call', _90 => _90((id) => _chunkIWSMDQE5cjs.findVideoClip.call(void 0, this.project, id))]), () => ( []));
2866
2968
  let next;
2867
2969
  if (options.add) {
2868
2970
  next = [...this.selection];
@@ -2889,7 +2991,7 @@ var VideoEditorController = (_class6 = class {
2889
2991
  step(frames) {
2890
2992
  this.player.pause();
2891
2993
  const fps = this.project.fps;
2892
- this.player.seek(Math.max(0, _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, this.player.currentTime, fps) + frames * 1e3 / fps));
2994
+ this.player.seek(Math.max(0, _chunkIWSMDQE5cjs.snapToVideoFrame.call(void 0, this.player.currentTime, fps) + frames * 1e3 / fps));
2893
2995
  }
2894
2996
  setLoop(loop) {
2895
2997
  this.player.setLoop(loop);
@@ -2906,14 +3008,14 @@ var VideoEditorController = (_class6 = class {
2906
3008
  */
2907
3009
  snap(time, options = {}) {
2908
3010
  const threshold = _nullishCoalesce(options.threshold, () => ( 8 * 1e3 / this.project.fps));
2909
- const points = _chunkSMJGE7HMcjs.videoSnapPoints.call(void 0, this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
2910
- const hit = _chunkSMJGE7HMcjs.snapVideoTime.call(void 0, time, points, threshold);
2911
- return hit.snapped !== null ? hit : { time: Math.max(0, _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, time, this.project.fps)), snapped: null };
3011
+ const points = _chunkIWSMDQE5cjs.videoSnapPoints.call(void 0, this.project, { exclude: options.exclude, playhead: options.playhead === false ? void 0 : this.player.currentTime });
3012
+ const hit = _chunkIWSMDQE5cjs.snapVideoTime.call(void 0, time, points, threshold);
3013
+ return hit.snapped !== null ? hit : { time: Math.max(0, _chunkIWSMDQE5cjs.snapToVideoFrame.call(void 0, time, this.project.fps)), snapped: null };
2912
3014
  }
2913
3015
  /** Splits the selected clips (or every clip) under the playhead there, as one undo step. */
2914
3016
  splitAtPlayhead() {
2915
- const t = _chunkSMJGE7HMcjs.snapToVideoFrame.call(void 0, this.player.currentTime, this.project.fps);
2916
- const under = _chunkSMJGE7HMcjs.videoClipsAt.call(void 0, this.project, t).filter(({ clip }) => t > clip.start && t < _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip));
3017
+ const t = _chunkIWSMDQE5cjs.snapToVideoFrame.call(void 0, this.player.currentTime, this.project.fps);
3018
+ const under = _chunkIWSMDQE5cjs.videoClipsAt.call(void 0, this.project, t).filter(({ clip }) => t > clip.start && t < _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip));
2917
3019
  const chosen = this.selection.length ? under.filter(({ clip }) => this.selection.includes(clip.id)) : under;
2918
3020
  if (!chosen.length) return this.refuse("No clip is under the playhead to split.");
2919
3021
  return this.apply(chosen.map(({ clip }) => ({ op: "split_clip", clip: clip.id, at: t })), "Split");
@@ -2923,25 +3025,200 @@ var VideoEditorController = (_class6 = class {
2923
3025
  if (!this.selection.length) return this.refuse("Select clips to delete first.");
2924
3026
  return this.apply({ op: "delete_clips", clips: [...this.selection], ripple: options.ripple }, options.ripple ? "Ripple delete" : "Delete clips");
2925
3027
  }
3028
+ // -----------------------------------------------------------------------------------------
3029
+ // Effects
3030
+ // -----------------------------------------------------------------------------------------
3031
+ /** The registered effects provider, or `null`. */
3032
+ get effectsProvider() {
3033
+ return this.effects.provider;
3034
+ }
3035
+ /** Registers (or with `null` removes) the effects provider. Not an edit: no undo step. */
3036
+ setEffectsProvider(provider) {
3037
+ this.effects.set(provider);
3038
+ }
3039
+ /** Registers `provider` and returns a function that removes it again (if it is still the one set). */
3040
+ useEffects(provider) {
3041
+ return this.effects.use(provider);
3042
+ }
3043
+ /** The provider's description of an effect, checked for `place` (rejects without a provider or for an unknown id). */
3044
+ async describeEffect(effect, place) {
3045
+ const d = await this.effects.require().describe(effect);
3046
+ if (place) _chunkIWSMDQE5cjs.checkVideoEffectPlace.call(void 0, d, place);
3047
+ return d;
3048
+ }
3049
+ refused(message) {
3050
+ return this.refuse(message);
3051
+ }
3052
+ async effectEdit(run, merge) {
3053
+ const reason = this.readOnlyReason();
3054
+ if (reason) return this.refused(reason);
3055
+ let plan;
3056
+ try {
3057
+ plan = await run();
3058
+ } catch (error) {
3059
+ if (_chunkIOXKXQNWcjs.isEffectError.call(void 0, error) || error instanceof Error) return this.refused(error.message);
3060
+ throw error;
3061
+ }
3062
+ const result = this.apply(plan.edit, plan.label, { merge });
3063
+ if (!result.ok) return result;
3064
+ return { ...result, clip: plan.clip, ...plan.effect ? { effect: plan.effect() } : {} };
3065
+ }
3066
+ clipOrThrow(id) {
3067
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, this.project, id);
3068
+ if (!at) throw new Error(`There is no clip "${id}"; list_applied_effects or get_video_project lists the clips.`);
3069
+ return at.clip;
3070
+ }
3071
+ /**
3072
+ * Adds a filter or overlay effect to a clip's effect stack (at `index`, default the end: applied
3073
+ * last), with `values` over the effect's defaults (numbers may be keyframes). One undo step.
3074
+ * Returns the effect with its new id.
3075
+ */
3076
+ applyClipEffect(clip, effect, options = {}) {
3077
+ return this.effectEdit(async () => {
3078
+ const current = this.clipOrThrow(clip);
3079
+ const d = await this.describeEffect(effect, "clip");
3080
+ const values = _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
3081
+ const stack = [..._nullishCoalesce(current.effects, () => ( []))];
3082
+ const taken = new Set(stack.map((e) => e.id));
3083
+ let n = 1;
3084
+ while (taken.has(`fx${n}`)) n++;
3085
+ const added = { id: `fx${n}`, effect: d.id, provider: this.effects.require().id, name: d.name, values };
3086
+ if (options.enabled === false) added.enabled = false;
3087
+ if (options.opacity !== void 0) added.opacity = options.opacity;
3088
+ const index = _nullishCoalesce(options.index, () => ( stack.length));
3089
+ if (!(Number.isInteger(index) && index >= 0 && index <= stack.length)) throw new Error(`"index" must be a whole number from 0 to ${stack.length}.`);
3090
+ stack.splice(index, 0, added);
3091
+ return { edit: { op: "update_clip", clip, set: { effects: stack } }, label: `Add effect ${d.name}`, clip, effect: () => added };
3092
+ });
3093
+ }
3094
+ /**
3095
+ * Changes an effect on a clip: `values` (merged over its current ones; numbers may be
3096
+ * keyframes, `null` resets a control to its default), `enabled`, `opacity` or its place in the
3097
+ * stack (`index`). Values are checked against the provider's controls. One undo step.
3098
+ */
3099
+ updateClipEffect(clip, instance, changes, options = {}) {
3100
+ return this.effectEdit(async () => {
3101
+ const current = this.clipOrThrow(clip);
3102
+ const stack = [..._nullishCoalesce(current.effects, () => ( []))];
3103
+ const i = stack.findIndex((e) => e.id === instance);
3104
+ if (i < 0) throw new Error(`Clip "${clip}" has no effect "${instance}"; its effects are ${stack.map((e) => `"${e.id}" (${_nullishCoalesce(e.name, () => ( e.effect))})`).join(", ") || "none"}.`);
3105
+ const was = stack[i];
3106
+ const next = { ...was };
3107
+ if (changes.values) {
3108
+ const d = await this.describeEffect(was.effect);
3109
+ const reset = Object.keys(changes.values).filter((k) => changes.values[k] === null);
3110
+ const given = Object.fromEntries(Object.entries(changes.values).filter(([, v]) => v !== null));
3111
+ const base = { ..._nullishCoalesce(was.values, () => ( {})) };
3112
+ for (const k of reset) {
3113
+ 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(", ")}.`);
3114
+ base[k] = d.defaults[k];
3115
+ }
3116
+ next.values = _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d, given, { base, keyframes: true });
3117
+ }
3118
+ if (changes.enabled !== void 0) {
3119
+ if (changes.enabled) delete next.enabled;
3120
+ else next.enabled = false;
3121
+ }
3122
+ if (changes.opacity !== void 0) next.opacity = changes.opacity;
3123
+ stack.splice(i, 1);
3124
+ const index = _nullishCoalesce(changes.index, () => ( i));
3125
+ if (!(Number.isInteger(index) && index >= 0 && index <= stack.length)) throw new Error(`"index" must be a whole number from 0 to ${stack.length}.`);
3126
+ stack.splice(index, 0, next);
3127
+ return { edit: { op: "update_clip", clip, set: { effects: stack } }, label: `Change effect ${_nullishCoalesce(was.name, () => ( was.effect))}`, clip, effect: () => next };
3128
+ }, options.merge);
3129
+ }
3130
+ /** Removes an effect from a clip's stack (works without a provider, so placeholders can be cleared). One undo step. */
3131
+ removeClipEffect(clip, instance) {
3132
+ const reason = this.readOnlyReason();
3133
+ if (reason) return this.refused(reason);
3134
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, this.project, clip);
3135
+ if (!at) return this.refused(`There is no clip "${clip}".`);
3136
+ const stack = _nullishCoalesce(at.clip.effects, () => ( []));
3137
+ const was = stack.find((e) => e.id === instance);
3138
+ if (!was) return this.refused(`Clip "${clip}" has no effect "${instance}"; its effects are ${stack.map((e) => `"${e.id}"`).join(", ") || "none"}.`);
3139
+ const rest = stack.filter((e) => e !== was);
3140
+ const result = rest.length ? this.apply({ op: "update_clip", clip, set: { effects: rest } }, `Remove effect ${_nullishCoalesce(was.name, () => ( was.effect))}`) : this.apply({ op: "update_clip", clip, remove: ["effects"] }, `Remove effect ${_nullishCoalesce(was.name, () => ( was.effect))}`);
3141
+ return result.ok ? { ...result, clip, effect: was } : result;
3142
+ }
3143
+ /**
3144
+ * Sets a provider transition into `clip` from the clip that ends where it starts (centred on the
3145
+ * cut, `duration` ms, default the effect's own length or 1000). One undo step.
3146
+ */
3147
+ setEffectTransition(clip, effect, options = {}) {
3148
+ return this.effectEdit(async () => {
3149
+ this.clipOrThrow(clip);
3150
+ const d = await this.describeEffect(effect, "transition");
3151
+ const values = _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d, options.values);
3152
+ const duration = _nullishCoalesce(_nullishCoalesce(options.duration, () => ( d.duration)), () => ( 1e3));
3153
+ 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 };
3154
+ });
3155
+ }
3156
+ /**
3157
+ * Adds an effect clip: a generator, title or overlay effect drawn over the whole frame for
3158
+ * `duration` ms (default the effect's own length, else 5 s) at `start` (default the end of the
3159
+ * track). One undo step. Returns the new clip's id.
3160
+ */
3161
+ addEffectClip(track, effect, options = {}) {
3162
+ return this.effectEdit(async () => {
3163
+ const d = await this.describeEffect(effect, "generator");
3164
+ const values = _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d, options.values, { keyframes: true });
3165
+ const duration = _nullishCoalesce(_nullishCoalesce(options.duration, () => ( d.duration)), () => ( 5e3));
3166
+ const label = `Add ${d.name}`;
3167
+ const clipId = _nullishCoalesce(options.id, () => ( ""));
3168
+ return {
3169
+ edit: { op: "add_clip", track, mode: options.mode, ripple: options.ripple, clip: { type: "effect", ...options.id ? { id: options.id } : {}, effect: d.id, provider: this.effects.require().id, name: _nullishCoalesce(options.name, () => ( d.name)), values, start: options.start, duration } },
3170
+ label,
3171
+ clip: clipId
3172
+ };
3173
+ }).then((r) => r.ok && !r.clip ? { ...r, clip: _nullishCoalesce(_optionalChain([r, 'access', _91 => _91.outcomes, 'access', _92 => _92[0], 'optionalAccess', _93 => _93.clip]), () => ( "")) } : r);
3174
+ }
3175
+ /**
3176
+ * Changes the values of an effect clip's picture (`target` its id) or of the effect transition
3177
+ * into a clip, merged over the current ones and checked against the provider's controls.
3178
+ * Transition values cannot be keyframed. One undo step.
3179
+ */
3180
+ updateEffectValues(clip, part, values, options = {}) {
3181
+ return this.effectEdit(async () => {
3182
+ const current = this.clipOrThrow(clip);
3183
+ if (part === "generator") {
3184
+ if (current.type !== "effect") throw new Error(`Clip "${clip}" is not an effect clip.`);
3185
+ const d2 = await this.describeEffect(current.effect);
3186
+ return { edit: { op: "update_clip", clip, set: { values: _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d2, values, { base: _nullishCoalesce(current.values, () => ( {})), keyframes: true }) } }, label: `Change ${_nullishCoalesce(current.name, () => ( d2.name))}`, clip };
3187
+ }
3188
+ const t = current.transition;
3189
+ if (_optionalChain([t, 'optionalAccess', _94 => _94.type]) !== "effect" || !t.effect) throw new Error(`Clip "${clip}" has no effect transition.`);
3190
+ const d = await this.describeEffect(t.effect.effect);
3191
+ const merged = _chunkIWSMDQE5cjs.checkVideoEffectValues.call(void 0, d, values, { base: _nullishCoalesce(t.effect.values, () => ( {})) });
3192
+ return { edit: { op: "set_transition", clip, transition: { ...t, effect: { ...t.effect, values: merged } } }, label: `Change transition ${d.name}`, clip };
3193
+ }, options.merge);
3194
+ }
3195
+ /** 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). */
3196
+ setClipEffectKeyframes(clip, instance, control, keys) {
3197
+ const current = _optionalChain([_chunkIWSMDQE5cjs.findVideoClip.call(void 0, this.project, clip), 'optionalAccess', _95 => _95.clip]);
3198
+ const was = _optionalChain([current, 'optionalAccess', _96 => _96.effects, 'optionalAccess', _97 => _97.find, 'call', _98 => _98((e) => e.id === instance)]);
3199
+ const value = _optionalChain([was, 'optionalAccess', _99 => _99.values, 'optionalAccess', _100 => _100[control]]);
3200
+ const plain = keys === null ? _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, value) ? _optionalChain([value, 'access', _101 => _101.keys, 'access', _102 => _102[0], 'optionalAccess', _103 => _103.v]) : value : { keys: [...keys].sort((a, b) => a.t - b.t) };
3201
+ return this.updateClipEffect(clip, instance, { values: { [control]: _nullishCoalesce(plain, () => ( null)) } });
3202
+ }
2926
3203
  /** What plays at `time` (default: the playhead). */
2927
3204
  frame(time = this.player.currentTime) {
2928
- return _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, this.project, time);
3205
+ return _chunkIWSMDQE5cjs.videoFrameAt.call(void 0, this.project, time);
2929
3206
  }
2930
3207
  /** The frame at `time` (default: the playhead) as SVG. */
2931
3208
  toSvg(time = this.player.currentTime, options = {}) {
2932
- return _chunkSMJGE7HMcjs.videoProjectSvg.call(void 0, this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
3209
+ return _chunkIWSMDQE5cjs.videoProjectSvg.call(void 0, this.project, time, { lutFor: (src) => this.luts.peek(src), ...options });
2933
3210
  }
2934
3211
  /** The project as an ffmpeg command. */
2935
3212
  toFfmpeg(options = {}) {
2936
- return _chunkSMJGE7HMcjs.toVideoFfmpeg.call(void 0, this.project, options);
3213
+ return _chunkIWSMDQE5cjs.toVideoFfmpeg.call(void 0, this.project, options);
2937
3214
  }
2938
3215
  /** The ffmpeg command that measures the mix's loudness (see `toVideoLoudnessMeasure`). */
2939
3216
  toLoudnessMeasure(options = {}) {
2940
- return _chunkSMJGE7HMcjs.toVideoLoudnessMeasure.call(void 0, this.project, options);
3217
+ return _chunkIWSMDQE5cjs.toVideoLoudnessMeasure.call(void 0, this.project, options);
2941
3218
  }
2942
3219
  /** One track as a CMX 3600 EDL. */
2943
3220
  toEdl(options = {}) {
2944
- return _chunkSMJGE7HMcjs.toVideoEdl.call(void 0, this.project, options);
3221
+ return _chunkIWSMDQE5cjs.toVideoEdl.call(void 0, this.project, options);
2945
3222
  }
2946
3223
  }, _class6);
2947
3224
  function checkPreviewScale(scale) {
@@ -2960,12 +3237,12 @@ function videoRulerTicks(duration, pxPerSecond, fps) {
2960
3237
  const ticks = [];
2961
3238
  for (let t = 0; t <= duration + 1e-6; t += step) {
2962
3239
  const isMajor = Math.abs(t / major - Math.round(t / major)) < 1e-9;
2963
- ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, t, fps).replace(/^00:/, "") } : {} });
3240
+ ticks.push({ time: t, x: t * pxPerMs, major: isMajor, ...isMajor ? { label: _chunkIWSMDQE5cjs.formatVideoTimecode.call(void 0, t, fps).replace(/^00:/, "") } : {} });
2964
3241
  }
2965
3242
  return ticks;
2966
3243
  }
2967
3244
  function videoClipShowsWaveform(clip, asset, mode = "audio") {
2968
- if (clip.type !== "media" || mode === "none" || !_chunkSMJGE7HMcjs.videoAssetHasSound.call(void 0, asset)) return false;
3245
+ if (clip.type !== "media" || mode === "none" || !_chunkIWSMDQE5cjs.videoAssetHasSound.call(void 0, asset)) return false;
2969
3246
  return mode === "all" || asset.kind === "audio";
2970
3247
  }
2971
3248
  var VIDEO_CLIP_ANIMATION_LABELS = {
@@ -2983,7 +3260,8 @@ var VIDEO_TRANSITION_LABELS = {
2983
3260
  wipe: "Wipe",
2984
3261
  push: "Push",
2985
3262
  slide: "Slide",
2986
- iris: "Iris"
3263
+ iris: "Iris",
3264
+ effect: "Effect"
2987
3265
  };
2988
3266
  var videoTransitionHasDirection = (type) => type === "wipe" || type === "push" || type === "slide";
2989
3267
  var VIDEO_BLEND_MODE_LABELS = {
@@ -3012,6 +3290,7 @@ function videoClipTint(clip, asset) {
3012
3290
  if (clip.type === "text") return "#a855f7";
3013
3291
  if (clip.type === "sequence") return "#0d9488";
3014
3292
  if (clip.type === "color") return clip.color;
3293
+ if (clip.type === "effect") return "#db2777";
3015
3294
  if (!asset) return "#ef4444";
3016
3295
  return asset.kind === "audio" ? "#10b981" : asset.kind === "image" ? "#f59e0b" : "#3b82f6";
3017
3296
  }
@@ -3019,13 +3298,14 @@ function videoClipLabel(clip, asset, sequence) {
3019
3298
  if (clip.name) return clip.name;
3020
3299
  if (clip.type === "text") return clip.text.split("\n")[0];
3021
3300
  if (clip.type === "color") return clip.color;
3022
- if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess', _89 => _89.name]), () => ( clip.sequence))}`;
3023
- const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _90 => _90.name]), () => ( _optionalChain([asset, 'optionalAccess', _91 => _91.src, 'access', _92 => _92.replace, 'call', _93 => _93(/^.*[\\/]/, "")]))), () => ( clip.asset));
3024
- const speed = _chunkSMJGE7HMcjs.videoClipSpeed.call(void 0, clip);
3301
+ if (clip.type === "sequence") return `Compound: ${_nullishCoalesce(_optionalChain([sequence, 'optionalAccess', _104 => _104.name]), () => ( clip.sequence))}`;
3302
+ if (clip.type === "effect") return `Effect: ${clip.effect}`;
3303
+ const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _105 => _105.name]), () => ( _optionalChain([asset, 'optionalAccess', _106 => _106.src, 'access', _107 => _107.replace, 'call', _108 => _108(/^.*[\\/]/, "")]))), () => ( clip.asset));
3304
+ const speed = _chunkIWSMDQE5cjs.videoClipSpeed.call(void 0, clip);
3025
3305
  return speed !== 1 ? `${base} (${Math.round(speed * 100)}%)` : base;
3026
3306
  }
3027
3307
  function planVideoClipDrag(project, input) {
3028
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, input.clip);
3308
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, input.clip);
3029
3309
  if (!at) return null;
3030
3310
  const { clip, track } = at;
3031
3311
  const snap = _nullishCoalesce(input.snap, () => ( ((t) => t)));
@@ -3042,17 +3322,17 @@ function planVideoClipDrag(project, input) {
3042
3322
  }
3043
3323
  const minimum = 1e3 / project.fps;
3044
3324
  if (input.mode === "trim-start") {
3045
- const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - minimum);
3325
+ const to2 = Math.min(snap(Math.max(0, clip.start + input.delta)), _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip) - minimum);
3046
3326
  const changed2 = Math.abs(to2 - clip.start) > 1e-6;
3047
- const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) - to2 };
3327
+ const plan = input.ripple ? { start: clip.start, duration: clip.duration - (to2 - clip.start) } : { start: to2, duration: _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip) - to2 };
3048
3328
  return { ...plan, track: track.id, edit: changed2 ? { op: "trim_clip", clip: clip.id, edge: "start", to: to2, ...input.ripple ? { ripple: true } : {} } : null };
3049
3329
  }
3050
- const to = Math.max(snap(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip) + input.delta), clip.start + minimum);
3051
- const changed = Math.abs(to - _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, clip)) > 1e-6;
3330
+ const to = Math.max(snap(_chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip) + input.delta), clip.start + minimum);
3331
+ const changed = Math.abs(to - _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, clip)) > 1e-6;
3052
3332
  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 };
3053
3333
  }
3054
3334
  function videoDropTracks(project, clipId) {
3055
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
3335
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, clipId);
3056
3336
  if (!at) return [];
3057
3337
  return project.tracks.filter((t) => t.kind === at.track.kind && !t.locked).map((t) => t.id);
3058
3338
  }
@@ -3061,10 +3341,10 @@ function videoDragLabel(edit) {
3061
3341
  return edit.op === "trim_clip" && edit.ripple ? "Ripple trim" : "Trim clip";
3062
3342
  }
3063
3343
  function videoAssetDropEdit(project, assetId, options = {}) {
3064
- const asset = _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project).get(assetId);
3344
+ const asset = _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, project).get(assetId);
3065
3345
  if (!asset) return null;
3066
3346
  const kind = asset.kind === "audio" ? "audio" : "video";
3067
- const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _94 => _94.tracks, 'access', _95 => _95.find, 'call', _96 => _96((t) => t.kind === kind && !t.locked), 'optionalAccess', _97 => _97.id])));
3347
+ const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _109 => _109.tracks, 'access', _110 => _110.find, 'call', _111 => _111((t) => t.kind === kind && !t.locked), 'optionalAccess', _112 => _112.id])));
3068
3348
  if (!track) return null;
3069
3349
  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 } : {} };
3070
3350
  }
@@ -3113,25 +3393,25 @@ var KEY_LABELS = {
3113
3393
  scale: { label: "Scale", step: 0.05 },
3114
3394
  rotation: { label: "Rotation", step: 1 }
3115
3395
  };
3116
- var animatableOf = (clip, property) => _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access', _98 => _98.transform, 'optionalAccess', _99 => _99[property]]) : property === "volume" ? clip.type === "media" || clip.type === "sequence" ? clip.volume : void 0 : clip.opacity;
3396
+ var animatableOf = (clip, property) => _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([clip, 'access', _113 => _113.transform, 'optionalAccess', _114 => _114[property]]) : property === "volume" ? clip.type === "media" || clip.type === "sequence" ? clip.volume : void 0 : clip.opacity;
3117
3397
  var playheadInClip = (clip, time) => Math.round(Math.min(clip.duration, Math.max(0, time - clip.start)));
3118
3398
  function videoKeyframeRows(project, clipId, time) {
3119
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
3399
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, clipId);
3120
3400
  if (!at) return [];
3121
3401
  const { clip } = at;
3122
- const asset = clip.type === "media" ? _chunkSMJGE7HMcjs.videoAssetMap.call(void 0, project).get(clip.asset) : void 0;
3123
- const visual = !(_optionalChain([asset, 'optionalAccess', _100 => _100.kind]) === "audio" || at.track.kind === "audio");
3124
- const audible = clip.type === "media" && _chunkSMJGE7HMcjs.videoAssetHasSound.call(void 0, asset) || clip.type === "sequence";
3125
- const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES : []];
3402
+ const asset = clip.type === "media" ? _chunkIWSMDQE5cjs.videoAssetMap.call(void 0, project).get(clip.asset) : void 0;
3403
+ const visual = !(_optionalChain([asset, 'optionalAccess', _115 => _115.kind]) === "audio" || at.track.kind === "audio");
3404
+ const audible = clip.type === "media" && _chunkIWSMDQE5cjs.videoAssetHasSound.call(void 0, asset) || clip.type === "sequence";
3405
+ const properties = [...visual ? ["opacity"] : [], ...audible ? ["volume"] : [], ...visual ? _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES : []];
3126
3406
  const clipTime = playheadInClip(clip, time);
3127
3407
  return properties.map((property) => {
3128
3408
  const prop = animatableOf(clip, property);
3129
- const keys = _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop) ? prop.keys : [];
3130
- const limits = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property];
3409
+ const keys = _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, prop) ? prop.keys : [];
3410
+ const limits = _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_LIMITS[property];
3131
3411
  return {
3132
3412
  property,
3133
3413
  ...KEY_LABELS[property],
3134
- value: Math.round(_chunkSMJGE7HMcjs.videoValueAt.call(void 0, prop, clipTime, limits.default) * 1e3) / 1e3,
3414
+ value: Math.round(_chunkIWSMDQE5cjs.videoValueAt.call(void 0, prop, clipTime, limits.default) * 1e3) / 1e3,
3135
3415
  keyed: keys.length > 0,
3136
3416
  keys: keys.length,
3137
3417
  onKey: keys.some((k) => Math.abs(k.t - clipTime) < 0.5),
@@ -3142,44 +3422,44 @@ function videoKeyframeRows(project, clipId, time) {
3142
3422
  });
3143
3423
  }
3144
3424
  function plainValueEdit(clip, property, value) {
3145
- if (!_chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property))
3425
+ if (!_chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES.includes(property))
3146
3426
  return value === void 0 ? { op: "update_clip", clip: clip.id, remove: [property] } : { op: "update_clip", clip: clip.id, set: { [property]: value } };
3147
3427
  const transform = { ...clip.transform, [property]: value };
3148
3428
  if (value === void 0) delete transform[property];
3149
3429
  return Object.keys(transform).length ? { op: "update_clip", clip: clip.id, set: { transform } } : { op: "update_clip", clip: clip.id, remove: ["transform"] };
3150
3430
  }
3151
3431
  function videoKeyframeValueEdit(project, clipId, property, time, value) {
3152
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
3432
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, clipId);
3153
3433
  if (!at) return null;
3154
3434
  const prop = animatableOf(at.clip, property);
3155
- if (!_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop)) return plainValueEdit(at.clip, property, value);
3435
+ if (!_chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, prop)) return plainValueEdit(at.clip, property, value);
3156
3436
  if (value === void 0) return null;
3157
- return { op: "set_keyframes", clip: clipId, property, keys: _chunkSMJGE7HMcjs.setVideoKey.call(void 0, prop, { t: playheadInClip(at.clip, time), v: value }, _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property].default).keys };
3437
+ return { op: "set_keyframes", clip: clipId, property, keys: _chunkIWSMDQE5cjs.setVideoKey.call(void 0, prop, { t: playheadInClip(at.clip, time), v: value }, _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_LIMITS[property].default).keys };
3158
3438
  }
3159
3439
  function videoKeyframeToggleEdit(project, clipId, property, time) {
3160
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, clipId);
3440
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, clipId);
3161
3441
  if (!at) return null;
3162
3442
  const prop = animatableOf(at.clip, property);
3163
3443
  const t = playheadInClip(at.clip, time);
3164
- const fallback = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS[property].default;
3165
- if (_chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop)) {
3444
+ const fallback = _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_LIMITS[property].default;
3445
+ if (_chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, prop)) {
3166
3446
  const key = prop.keys.find((k) => Math.abs(k.t - t) < 0.5);
3167
3447
  if (key) {
3168
- const rest = _chunkSMJGE7HMcjs.removeVideoKey.call(void 0, prop, key.t);
3169
- return _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
3448
+ const rest = _chunkIWSMDQE5cjs.removeVideoKey.call(void 0, prop, key.t);
3449
+ return _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, rest) ? { op: "set_keyframes", clip: clipId, property, keys: rest.keys } : plainValueEdit(at.clip, property, rest === fallback ? void 0 : rest);
3170
3450
  }
3171
3451
  }
3172
- const v = _chunkSMJGE7HMcjs.videoValueAt.call(void 0, prop, t, fallback);
3173
- return { op: "set_keyframes", clip: clipId, property, keys: _chunkSMJGE7HMcjs.isVideoKeyframes.call(void 0, prop) ? _chunkSMJGE7HMcjs.setVideoKey.call(void 0, prop, { t, v }, fallback).keys : [{ t, v }] };
3452
+ const v = _chunkIWSMDQE5cjs.videoValueAt.call(void 0, prop, t, fallback);
3453
+ return { op: "set_keyframes", clip: clipId, property, keys: _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, prop) ? _chunkIWSMDQE5cjs.setVideoKey.call(void 0, prop, { t, v }, fallback).keys : [{ t, v }] };
3174
3454
  }
3175
3455
  function videoLutEdits(project, clips, lut) {
3176
3456
  const edits = [];
3177
3457
  for (const id of clips) {
3178
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project, id);
3458
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project, id);
3179
3459
  if (!at) continue;
3180
3460
  const { lut: current, ...rest } = _nullishCoalesce(at.clip.grade, () => ( {}));
3181
3461
  if (!lut && !current) continue;
3182
- const grade = _chunkSMJGE7HMcjs.normalizeVideoGrade.call(void 0, lut ? { ...rest, lut } : rest);
3462
+ const grade = _chunkIWSMDQE5cjs.normalizeVideoGrade.call(void 0, lut ? { ...rest, lut } : rest);
3183
3463
  edits.push(grade ? { op: "update_clip", clip: id, set: { grade } } : { op: "update_clip", clip: id, remove: ["grade"] });
3184
3464
  }
3185
3465
  return edits;
@@ -3209,7 +3489,7 @@ var RIPPLE = {
3209
3489
  };
3210
3490
  var MODE = {
3211
3491
  type: "string",
3212
- enum: [..._chunkSMJGE7HMcjs.VIDEO_PLACEMENT_MODES],
3492
+ enum: [..._chunkIWSMDQE5cjs.VIDEO_PLACEMENT_MODES],
3213
3493
  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.'
3214
3494
  };
3215
3495
  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.` });
@@ -3226,11 +3506,11 @@ var TRANSFORM = object(
3226
3506
  );
3227
3507
  var TRANSITION = object(
3228
3508
  {
3229
- type: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES], 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)." },
3509
+ type: { type: "string", enum: _chunkIWSMDQE5cjs.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." },
3230
3510
  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." },
3231
3511
  color: COLOR("For dip: the colour passed through (default black)"),
3232
- direction: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
3233
- audioCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.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." }
3512
+ direction: { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_WIPE_DIRECTIONS], description: "For wipe, push and slide: the way the edge or picture travels (default right, coming in from the left)." },
3513
+ audioCurve: { type: "string", enum: [..._chunkIWSMDQE5cjs.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." }
3234
3514
  },
3235
3515
  ["type", "duration"],
3236
3516
  "A transition from the clip that ends where this one starts on the same track."
@@ -3239,7 +3519,7 @@ var LUT_SRC = { type: "string", minLength: 1, description: 'A .cube 3D LUT file
3239
3519
  var LUT_STRENGTH = { type: "number", minimum: 0, maximum: 1, description: "How much of the LUT's change to apply, 0 (none) to 1 (full, the default); 0.3-0.7 for a subtler look." };
3240
3520
  var GRADE = object(
3241
3521
  {
3242
- ...Object.fromEntries(_chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
3522
+ ...Object.fromEntries(_chunkIWSMDQE5cjs.VIDEO_GRADE_CONTROLS.map((c) => [c.key, { type: "number", minimum: c.min, maximum: c.max, description: c.description }])),
3243
3523
  lut: object({ src: LUT_SRC, strength: LUT_STRENGTH, name: { type: "string", minLength: 1, description: "A label for the look." } }, ["src"], "A 3D LUT applied after the other settings (set_video_lut checks the file first).")
3244
3524
  },
3245
3525
  [],
@@ -3247,7 +3527,7 @@ var GRADE = object(
3247
3527
  );
3248
3528
  var ANIMATION = (when) => object(
3249
3529
  {
3250
- effect: { type: "string", enum: [..._chunkSMJGE7HMcjs.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." },
3530
+ effect: { type: "string", enum: [..._chunkIWSMDQE5cjs.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." },
3251
3531
  duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default 500)." }
3252
3532
  },
3253
3533
  ["effect"],
@@ -3257,11 +3537,11 @@ var CLIP_COMMON = {
3257
3537
  name: { type: "string", description: "A label for the clip." },
3258
3538
  opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0\u20131 (default 1). A number replaces any keyframes; set_video_keyframes animates it." },
3259
3539
  transform: TRANSFORM,
3260
- fit: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
3540
+ fit: { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_FITS], description: "How the picture fits the frame before the transform, as CSS object-fit (default contain for media, fill for colours)." },
3261
3541
  grade: GRADE,
3262
3542
  animateIn: ANIMATION("How the picture enters, from the clip's start (on top of any fade in). Titles usually rise, pop or fade in."),
3263
3543
  animateOut: ANIMATION("How the picture leaves, ending at the clip's end."),
3264
- blend: { type: "string", enum: [..._chunkSMJGE7HMcjs.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." },
3544
+ blend: { type: "string", enum: [..._chunkIWSMDQE5cjs.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." },
3265
3545
  fadeIn: MS("Fade up from nothing (picture and sound) over this long"),
3266
3546
  fadeOut: MS("Fade down to nothing over this long")
3267
3547
  };
@@ -3270,8 +3550,8 @@ var MEDIA_FIELDS = {
3270
3550
  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." },
3271
3551
  volume: { type: "number", minimum: 0, maximum: 4, description: "Gain (1 = unchanged, default 1). A number replaces any keyframes; set_video_keyframes animates it." },
3272
3552
  muted: { type: "boolean", description: "Silence this clip (default false)." },
3273
- fadeInCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.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)." },
3274
- fadeOutCurve: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
3553
+ fadeInCurve: { type: "string", enum: [..._chunkIWSMDQE5cjs.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)." },
3554
+ fadeOutCurve: { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_FADE_CURVES], description: "Shape of the sound's fade out (default linear), the same choices as fadeInCurve; exponential sounds natural fading to silence." }
3275
3555
  };
3276
3556
  var TEXT_FIELDS = {
3277
3557
  text: { type: "string", minLength: 1, description: `The title's text ("\\n" breaks lines).` },
@@ -3320,7 +3600,7 @@ var ASSET_FIELDS = {
3320
3600
  };
3321
3601
  var KEY_PROPERTY = {
3322
3602
  type: "string",
3323
- enum: [..._chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES],
3603
+ enum: [..._chunkIWSMDQE5cjs.VIDEO_KEYFRAME_PROPERTIES],
3324
3604
  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)."
3325
3605
  };
3326
3606
  var KEYS = {
@@ -3335,7 +3615,7 @@ var KEYS = {
3335
3615
  ease: {
3336
3616
  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.",
3337
3617
  anyOf: [
3338
- { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_EASE_NAMES] },
3618
+ { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_EASE_NAMES] },
3339
3619
  { type: "array", items: { type: "number" }, minItems: 4, maxItems: 4 }
3340
3620
  ]
3341
3621
  }
@@ -3364,19 +3644,19 @@ var describeVideoTracks = (tracks) => tracks.map((t, index) => ({
3364
3644
  ...t.locked ? { locked: true } : {},
3365
3645
  ...t.syncLocked === false ? { syncLocked: false } : {},
3366
3646
  ...t.volume !== void 0 ? { volume: t.volume } : {},
3367
- clips: _chunkSMJGE7HMcjs.sortedVideoClips.call(void 0, t).map((c) => ({ ...c, end: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) } : {} }))
3647
+ clips: _chunkIWSMDQE5cjs.sortedVideoClips.call(void 0, t).map((c) => ({ ...c, end: _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkIWSMDQE5cjs.videoClipSourceRange.call(void 0, c) } : {} }))
3368
3648
  }));
3369
- var videoSequenceUsers = (project, id) => _chunkSMJGE7HMcjs.allVideoTracks.call(void 0, project).flatMap(
3370
- ({ 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: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) }] : [])
3649
+ var videoSequenceUsers = (project, id) => _chunkIWSMDQE5cjs.allVideoTracks.call(void 0, project).flatMap(
3650
+ ({ 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: _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c), source: _chunkIWSMDQE5cjs.videoClipSourceRange.call(void 0, c) }] : [])
3371
3651
  );
3372
3652
  function describeVideoSequence(project, sequence, tracks = true) {
3373
- const cycle = _chunkSMJGE7HMcjs.findVideoSequenceCycle.call(void 0, project, sequence.id);
3653
+ const cycle = _chunkIWSMDQE5cjs.findVideoSequenceCycle.call(void 0, project, sequence.id);
3374
3654
  return {
3375
3655
  id: sequence.id,
3376
3656
  ...sequence.name ? { name: sequence.name } : {},
3377
- duration: _chunkSMJGE7HMcjs.videoSequenceDuration.call(void 0, sequence),
3657
+ duration: _chunkIWSMDQE5cjs.videoSequenceDuration.call(void 0, sequence),
3378
3658
  clipCount: sequence.tracks.reduce((n, t) => n + t.clips.length, 0),
3379
- nests: _chunkSMJGE7HMcjs.videoSequenceChildren.call(void 0, sequence),
3659
+ nests: _chunkIWSMDQE5cjs.videoSequenceChildren.call(void 0, sequence),
3380
3660
  usedBy: videoSequenceUsers(project, sequence.id),
3381
3661
  ...cycle ? { cycle } : {},
3382
3662
  ...tracks ? { tracks: describeVideoTracks(sequence.tracks) } : { trackCount: sequence.tracks.length }
@@ -3388,11 +3668,11 @@ function describeVideoProject(project) {
3388
3668
  width: project.width,
3389
3669
  height: project.height,
3390
3670
  fps: project.fps,
3391
- duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project),
3671
+ duration: _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, project),
3392
3672
  ...project.background ? { background: project.background } : {},
3393
3673
  assets: project.assets.map(videoAssetOut),
3394
3674
  tracks: describeVideoTracks(project.tracks),
3395
- ..._optionalChain([project, 'access', _101 => _101.sequences, 'optionalAccess', _102 => _102.length]) ? { sequences: project.sequences.map((q) => describeVideoSequence(project, q, false)) } : {},
3675
+ ..._optionalChain([project, 'access', _116 => _116.sequences, 'optionalAccess', _117 => _117.length]) ? { sequences: project.sequences.map((q) => describeVideoSequence(project, q, false)) } : {},
3396
3676
  markers: _nullishCoalesce(project.markers, () => ( []))
3397
3677
  };
3398
3678
  }
@@ -3405,7 +3685,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3405
3685
  const project = () => controller.getProject();
3406
3686
  const outcome = (result, extra = {}) => {
3407
3687
  if (!result.ok) throw new Error(result.error);
3408
- return { ...extra, duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, result.project), issues: issueSummary(result.issues) };
3688
+ return { ...extra, duration: _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, result.project), issues: issueSummary(result.issues) };
3409
3689
  };
3410
3690
  const apply = (edits, label, extra) => {
3411
3691
  const result = controller.apply(edits, label);
@@ -3414,19 +3694,19 @@ function createVideoEditorToolProvider(controller, options = {}) {
3414
3694
  const clipOut = (p, id) => {
3415
3695
  for (const t of p.tracks) {
3416
3696
  const c = t.clips.find((x) => x.id === id);
3417
- if (c) return { track: t.id, ...c, end: _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkSMJGE7HMcjs.videoClipSourceRange.call(void 0, c) } : {} };
3697
+ if (c) return { track: t.id, ...c, end: _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c), ...c.type === "media" || c.type === "sequence" ? { source: _chunkIWSMDQE5cjs.videoClipSourceRange.call(void 0, c) } : {} };
3418
3698
  }
3419
3699
  return null;
3420
3700
  };
3421
3701
  const placed = (o) => ({
3422
- ..._optionalChain([o, 'access', _103 => _103.created, 'optionalAccess', _104 => _104.length]) ? { created: o.created } : {},
3423
- ..._optionalChain([o, 'access', _105 => _105.trimmed, 'optionalAccess', _106 => _106.length]) ? { trimmed: o.trimmed } : {},
3424
- ..._optionalChain([o, 'access', _107 => _107.removed, 'optionalAccess', _108 => _108.length]) ? { removed: o.removed } : {},
3702
+ ..._optionalChain([o, 'access', _118 => _118.created, 'optionalAccess', _119 => _119.length]) ? { created: o.created } : {},
3703
+ ..._optionalChain([o, 'access', _120 => _120.trimmed, 'optionalAccess', _121 => _121.length]) ? { trimmed: o.trimmed } : {},
3704
+ ..._optionalChain([o, 'access', _122 => _122.removed, 'optionalAccess', _123 => _123.length]) ? { removed: o.removed } : {},
3425
3705
  ...o.rippled ? { rippled: o.rippled } : {}
3426
3706
  });
3427
3707
  const keysOut = (p, clip, property) => {
3428
3708
  const c = clipOut(p, clip);
3429
- const value = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess', _109 => _109.transform, 'optionalAccess', _110 => _110[property]]) : _optionalChain([c, 'optionalAccess', _111 => _111[property]]);
3709
+ const value = _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES.includes(property) ? _optionalChain([c, 'optionalAccess', _124 => _124.transform, 'optionalAccess', _125 => _125[property]]) : _optionalChain([c, 'optionalAccess', _126 => _126[property]]);
3430
3710
  return typeof value === "object" ? { keys: value.keys } : { keys: [], value: _nullishCoalesce(value, () => ( null)) };
3431
3711
  };
3432
3712
  const getProject = {
@@ -3448,8 +3728,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
3448
3728
  inputSchema: object({ time: MS("Time from the start (default: the playhead)") }),
3449
3729
  annotations: { title: "What plays at a moment", ...READ },
3450
3730
  handler: ({ time }) => {
3451
- const frame = _chunkSMJGE7HMcjs.videoFrameAt.call(void 0, project(), _nullishCoalesce(time, () => ( controller.getState().time)));
3452
- return { ...frame, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, frame.time, project().fps) };
3731
+ const frame = _chunkIWSMDQE5cjs.videoFrameAt.call(void 0, project(), _nullishCoalesce(time, () => ( controller.getState().time)));
3732
+ return { ...frame, timecode: _chunkIWSMDQE5cjs.formatVideoTimecode.call(void 0, frame.time, project().fps) };
3453
3733
  }
3454
3734
  };
3455
3735
  const listSequences = {
@@ -3477,7 +3757,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3477
3757
  annotations: { title: "Find gaps", ...READ },
3478
3758
  handler: ({ track }) => {
3479
3759
  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(", ")}.`);
3480
- return { gaps: _chunkSMJGE7HMcjs.findVideoGaps.call(void 0, project(), track) };
3760
+ return { gaps: _chunkIWSMDQE5cjs.findVideoGaps.call(void 0, project(), track) };
3481
3761
  }
3482
3762
  };
3483
3763
  const checkProject = {
@@ -3504,10 +3784,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
3504
3784
  annotations: { title: "Render a frame", ...READ },
3505
3785
  handler: async ({ time, times, columns, format = "svg" }) => {
3506
3786
  const p = project();
3507
- const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access', _112 => _112.grade, 'optionalAccess', _113 => _113.lut, 'optionalAccess', _114 => _114.src])).filter((x) => !!x)))];
3787
+ const lutSrcs = [...new Set(p.tracks.flatMap((t) => t.clips.map((c) => _optionalChain([c, 'access', _127 => _127.grade, 'optionalAccess', _128 => _128.lut, 'optionalAccess', _129 => _129.src])).filter((x) => !!x)))];
3508
3788
  const missing = (await Promise.all(lutSrcs.map((src) => controller.luts.load(src).then(() => null, (e) => e.message)))).filter((m) => !!m);
3509
3789
  const svgOptions = { lutFor: (src) => controller.luts.peek(src), ...columns ? { columns } : {} };
3510
- const svg = times ? _chunkSMJGE7HMcjs.videoContactSheetSvg.call(void 0, p, times, svgOptions) : _chunkSMJGE7HMcjs.videoProjectSvg.call(void 0, p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
3790
+ const svg = times ? _chunkIWSMDQE5cjs.videoContactSheetSvg.call(void 0, p, times, svgOptions) : _chunkIWSMDQE5cjs.videoProjectSvg.call(void 0, p, _nullishCoalesce(time, () => ( controller.getState().time)), svgOptions);
3511
3791
  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."] : []];
3512
3792
  if (format === "png") {
3513
3793
  if (!options.rasterize) throw new Error('This host cannot make PNG images; call render_video_frame with format "svg".');
@@ -3597,7 +3877,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3597
3877
  if (play === true) controller.play();
3598
3878
  if (play === false) controller.pause();
3599
3879
  const state = controller.getState();
3600
- return { time: state.time, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, state.time, p.fps), playing: state.playing, clips: state.current };
3880
+ return { time: state.time, timecode: _chunkIWSMDQE5cjs.formatVideoTimecode.call(void 0, state.time, p.fps), playing: state.playing, clips: state.current };
3601
3881
  }
3602
3882
  };
3603
3883
  const setSettings = {
@@ -3742,10 +4022,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
3742
4022
  const gradeTargets = (ids) => {
3743
4023
  const p = project();
3744
4024
  for (const id of ids) {
3745
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, id);
4025
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, p, id);
3746
4026
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
3747
4027
  const { clip } = at;
3748
- if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access', _115 => _115.assets, 'access', _116 => _116.find, 'call', _117 => _117((a) => a.id === clip.asset), 'optionalAccess', _118 => _118.kind]) === "audio")
4028
+ if (at.track.kind !== "video" || clip.type === "media" && _optionalChain([p, 'access', _130 => _130.assets, 'access', _131 => _131.find, 'call', _132 => _132((a) => a.id === clip.asset), 'optionalAccess', _133 => _133.kind]) === "audio")
3749
4029
  throw new Error(`Clip "${id}" is sound only; grades change pictures. Pass clips on video tracks.`);
3750
4030
  }
3751
4031
  };
@@ -3756,7 +4036,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3756
4036
  inputSchema: object(
3757
4037
  {
3758
4038
  clips: { type: "array", items: CLIP_ID, minItems: 1, description: "Clips on video tracks to grade." },
3759
- preset: { type: "string", enum: [..._chunkSMJGE7HMcjs.VIDEO_GRADE_PRESET_NAMES], description: "The look." },
4039
+ preset: { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_GRADE_PRESET_NAMES], description: "The look." },
3760
4040
  amount: { type: "number", minimum: 0, maximum: 1, description: "Strength, 0 (none) to 1 (full, the default); 0.5 is a subtler version." }
3761
4041
  },
3762
4042
  ["clips", "preset"]
@@ -3765,10 +4045,10 @@ function createVideoEditorToolProvider(controller, options = {}) {
3765
4045
  handler: ({ clips, preset, amount }) => {
3766
4046
  gradeTargets(clips);
3767
4047
  const edits = clips.map((clip) => {
3768
- const grade = _chunkSMJGE7HMcjs.videoGradeLook.call(void 0, _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
4048
+ const grade = _chunkIWSMDQE5cjs.videoGradeLook.call(void 0, _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project(), clip).clip.grade, preset, _nullishCoalesce(amount, () => ( 1)));
3769
4049
  return grade ? { op: "update_clip", clip, set: { grade } } : { op: "update_clip", clip, remove: ["grade"] };
3770
4050
  });
3771
- return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _119 => _119.clip, 'access', _120 => _120.grade]), () => ( null)) })) }));
4051
+ return apply(edits, `Apply ${preset} look`, (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkIWSMDQE5cjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _134 => _134.clip, 'access', _135 => _135.grade]), () => ( null)) })) }));
3772
4052
  }
3773
4053
  };
3774
4054
  const copyGrade = {
@@ -3779,7 +4059,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3779
4059
  annotations: { title: "Copy a colour grade", ...WRITE_IDEMPOTENT },
3780
4060
  handler: ({ from, to }) => {
3781
4061
  gradeTargets([from, ...to]);
3782
- const grade = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), from).clip.grade;
4062
+ const grade = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project(), from).clip.grade;
3783
4063
  const edits = to.map((clip) => grade ? { op: "update_clip", clip, set: { grade: { ...grade } } } : { op: "update_clip", clip, remove: ["grade"] });
3784
4064
  return apply(edits, "Copy grade", () => ({ grade: _nullishCoalesce(grade, () => ( null)), clips: to }));
3785
4065
  }
@@ -3804,7 +4084,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3804
4084
  const lut = await controller.luts.load(src);
3805
4085
  const label = _nullishCoalesce(name, () => ( lut.title));
3806
4086
  const setting = { src, ...strength !== void 0 && strength !== 1 ? { strength } : {}, ...label ? { name: label } : {} };
3807
- 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([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _121 => _121.clip, 'access', _122 => _122.grade]), () => ( null)) })) }));
4087
+ 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([_chunkIWSMDQE5cjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _136 => _136.clip, 'access', _137 => _137.grade]), () => ( null)) })) }));
3808
4088
  }
3809
4089
  };
3810
4090
  const removeLut = {
@@ -3816,9 +4096,9 @@ function createVideoEditorToolProvider(controller, options = {}) {
3816
4096
  handler: ({ clips }) => {
3817
4097
  gradeTargets(clips);
3818
4098
  const p = project();
3819
- const withLut = clips.filter((id) => _optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, id), 'access', _123 => _123.clip, 'access', _124 => _124.grade, 'optionalAccess', _125 => _125.lut]));
4099
+ const withLut = clips.filter((id) => _optionalChain([_chunkIWSMDQE5cjs.findVideoClip.call(void 0, p, id), 'access', _138 => _138.clip, 'access', _139 => _139.grade, 'optionalAccess', _140 => _140.lut]));
3820
4100
  if (!withLut.length) throw new Error(`None of ${clips.map((c) => `"${c}"`).join(", ")} has a LUT; get_video_project shows each clip's grade.`);
3821
- return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkSMJGE7HMcjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _126 => _126.clip, 'access', _127 => _127.grade]), () => ( null)) })) }));
4101
+ return apply(videoLutEdits(p, withLut, null), "Remove LUT", (r) => ({ clips: clips.map((id) => ({ id, grade: _nullishCoalesce(_optionalChain([_chunkIWSMDQE5cjs.findVideoClip.call(void 0, r.project, id), 'optionalAccess', _141 => _141.clip, 'access', _142 => _142.grade]), () => ( null)) })) }));
3822
4102
  }
3823
4103
  };
3824
4104
  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." };
@@ -3876,7 +4156,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3876
4156
  controller.setPreviewScale(scale);
3877
4157
  const s = controller.getState().previewScale;
3878
4158
  const fixed = s === "full" ? 1 : typeof s === "number" ? s : null;
3879
- const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _128 => _128(a, fixed), 'optionalAccess', _129 => _129.src]), () => ( a.src)), proxy: !!videoAssetProxy(a, fixed) }));
4159
+ const plays = fixed === null ? void 0 : project().assets.filter((a) => a.kind === "video").map((a) => ({ asset: a.id, src: _nullishCoalesce(_optionalChain([videoAssetProxy, 'call', _143 => _143(a, fixed), 'optionalAccess', _144 => _144.src]), () => ( a.src)), proxy: !!videoAssetProxy(a, fixed) }));
3880
4160
  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." } };
3881
4161
  }
3882
4162
  };
@@ -3927,7 +4207,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3927
4207
  approximate: parsed.approximate,
3928
4208
  first: list[0],
3929
4209
  last: list[list.length - 1],
3930
- ...a.duration !== void 0 && list[list.length - 1].end > a.duration + _chunkSMJGE7HMcjs.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?` } : {}
4210
+ ...a.duration !== void 0 && list[list.length - 1].end > a.duration + _chunkIWSMDQE5cjs.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?` } : {}
3931
4211
  }));
3932
4212
  }
3933
4213
  };
@@ -3945,7 +4225,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
3945
4225
  handler: ({ track, from, to, limit }) => {
3946
4226
  const all = timelineWords(track).filter((w) => w.end > (_nullishCoalesce(from, () => ( 0))) && w.start < (_nullishCoalesce(to, () => ( Infinity))));
3947
4227
  const words = all.slice(0, _nullishCoalesce(limit, () => ( 1e3)));
3948
- return { track: _nullishCoalesce(_optionalChain([words, 'access', _130 => _130[0], 'optionalAccess', _131 => _131.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 };
4228
+ return { track: _nullishCoalesce(_optionalChain([words, 'access', _145 => _145[0], 'optionalAccess', _146 => _146.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 };
3949
4229
  }
3950
4230
  };
3951
4231
  const findText = {
@@ -3998,22 +4278,22 @@ function createVideoEditorToolProvider(controller, options = {}) {
3998
4278
  const bad = ranges.findIndex((r) => !(r.to > r.from));
3999
4279
  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".`);
4000
4280
  const merged = mergeVideoRanges(ranges);
4001
- const before = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, project());
4002
- return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project)), duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project) }));
4281
+ const before = _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, project());
4282
+ return apply(videoRemoveRangesEdits(merged, tracks), merged.length > 1 ? `Cut ${merged.length} stretches` : "Cut stretch", (r) => ({ removed: merged.length, time: round(before - _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, r.project)), duration: _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, r.project) }));
4003
4283
  }
4004
4284
  };
4005
4285
  const rampTarget = (id) => {
4006
- const at = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, project(), id);
4286
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, project(), id);
4007
4287
  if (!at) throw new Error(`There is no clip "${id}"; get_video_project lists the clips.`);
4008
4288
  const { clip } = at;
4009
4289
  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.`);
4010
- if (clip.type !== "media") throw new Error(`Clip "${id}" is a ${clip.type === "text" ? "title" : "colour"}, so it has no source to change the speed of; use a video or audio clip.`);
4011
- if (_optionalChain([project, 'call', _132 => _132(), 'access', _133 => _133.assets, 'access', _134 => _134.find, 'call', _135 => _135((a) => a.id === clip.asset), 'optionalAccess', _136 => _136.kind]) === "image") throw new Error(`Clip "${id}" is a still, so it has no motion to change the speed of.`);
4290
+ if (clip.type !== "media") throw new Error(`Clip "${id}" is a ${clip.type === "text" ? "title" : clip.type === "effect" ? "effect clip" : "colour"}, so it has no source to change the speed of; use a video or audio clip.`);
4291
+ if (_optionalChain([project, 'call', _147 => _147(), 'access', _148 => _148.assets, 'access', _149 => _149.find, 'call', _150 => _150((a) => a.id === clip.asset), 'optionalAccess', _151 => _151.kind]) === "image") throw new Error(`Clip "${id}" is a still, so it has no motion to change the speed of.`);
4012
4292
  return clip;
4013
4293
  };
4014
4294
  const rampOut = (r, id) => {
4015
4295
  const outcome2 = r.outcomes[r.outcomes.length - 1];
4016
- return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, r.project) };
4296
+ return { clip: clipOut(r.project, id), ...outcome2.rippled ? { rippled: outcome2.rippled } : {}, duration: _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, r.project) };
4017
4297
  };
4018
4298
  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." };
4019
4299
  const setSpeedRamp = {
@@ -4044,8 +4324,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
4044
4324
  ),
4045
4325
  annotations: { title: "Ramp the speed", ...WRITE_IDEMPOTENT },
4046
4326
  handler: ({ clip, segments, ripple }) => {
4047
- const edit = _chunkSMJGE7HMcjs.videoSpeedRampEdit.call(void 0, rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
4048
- return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(_chunkSMJGE7HMcjs.videoSpeedRampKeys.call(void 0, segments).source) }));
4327
+ const edit = _chunkIWSMDQE5cjs.videoSpeedRampEdit.call(void 0, rampTarget(clip), segments, _nullishCoalesce(ripple, () => ( true)));
4328
+ return apply(edit, "Speed ramp", (r) => ({ ...rampOut(r, clip), source: Math.round(_chunkIWSMDQE5cjs.videoSpeedRampKeys.call(void 0, segments).source) }));
4049
4329
  }
4050
4330
  };
4051
4331
  const addFreeze = {
@@ -4065,8 +4345,8 @@ function createVideoEditorToolProvider(controller, options = {}) {
4065
4345
  handler: ({ clip, at, duration, ripple }) => {
4066
4346
  const c = rampTarget(clip);
4067
4347
  const t = at - c.start;
4068
- if (t < 0 || t > c.duration) throw new Error(`${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, at)} is outside clip "${clip}" (${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, c.start)}\u2013${_chunkSMJGE7HMcjs.formatVideoSeconds.call(void 0, _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c))}); pick a time inside it.`);
4069
- return apply(_chunkSMJGE7HMcjs.videoFreezeFrameEdit.call(void 0, c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
4348
+ if (t < 0 || t > c.duration) throw new Error(`${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, at)} is outside clip "${clip}" (${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, c.start)}\u2013${_chunkIWSMDQE5cjs.formatVideoSeconds.call(void 0, _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c))}); pick a time inside it.`);
4349
+ return apply(_chunkIWSMDQE5cjs.videoFreezeFrameEdit.call(void 0, c, t, duration, _nullishCoalesce(ripple, () => ( true))), "Freeze frame", (r) => rampOut(r, clip));
4070
4350
  }
4071
4351
  };
4072
4352
  const removeRamp = {
@@ -4239,7 +4519,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4239
4519
  let from;
4240
4520
  let to;
4241
4521
  if (args.clip !== void 0) {
4242
- const found = _chunkSMJGE7HMcjs.findVideoClip.call(void 0, p, args.clip);
4522
+ const found = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, p, args.clip);
4243
4523
  if (!found) throw new Error(`There is no clip "${args.clip}"; get_video_project lists the clips.`);
4244
4524
  const c = found.clip;
4245
4525
  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).`);
@@ -4249,7 +4529,7 @@ function createVideoEditorToolProvider(controller, options = {}) {
4249
4529
  toSource = (t) => (_nullishCoalesce(c.in, () => ( 0))) + (t - c.start) * speed;
4250
4530
  toOut = (s) => c.start + (s - (_nullishCoalesce(c.in, () => ( 0)))) / speed;
4251
4531
  from = Math.max(c.start, _nullishCoalesce(args.from, () => ( c.start)));
4252
- to = Math.min(_chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c), _nullishCoalesce(args.to, () => ( _chunkSMJGE7HMcjs.videoClipEnd.call(void 0, c))));
4532
+ to = Math.min(_chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c), _nullishCoalesce(args.to, () => ( _chunkIWSMDQE5cjs.videoClipEnd.call(void 0, c))));
4253
4533
  } else {
4254
4534
  asset = p.assets.find((a) => a.id === args.asset);
4255
4535
  if (!asset) throw new Error(`There is no asset "${args.asset}"; the assets are ${p.assets.map((a) => `"${a.id}"`).join(", ") || "none"}.`);
@@ -4330,11 +4610,11 @@ function createVideoEditorToolProvider(controller, options = {}) {
4330
4610
  annotations: { title: "Measure a frame with scopes", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
4331
4611
  handler: async ({ time, bins, columns }) => {
4332
4612
  const p = project();
4333
- const end = _chunkSMJGE7HMcjs.videoProjectDuration.call(void 0, p);
4613
+ const end = _chunkIWSMDQE5cjs.videoProjectDuration.call(void 0, p);
4334
4614
  const t = _nullishCoalesce(time, () => ( controller.getState().time));
4335
4615
  if (time !== void 0 && time > end) throw new Error(`Time ${time} ms is past the end of the project (${end} ms).`);
4336
4616
  const pixels = await pixelsAt(t);
4337
- return { time: t, timecode: _chunkSMJGE7HMcjs.formatVideoTimecode.call(void 0, t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
4617
+ return { time: t, timecode: _chunkIWSMDQE5cjs.formatVideoTimecode.call(void 0, t, p.fps), width: pixels.width, height: pixels.height, ...summarizeVideoScopes(pixels, { bins, columns }) };
4338
4618
  }
4339
4619
  };
4340
4620
  const reads = [getProject, listSequences, getFrame, getTranscript, findText, findFillers, findPauses, findGaps, checkProject, renderFrame, getScopes, previewCache, planProxies, exportFfmpeg, exportLoudnessMeasure, exportEdl, audioLevels, findSilences, seek, setPreviewScale];
@@ -4356,6 +4636,198 @@ function createVideoEditorToolProvider(controller, options = {}) {
4356
4636
  };
4357
4637
  }
4358
4638
 
4639
+ // src/video-editor/effect-tools.ts
4640
+ function videoClipAppliedEffects(clip) {
4641
+ const out = [];
4642
+ const ref = (r) => ({ effect: r.effect, ...r.name ? { name: r.name } : {}, ...r.provider ? { provider: r.provider } : {} });
4643
+ if (clip.type === "effect") out.push({ id: "generator", ...ref(clip), role: "effect clip", enabled: true, values: _nullishCoalesce(clip.values, () => ( {})) });
4644
+ if (_optionalChain([clip, 'access', _152 => _152.transition, 'optionalAccess', _153 => _153.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 });
4645
+ (_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 }));
4646
+ return out;
4647
+ }
4648
+ var MS2 = (what) => ({ type: "number", minimum: 0, description: `${what}, in milliseconds.` });
4649
+ var KEYS2 = {
4650
+ type: "array",
4651
+ minItems: 1,
4652
+ items: {
4653
+ type: "object",
4654
+ properties: {
4655
+ t: { type: "number", description: "Clip-relative time in ms (0 = the clip's start)." },
4656
+ v: { type: "number", description: "The control's value at t, within its range from describe_effect." },
4657
+ ease: { anyOf: [{ type: "string", enum: [..._chunkIWSMDQE5cjs.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]." }
4658
+ },
4659
+ required: ["t", "v"],
4660
+ additionalProperties: false
4661
+ },
4662
+ description: "Keys in any order (sorted for you), one per time."
4663
+ };
4664
+ function createVideoEffectsToolProvider(controller, options = {}) {
4665
+ const readOnlyReason = () => {
4666
+ const ro = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
4667
+ if (ro) return typeof ro === "string" ? ro : "The video project is read-only.";
4668
+ return controller.readOnlyReason();
4669
+ };
4670
+ const clipOf = (id) => {
4671
+ const at = _chunkIWSMDQE5cjs.findVideoClip.call(void 0, controller.getProject(), id);
4672
+ if (!at) {
4673
+ const ids = controller.getProject().tracks.flatMap((t) => t.clips.map((c) => c.id));
4674
+ throw new Error(`There is no clip "${id}"; the clips are ${ids.map((c) => `"${c}"`).join(", ") || "none"} (get_video_project lists them).`);
4675
+ }
4676
+ return at.clip;
4677
+ };
4678
+ const result = (r, target, instance, extra = {}) => {
4679
+ if (!r.ok) throw new Error(r.error);
4680
+ const effects = videoClipAppliedEffects(clipOf(target));
4681
+ const effect = _nullishCoalesce(effects.find((e) => e.id === (_nullishCoalesce(instance, () => ( _optionalChain([r, 'access', _154 => _154.effect, 'optionalAccess', _155 => _155.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])));
4682
+ return { target, effect, effects, ...extra };
4683
+ };
4684
+ return _chunkTK53AB4Qcjs.createEffectToolProvider.call(void 0, {
4685
+ id: _nullishCoalesce(options.id, () => ( "video-effects")),
4686
+ namespace: options.namespace,
4687
+ target: { noun: "clip", id: 'A clip id from get_video_project (e.g. "c1").' },
4688
+ applyUses: ["filter", "overlay"],
4689
+ applyDetails: "Filters change the clip's picture and overlays draw over it, in stack order, on the picture as it comes from the source, before the clip's grade, placement, opacity and blend; numbers may be keyframed (clip-relative ms). Transitions go through set_video_effect_transition and generators or titles through add_video_effect_clip. The preview renders them frame by frame; the ffmpeg export then needs rendered frames (see export_video_ffmpeg).",
4690
+ provider: () => controller.effectsProvider,
4691
+ readOnlyReason,
4692
+ list: (target) => {
4693
+ const clips = target ? [clipOf(target)] : controller.getProject().tracks.flatMap((t) => t.clips);
4694
+ return clips.map((c) => ({ target: c.id, ...c.name ? { name: c.name } : {}, effects: videoClipAppliedEffects(c) })).filter((t) => target || t.effects.length);
4695
+ },
4696
+ apply: async (target, effect, args) => {
4697
+ clipOf(target);
4698
+ return result(await controller.applyClipEffect(target, effect, { values: args.values, index: args.index, enabled: args.enabled, opacity: args.opacity }), target);
4699
+ },
4700
+ update: async (target, instance, changes) => {
4701
+ clipOf(target);
4702
+ if (instance === "generator" || instance === "transition") {
4703
+ const extra = ["enabled", "opacity", "index"].filter((k) => changes[k] !== void 0);
4704
+ if (extra.length) throw new Error(`An ${instance === "generator" ? "effect clip" : "effect transition"} only takes values; change its ${extra.join(", ")} with update_video_clip${instance === "transition" ? " or set_video_effect_transition" : ""}.`);
4705
+ const values = Object.fromEntries(Object.entries(_nullishCoalesce(changes.values, () => ( {}))).filter(([, v]) => v !== null));
4706
+ return result(await controller.updateEffectValues(target, instance, values), target, instance);
4707
+ }
4708
+ return result(await controller.updateClipEffect(target, instance, changes), target, instance);
4709
+ },
4710
+ remove: async (target, instance) => {
4711
+ const clip = clipOf(target);
4712
+ const was = videoClipAppliedEffects(clip).find((e) => e.id === instance);
4713
+ if (!was) throw new Error(`Clip "${target}" has no effect "${instance}"; its effects are ${videoClipAppliedEffects(clip).map((e) => `"${e.id}"`).join(", ") || "none"}.`);
4714
+ if (instance === "generator") throw new Error(`"${target}" is an effect clip: its effect is the clip itself. Delete the clip with delete_video_clips.`);
4715
+ if (instance === "transition") {
4716
+ const r2 = controller.apply({ op: "set_transition", clip: target, transition: null }, "Remove transition");
4717
+ if (!r2.ok) throw new Error(r2.error);
4718
+ return { target, effect: was, effects: videoClipAppliedEffects(clipOf(target)) };
4719
+ }
4720
+ const r = controller.removeClipEffect(target, instance);
4721
+ if (!r.ok) throw new Error(r.error);
4722
+ return { target, effect: was, effects: videoClipAppliedEffects(clipOf(target)) };
4723
+ },
4724
+ subscribe: (notify) => controller.subscribe(() => notify()),
4725
+ extraTools: (ctx) => [
4726
+ {
4727
+ name: "add_video_effect_clip",
4728
+ title: "Add an effect clip",
4729
+ description: "Adds a clip drawn by a provider generator, title or overlay effect (search_effects with use generator, title or overlay), filling the frame like a colour clip; transparent effects show the tracks beneath. It can be moved, trimmed, faded, graded and given clip effects like any clip. One undo step. Returns the new clip id and its effect. The ffmpeg export then needs rendered frames.",
4730
+ inputSchema: {
4731
+ type: "object",
4732
+ properties: {
4733
+ track: { type: "string", minLength: 1, description: 'A video track id from get_video_project (e.g. "v1"); earlier tracks draw on top.' },
4734
+ effect: ctx.effectIdSchema(["generator", "title", "overlay"]),
4735
+ start: MS2("Where it starts on the timeline (default: the end of the track)"),
4736
+ duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms (default: the effect's own length, else 5000)." },
4737
+ values: ctx.valuesSchema("Control values over the effect's defaults", true),
4738
+ name: { type: "string", minLength: 1, description: "A label for the clip (default: the effect's name)." },
4739
+ mode: { type: "string", enum: [..._chunkIWSMDQE5cjs.VIDEO_PLACEMENT_MODES], description: "What to do with clips already there: refuse (default), overwrite or insert." }
4740
+ },
4741
+ required: ["track", "effect"],
4742
+ additionalProperties: false
4743
+ },
4744
+ annotations: { title: "Add an effect clip", ...ctx.annotations.write },
4745
+ handler: async (args) => {
4746
+ ctx.requireProvider();
4747
+ const r = await controller.addEffectClip(args.track, args.effect, { start: args.start, duration: args.duration, values: args.values, name: args.name, mode: args.mode });
4748
+ if (!r.ok) throw new Error(r.error);
4749
+ return { clip: r.clip, track: args.track, effects: videoClipAppliedEffects(clipOf(r.clip)) };
4750
+ }
4751
+ },
4752
+ {
4753
+ name: "set_video_effect_transition",
4754
+ title: "Set an effect transition",
4755
+ description: `Sets a provider transition effect (search_effects with use transition) into a clip from the clip that ends where it starts on the same track, centred on the cut; like a crossfade it needs half its length in media past the cut on both sides. Replaces any transition there. One undo step. Returns the clip's effects. Remove it with remove_effect (effect "transition") or set_video_transition null.`,
4756
+ inputSchema: {
4757
+ type: "object",
4758
+ properties: {
4759
+ clip: { type: "string", minLength: 1, description: "The incoming clip (the one after the cut), from get_video_project." },
4760
+ effect: ctx.effectIdSchema(["transition"]),
4761
+ duration: { type: "number", exclusiveMinimum: 0, description: "Length in ms, centred on the cut (default: the effect's own length, else 1000)." },
4762
+ values: ctx.valuesSchema("Control values over the effect's defaults (plain values; transitions cannot be keyframed)")
4763
+ },
4764
+ required: ["clip", "effect"],
4765
+ additionalProperties: false
4766
+ },
4767
+ annotations: { title: "Set an effect transition", ...ctx.annotations.writeIdempotent },
4768
+ handler: async (args) => {
4769
+ ctx.requireProvider();
4770
+ const r = await controller.setEffectTransition(args.clip, args.effect, { duration: args.duration, values: args.values });
4771
+ if (!r.ok) throw new Error(r.error);
4772
+ return { clip: args.clip, transition: clipOf(args.clip).transition, effects: videoClipAppliedEffects(clipOf(args.clip)) };
4773
+ }
4774
+ },
4775
+ {
4776
+ name: "set_video_effect_keyframes",
4777
+ title: "Keyframe an effect control",
4778
+ description: "Animates one number control of a clip effect or an effect clip with keys at clip-relative times (ms), or with keys null stops animating it, keeping its value at the clip's start. Values are checked against the control's range from describe_effect. One undo step. Returns the effect.",
4779
+ inputSchema: {
4780
+ type: "object",
4781
+ properties: {
4782
+ clip: { type: "string", minLength: 1, description: "A clip id from list_applied_effects." },
4783
+ effect: { type: "string", minLength: 1, description: `The effect's id on the clip ("fx1", or "generator" for an effect clip's own effect).` },
4784
+ control: { type: "string", minLength: 1, description: "A number control name from describe_effect." },
4785
+ keys: { anyOf: [KEYS2, { type: "null" }], description: "The keys, or null to stop animating the control." }
4786
+ },
4787
+ required: ["clip", "effect", "control", "keys"],
4788
+ additionalProperties: false
4789
+ },
4790
+ annotations: { title: "Keyframe an effect control", ...ctx.annotations.writeIdempotent },
4791
+ handler: async (args) => {
4792
+ ctx.requireProvider();
4793
+ const keys = args.keys;
4794
+ let r;
4795
+ if (args.effect === "generator") {
4796
+ const clip = clipOf(args.clip);
4797
+ 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).`);
4798
+ const was = _optionalChain([clip, 'access', _156 => _156.values, 'optionalAccess', _157 => _157[args.control]]);
4799
+ const plain = keys === null ? _chunkIWSMDQE5cjs.isVideoKeyframes.call(void 0, was) ? _optionalChain([was, 'access', _158 => _158.keys, 'access', _159 => _159[0], 'optionalAccess', _160 => _160.v]) : was : { keys: [...keys].sort((a, b) => a.t - b.t) };
4800
+ if (plain === void 0) throw new Error(`"${args.control}" has no value to keep; give keys instead.`);
4801
+ r = await controller.updateEffectValues(args.clip, "generator", { [args.control]: plain });
4802
+ } else r = await controller.setClipEffectKeyframes(args.clip, args.effect, args.control, keys);
4803
+ if (!r.ok) throw new Error(r.error);
4804
+ return { clip: args.clip, effect: videoClipAppliedEffects(clipOf(args.clip)).find((e) => e.id === args.effect) };
4805
+ }
4806
+ }
4807
+ ]
4808
+ });
4809
+ }
4810
+
4811
+
4812
+
4813
+
4814
+
4815
+
4816
+
4817
+
4818
+
4819
+
4820
+
4821
+
4822
+
4823
+
4824
+
4825
+
4826
+
4827
+
4828
+
4829
+
4830
+
4359
4831
 
4360
4832
 
4361
4833
 
@@ -4587,5 +5059,5 @@ function createVideoEditorToolProvider(controller, options = {}) {
4587
5059
 
4588
5060
 
4589
5061
 
4590
- exports.VIDEO_BLEND_MODES = _chunkSMJGE7HMcjs.VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = _chunkSMJGE7HMcjs.VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = _chunkSMJGE7HMcjs.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_EASE_NAMES = _chunkSMJGE7HMcjs.VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_FADE_CURVES = _chunkSMJGE7HMcjs.VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = _chunkSMJGE7HMcjs.VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = _chunkSMJGE7HMcjs.VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = _chunkSMJGE7HMcjs.VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = _chunkSMJGE7HMcjs.VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = _chunkSMJGE7HMcjs.VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LUT_MAX_SIZE = _chunkSMJGE7HMcjs.VIDEO_LUT_MAX_SIZE; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = _chunkSMJGE7HMcjs.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 = _chunkSMJGE7HMcjs.VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = _chunkSMJGE7HMcjs.VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = _chunkSMJGE7HMcjs.VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = _chunkSMJGE7HMcjs.VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = _chunkSMJGE7HMcjs.VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = _chunkSMJGE7HMcjs.allVideoClipIds; exports.allVideoTracks = _chunkSMJGE7HMcjs.allVideoTracks; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = _chunkSMJGE7HMcjs.applyVideoGrade; exports.applyVideoLut = _chunkSMJGE7HMcjs.applyVideoLut; exports.applyVideoLutToPixels = _chunkSMJGE7HMcjs.applyVideoLutToPixels; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = _chunkSMJGE7HMcjs.checkVideoTimeRemap; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.drawVideoFrame = _chunkSMJGE7HMcjs.drawVideoFrame; exports.ffmpegFilterValue = _chunkSMJGE7HMcjs.ffmpegFilterValue; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = _chunkSMJGE7HMcjs.findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = _chunkSMJGE7HMcjs.findVideoGaps; exports.findVideoSequenceClip = _chunkSMJGE7HMcjs.findVideoSequenceClip; exports.findVideoSequenceCycle = _chunkSMJGE7HMcjs.findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = _chunkSMJGE7HMcjs.formatVideoSeconds; exports.formatVideoTimecode = _chunkSMJGE7HMcjs.formatVideoTimecode; exports.formatVideoTimecodeFrames = _chunkSMJGE7HMcjs.formatVideoTimecodeFrames; exports.isVideoDropFrameRate = _chunkSMJGE7HMcjs.isVideoDropFrameRate; exports.isVideoKeyframes = _chunkSMJGE7HMcjs.isVideoKeyframes; exports.mergeVideoRanges = mergeVideoRanges; exports.nextFreeVideoSlot = _chunkSMJGE7HMcjs.nextFreeVideoSlot; exports.normalizeVideoGrade = _chunkSMJGE7HMcjs.normalizeVideoGrade; exports.normalizeVideoGradeLut = _chunkSMJGE7HMcjs.normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoCubeLut = _chunkSMJGE7HMcjs.parseVideoCubeLut; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = _chunkSMJGE7HMcjs.parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = _chunkSMJGE7HMcjs.placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoPrefetch = planVideoPrefetch; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = _chunkSMJGE7HMcjs.removeVideoKey; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = _chunkSMJGE7HMcjs.retimeVideoAnimatable; exports.setVideoKey = _chunkSMJGE7HMcjs.setVideoKey; exports.snapToVideoFrame = _chunkSMJGE7HMcjs.snapToVideoFrame; exports.snapVideoTime = _chunkSMJGE7HMcjs.snapVideoTime; exports.sortVideoKeys = _chunkSMJGE7HMcjs.sortVideoKeys; exports.sortedVideoClips = _chunkSMJGE7HMcjs.sortedVideoClips; exports.splitVideoAnimatable = _chunkSMJGE7HMcjs.splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = _chunkSMJGE7HMcjs.toVideoEdl; exports.toVideoFfmpeg = _chunkSMJGE7HMcjs.toVideoFfmpeg; exports.toVideoLoudnessMeasure = _chunkSMJGE7HMcjs.toVideoLoudnessMeasure; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = _chunkSMJGE7HMcjs.videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = _chunkSMJGE7HMcjs.videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoCacheEvictions = videoCacheEvictions; exports.videoChroma = videoChroma; exports.videoClipAfter = _chunkSMJGE7HMcjs.videoClipAfter; exports.videoClipAnimated = _chunkSMJGE7HMcjs.videoClipAnimated; exports.videoClipAnimationProperties = _chunkSMJGE7HMcjs.videoClipAnimationProperties; exports.videoClipAnimationSpans = _chunkSMJGE7HMcjs.videoClipAnimationSpans; exports.videoClipBefore = _chunkSMJGE7HMcjs.videoClipBefore; exports.videoClipEnd = _chunkSMJGE7HMcjs.videoClipEnd; exports.videoClipHandles = _chunkSMJGE7HMcjs.videoClipHandles; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = _chunkSMJGE7HMcjs.videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = _chunkSMJGE7HMcjs.videoClipSoundGain; exports.videoClipSourceRange = _chunkSMJGE7HMcjs.videoClipSourceRange; exports.videoClipSourceTime = _chunkSMJGE7HMcjs.videoClipSourceTime; exports.videoClipSpeed = _chunkSMJGE7HMcjs.videoClipSpeed; exports.videoClipSpeedAt = _chunkSMJGE7HMcjs.videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = _chunkSMJGE7HMcjs.videoClipsAt; exports.videoContactSheetSvg = _chunkSMJGE7HMcjs.videoContactSheetSvg; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoEaseBezier = _chunkSMJGE7HMcjs.videoEaseBezier; exports.videoEaseProgress = _chunkSMJGE7HMcjs.videoEaseProgress; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = _chunkSMJGE7HMcjs.videoFadeCurveGain; exports.videoFrameAt = _chunkSMJGE7HMcjs.videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = _chunkSMJGE7HMcjs.videoFrameDuration; exports.videoFrameLeafLayers = _chunkSMJGE7HMcjs.videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = _chunkSMJGE7HMcjs.videoFrameToSvg; exports.videoFrames = _chunkSMJGE7HMcjs.videoFrames; exports.videoFreezeFrameEdit = _chunkSMJGE7HMcjs.videoFreezeFrameEdit; exports.videoGradeCssFilter = _chunkSMJGE7HMcjs.videoGradeCssFilter; exports.videoGradeFfmpegFilters = _chunkSMJGE7HMcjs.videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = _chunkSMJGE7HMcjs.videoGradeGainsFilterId; exports.videoGradeLook = _chunkSMJGE7HMcjs.videoGradeLook; exports.videoGradePreset = _chunkSMJGE7HMcjs.videoGradePreset; exports.videoGradeStepMatrix = _chunkSMJGE7HMcjs.videoGradeStepMatrix; exports.videoGradeStepSvgValues = _chunkSMJGE7HMcjs.videoGradeStepSvgValues; exports.videoGradeSteps = _chunkSMJGE7HMcjs.videoGradeSteps; exports.videoGradeSvgDefs = _chunkSMJGE7HMcjs.videoGradeSvgDefs; exports.videoGradeSvgFilter = _chunkSMJGE7HMcjs.videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = _chunkSMJGE7HMcjs.videoHourFrames; exports.videoIrisRadius = _chunkSMJGE7HMcjs.videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyframeBreakpoints = _chunkSMJGE7HMcjs.videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = _chunkSMJGE7HMcjs.videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = _chunkSMJGE7HMcjs.videoKeysOf; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = _chunkSMJGE7HMcjs.videoLutFromFunction; exports.videoLutSvgApproximation = _chunkSMJGE7HMcjs.videoLutSvgApproximation; exports.videoLutSvgPrimitives = _chunkSMJGE7HMcjs.videoLutSvgPrimitives; exports.videoLutToCube = _chunkSMJGE7HMcjs.videoLutToCube; exports.videoOverlap = _chunkSMJGE7HMcjs.videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = _chunkSMJGE7HMcjs.videoProjectDuration; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = _chunkSMJGE7HMcjs.videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = _chunkSMJGE7HMcjs.videoSequenceChildren; exports.videoSequenceDuration = _chunkSMJGE7HMcjs.videoSequenceDuration; exports.videoSequenceMap = _chunkSMJGE7HMcjs.videoSequenceMap; exports.videoShellQuote = _chunkSMJGE7HMcjs.videoShellQuote; exports.videoSlowMotionRamp = _chunkSMJGE7HMcjs.videoSlowMotionRamp; exports.videoSnapPoints = _chunkSMJGE7HMcjs.videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeedRampEdit = _chunkSMJGE7HMcjs.videoSpeedRampEdit; exports.videoSpeedRampKeys = _chunkSMJGE7HMcjs.videoSpeedRampKeys; exports.videoTextStyle = _chunkSMJGE7HMcjs.videoTextStyle; exports.videoTimeRemapBreakpoints = _chunkSMJGE7HMcjs.videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = _chunkSMJGE7HMcjs.videoTimeRemapSpan; exports.videoTimecodeFrames = _chunkSMJGE7HMcjs.videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = _chunkSMJGE7HMcjs.videoTitleFrame; exports.videoTrackSyncLocked = _chunkSMJGE7HMcjs.videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = _chunkSMJGE7HMcjs.videoTransformAt; exports.videoTransitionAudioCurve = _chunkSMJGE7HMcjs.videoTransitionAudioCurve; exports.videoTransitionEase = _chunkSMJGE7HMcjs.videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = _chunkSMJGE7HMcjs.videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = _chunkSMJGE7HMcjs.videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange;
5062
+ exports.VIDEO_BLEND_MODES = _chunkIWSMDQE5cjs.VIDEO_BLEND_MODES; exports.VIDEO_BLEND_MODE_LABELS = VIDEO_BLEND_MODE_LABELS; exports.VIDEO_CLIP_ANIMATION_DURATION = _chunkIWSMDQE5cjs.VIDEO_CLIP_ANIMATION_DURATION; exports.VIDEO_CLIP_ANIMATION_EFFECTS = _chunkIWSMDQE5cjs.VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_CLIP_ANIMATION_LABELS = VIDEO_CLIP_ANIMATION_LABELS; exports.VIDEO_CLIP_TYPES = _chunkIWSMDQE5cjs.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_EASE_NAMES = _chunkIWSMDQE5cjs.VIDEO_EASE_NAMES; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_EFFECT_PLACES = _chunkIWSMDQE5cjs.VIDEO_EFFECT_PLACES; exports.VIDEO_FADE_CURVES = _chunkIWSMDQE5cjs.VIDEO_FADE_CURVES; exports.VIDEO_FADE_CURVE_LABELS = VIDEO_FADE_CURVE_LABELS; exports.VIDEO_FITS = _chunkIWSMDQE5cjs.VIDEO_FITS; exports.VIDEO_GRADE_CONTROLS = _chunkIWSMDQE5cjs.VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = _chunkIWSMDQE5cjs.VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = _chunkIWSMDQE5cjs.VIDEO_GRADE_PRESET_NAMES; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_KEYFRAME_LIMITS = _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_LIMITS; exports.VIDEO_KEYFRAME_PROPERTIES = _chunkIWSMDQE5cjs.VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_LUT_MAX_SIZE = _chunkIWSMDQE5cjs.VIDEO_LUT_MAX_SIZE; exports.VIDEO_PEAK_BLOCK = VIDEO_PEAK_BLOCK; exports.VIDEO_PLACEMENT_MODES = _chunkIWSMDQE5cjs.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 = _chunkIWSMDQE5cjs.VIDEO_TIME_EPSILON; exports.VIDEO_TRANSFORM_PROPERTIES = _chunkIWSMDQE5cjs.VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_TRANSITION_LABELS = VIDEO_TRANSITION_LABELS; exports.VIDEO_TRANSITION_TYPES = _chunkIWSMDQE5cjs.VIDEO_TRANSITION_TYPES; exports.VIDEO_VECTORSCOPE_TARGETS = VIDEO_VECTORSCOPE_TARGETS; exports.VIDEO_WIPE_DIRECTIONS = _chunkIWSMDQE5cjs.VIDEO_WIPE_DIRECTIONS; exports.VideoAudioPeaksCache = VideoAudioPeaksCache; exports.VideoEditorController = VideoEditorController; exports.VideoEffectsEngine = _chunkIWSMDQE5cjs.VideoEffectsEngine; exports.VideoFrameCache = VideoFrameCache; exports.VideoLutCache = _chunkIWSMDQE5cjs.VideoLutCache; exports.VideoPreviewEngine = VideoPreviewEngine; exports.VideoPreviewPixels = VideoPreviewPixels; exports.allVideoClipIds = _chunkIWSMDQE5cjs.allVideoClipIds; exports.allVideoTracks = _chunkIWSMDQE5cjs.allVideoTracks; exports.applyVideoEdits = applyVideoEdits; exports.applyVideoGrade = _chunkIWSMDQE5cjs.applyVideoGrade; exports.applyVideoLut = _chunkIWSMDQE5cjs.applyVideoLut; exports.applyVideoLutToPixels = _chunkIWSMDQE5cjs.applyVideoLutToPixels; exports.buildVideoAudioPeaks = buildVideoAudioPeaks; exports.checkVideoEffectPlace = _chunkIWSMDQE5cjs.checkVideoEffectPlace; exports.checkVideoEffectValues = _chunkIWSMDQE5cjs.checkVideoEffectValues; exports.checkVideoProject = checkVideoProject; exports.checkVideoTimeRemap = _chunkIWSMDQE5cjs.checkVideoTimeRemap; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoEffectsToolProvider = createVideoEffectsToolProvider; exports.createVideoElementDecoder = createVideoElementDecoder; exports.createVideoProject = createVideoProject; exports.decodeVideoAudioPeaks = decodeVideoAudioPeaks; exports.describeVideoProject = describeVideoProject; exports.describeVideoSequence = describeVideoSequence; exports.drawVideoFrame = _chunkIWSMDQE5cjs.drawVideoFrame; exports.ffmpegFilterValue = _chunkIWSMDQE5cjs.ffmpegFilterValue; exports.findVideoAudioSilences = findVideoAudioSilences; exports.findVideoClip = _chunkIWSMDQE5cjs.findVideoClip; exports.findVideoFillers = findVideoFillers; exports.findVideoGaps = _chunkIWSMDQE5cjs.findVideoGaps; exports.findVideoSequenceClip = _chunkIWSMDQE5cjs.findVideoSequenceClip; exports.findVideoSequenceCycle = _chunkIWSMDQE5cjs.findVideoSequenceCycle; exports.findVideoTranscriptPauses = findVideoTranscriptPauses; exports.findVideoTranscriptText = findVideoTranscriptText; exports.formatVideoSeconds = _chunkIWSMDQE5cjs.formatVideoSeconds; exports.formatVideoTimecode = _chunkIWSMDQE5cjs.formatVideoTimecode; exports.formatVideoTimecodeFrames = _chunkIWSMDQE5cjs.formatVideoTimecodeFrames; exports.isVideoDropFrameRate = _chunkIWSMDQE5cjs.isVideoDropFrameRate; exports.isVideoKeyframes = _chunkIWSMDQE5cjs.isVideoKeyframes; exports.mergeVideoRanges = mergeVideoRanges; exports.mixEffectPixels = _chunkIWSMDQE5cjs.mixEffectPixels; exports.nextFreeVideoSlot = _chunkIWSMDQE5cjs.nextFreeVideoSlot; exports.normalizeVideoGrade = _chunkIWSMDQE5cjs.normalizeVideoGrade; exports.normalizeVideoGradeLut = _chunkIWSMDQE5cjs.normalizeVideoGradeLut; exports.normalizeVideoWord = normalizeVideoWord; exports.overEffectPixels = _chunkIWSMDQE5cjs.overEffectPixels; exports.parseVideoAnimatable = parseVideoAnimatable; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoAssetProxies = parseVideoAssetProxies; exports.parseVideoClip = parseVideoClip; exports.parseVideoClipAnimation = parseVideoClipAnimation; exports.parseVideoClipEffects = parseVideoClipEffects; exports.parseVideoCubeLut = _chunkIWSMDQE5cjs.parseVideoCubeLut; exports.parseVideoEffectRef = parseVideoEffectRef; exports.parseVideoEffectValues = parseVideoEffectValues; exports.parseVideoGrade = parseVideoGrade; exports.parseVideoGradeLut = parseVideoGradeLut; exports.parseVideoKeyframes = parseVideoKeyframes; exports.parseVideoLoudnessMeasurement = _chunkIWSMDQE5cjs.parseVideoLoudnessMeasurement; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoPreviewScale = parseVideoPreviewScale; exports.parseVideoProject = parseVideoProject; exports.parseVideoSequence = parseVideoSequence; exports.parseVideoTimeRemap = parseVideoTimeRemap; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTranscript = parseVideoTranscript; exports.parseVideoTranscriptWords = parseVideoTranscriptWords; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = _chunkIWSMDQE5cjs.placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.planVideoPrefetch = planVideoPrefetch; exports.probeVideoMedia = probeVideoMedia; exports.readVideoScopesPanel = readVideoScopesPanel; exports.removeVideoKey = _chunkIWSMDQE5cjs.removeVideoKey; exports.renderVideoFrameExact = _chunkIWSMDQE5cjs.renderVideoFrameExact; exports.resolveVideoPreviewScale = resolveVideoPreviewScale; exports.retimeVideoAnimatable = _chunkIWSMDQE5cjs.retimeVideoAnimatable; exports.setVideoKey = _chunkIWSMDQE5cjs.setVideoKey; exports.snapToVideoFrame = _chunkIWSMDQE5cjs.snapToVideoFrame; exports.snapVideoTime = _chunkIWSMDQE5cjs.snapVideoTime; exports.sortVideoKeys = _chunkIWSMDQE5cjs.sortVideoKeys; exports.sortedVideoClips = _chunkIWSMDQE5cjs.sortedVideoClips; exports.splitVideoAnimatable = _chunkIWSMDQE5cjs.splitVideoAnimatable; exports.summarizeVideoScopes = summarizeVideoScopes; exports.toVideoEdl = _chunkIWSMDQE5cjs.toVideoEdl; exports.toVideoFfmpeg = _chunkIWSMDQE5cjs.toVideoFfmpeg; exports.toVideoLoudnessMeasure = _chunkIWSMDQE5cjs.toVideoLoudnessMeasure; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetHasSound = _chunkIWSMDQE5cjs.videoAssetHasSound; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = _chunkIWSMDQE5cjs.videoAssetMap; exports.videoAssetProxy = videoAssetProxy; exports.videoAudioLevels = videoAudioLevels; exports.videoAudioPeakRange = videoAudioPeakRange; exports.videoAudioPeakSpans = videoAudioPeakSpans; exports.videoAudioPeaksDuration = videoAudioPeaksDuration; exports.videoCacheEvictions = videoCacheEvictions; exports.videoChroma = videoChroma; exports.videoClipAfter = _chunkIWSMDQE5cjs.videoClipAfter; exports.videoClipAnimated = _chunkIWSMDQE5cjs.videoClipAnimated; exports.videoClipAnimationProperties = _chunkIWSMDQE5cjs.videoClipAnimationProperties; exports.videoClipAnimationSpans = _chunkIWSMDQE5cjs.videoClipAnimationSpans; exports.videoClipAppliedEffects = videoClipAppliedEffects; exports.videoClipBefore = _chunkIWSMDQE5cjs.videoClipBefore; exports.videoClipEffectUses = _chunkIWSMDQE5cjs.videoClipEffectUses; exports.videoClipEnd = _chunkIWSMDQE5cjs.videoClipEnd; exports.videoClipHandles = _chunkIWSMDQE5cjs.videoClipHandles; exports.videoClipKeyframes = videoClipKeyframes; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = _chunkIWSMDQE5cjs.videoClipOverhang; exports.videoClipShowsWaveform = videoClipShowsWaveform; exports.videoClipSoundGain = _chunkIWSMDQE5cjs.videoClipSoundGain; exports.videoClipSourceRange = _chunkIWSMDQE5cjs.videoClipSourceRange; exports.videoClipSourceTime = _chunkIWSMDQE5cjs.videoClipSourceTime; exports.videoClipSpeed = _chunkIWSMDQE5cjs.videoClipSpeed; exports.videoClipSpeedAt = _chunkIWSMDQE5cjs.videoClipSpeedAt; exports.videoClipTint = videoClipTint; exports.videoClipWaveform = videoClipWaveform; exports.videoClipWaveformPath = videoClipWaveformPath; exports.videoClipsAt = _chunkIWSMDQE5cjs.videoClipsAt; exports.videoContactSheetSvg = _chunkIWSMDQE5cjs.videoContactSheetSvg; exports.videoDragLabel = videoDragLabel; exports.videoDropTracks = videoDropTracks; exports.videoEaseBezier = _chunkIWSMDQE5cjs.videoEaseBezier; exports.videoEaseProgress = _chunkIWSMDQE5cjs.videoEaseProgress; exports.videoEffectFrameTime = _chunkIWSMDQE5cjs.videoEffectFrameTime; exports.videoEffectLayerKey = _chunkIWSMDQE5cjs.videoEffectLayerKey; exports.videoEffectValuesAt = _chunkIWSMDQE5cjs.videoEffectValuesAt; exports.videoExposureNotes = videoExposureNotes; exports.videoExposureStats = videoExposureStats; exports.videoFadeCurveGain = _chunkIWSMDQE5cjs.videoFadeCurveGain; exports.videoFfmpegUnsupportedEffects = _chunkIWSMDQE5cjs.videoFfmpegUnsupportedEffects; exports.videoFrameAt = _chunkIWSMDQE5cjs.videoFrameAt; exports.videoFrameCacheKey = videoFrameCacheKey; exports.videoFrameDuration = _chunkIWSMDQE5cjs.videoFrameDuration; exports.videoFrameLeafLayers = _chunkIWSMDQE5cjs.videoFrameLeafLayers; exports.videoFrameRequestsAt = videoFrameRequestsAt; exports.videoFrameToSvg = _chunkIWSMDQE5cjs.videoFrameToSvg; exports.videoFrames = _chunkIWSMDQE5cjs.videoFrames; exports.videoFreezeFrameEdit = _chunkIWSMDQE5cjs.videoFreezeFrameEdit; exports.videoGradeCssFilter = _chunkIWSMDQE5cjs.videoGradeCssFilter; exports.videoGradeFfmpegFilters = _chunkIWSMDQE5cjs.videoGradeFfmpegFilters; exports.videoGradeGainsFilterId = _chunkIWSMDQE5cjs.videoGradeGainsFilterId; exports.videoGradeLook = _chunkIWSMDQE5cjs.videoGradeLook; exports.videoGradePreset = _chunkIWSMDQE5cjs.videoGradePreset; exports.videoGradeStepMatrix = _chunkIWSMDQE5cjs.videoGradeStepMatrix; exports.videoGradeStepSvgValues = _chunkIWSMDQE5cjs.videoGradeStepSvgValues; exports.videoGradeSteps = _chunkIWSMDQE5cjs.videoGradeSteps; exports.videoGradeSvgDefs = _chunkIWSMDQE5cjs.videoGradeSvgDefs; exports.videoGradeSvgFilter = _chunkIWSMDQE5cjs.videoGradeSvgFilter; exports.videoHistogram = videoHistogram; exports.videoHistogramImage = videoHistogramImage; exports.videoHourFrames = _chunkIWSMDQE5cjs.videoHourFrames; exports.videoIrisRadius = _chunkIWSMDQE5cjs.videoIrisRadius; exports.videoIssueKey = videoIssueKey; exports.videoKeyframeBreakpoints = _chunkIWSMDQE5cjs.videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = _chunkIWSMDQE5cjs.videoKeyframeFfmpegExpr; exports.videoKeyframeRows = videoKeyframeRows; exports.videoKeyframeToggleEdit = videoKeyframeToggleEdit; exports.videoKeyframeValueEdit = videoKeyframeValueEdit; exports.videoKeysOf = _chunkIWSMDQE5cjs.videoKeysOf; exports.videoLayersUseEffects = _chunkIWSMDQE5cjs.videoLayersUseEffects; exports.videoLayersWithoutTransitionEffects = _chunkIWSMDQE5cjs.videoLayersWithoutTransitionEffects; exports.videoLuma = videoLuma; exports.videoLumaWaveform = videoLumaWaveform; exports.videoLutEdits = videoLutEdits; exports.videoLutFromFunction = _chunkIWSMDQE5cjs.videoLutFromFunction; exports.videoLutSvgApproximation = _chunkIWSMDQE5cjs.videoLutSvgApproximation; exports.videoLutSvgPrimitives = _chunkIWSMDQE5cjs.videoLutSvgPrimitives; exports.videoLutToCube = _chunkIWSMDQE5cjs.videoLutToCube; exports.videoOverlap = _chunkIWSMDQE5cjs.videoOverlap; exports.videoPeakDb = videoPeakDb; exports.videoPreviewSrc = videoPreviewSrc; exports.videoProjectDuration = _chunkIWSMDQE5cjs.videoProjectDuration; exports.videoProjectEffects = _chunkIWSMDQE5cjs.videoProjectEffects; exports.videoProjectHasProxies = videoProjectHasProxies; exports.videoProjectSvg = _chunkIWSMDQE5cjs.videoProjectSvg; exports.videoProxyFfmpeg = videoProxyFfmpeg; exports.videoProxyName = videoProxyName; exports.videoProxyPlan = videoProxyPlan; exports.videoRemoveRangesEdits = videoRemoveRangesEdits; exports.videoRulerTicks = videoRulerTicks; exports.videoScopeImage = videoScopeImage; exports.videoSequenceChildren = _chunkIWSMDQE5cjs.videoSequenceChildren; exports.videoSequenceDuration = _chunkIWSMDQE5cjs.videoSequenceDuration; exports.videoSequenceMap = _chunkIWSMDQE5cjs.videoSequenceMap; exports.videoShellQuote = _chunkIWSMDQE5cjs.videoShellQuote; exports.videoSlowMotionRamp = _chunkIWSMDQE5cjs.videoSlowMotionRamp; exports.videoSnapPoints = _chunkIWSMDQE5cjs.videoSnapPoints; exports.videoSourceFrame = videoSourceFrame; exports.videoSourceFrameTime = videoSourceFrameTime; exports.videoSpeedRampEdit = _chunkIWSMDQE5cjs.videoSpeedRampEdit; exports.videoSpeedRampKeys = _chunkIWSMDQE5cjs.videoSpeedRampKeys; exports.videoTextStyle = _chunkIWSMDQE5cjs.videoTextStyle; exports.videoTimeRemapBreakpoints = _chunkIWSMDQE5cjs.videoTimeRemapBreakpoints; exports.videoTimeRemapSpan = _chunkIWSMDQE5cjs.videoTimeRemapSpan; exports.videoTimecodeFrames = _chunkIWSMDQE5cjs.videoTimecodeFrames; exports.videoTimelineTranscript = videoTimelineTranscript; exports.videoTitleFrame = _chunkIWSMDQE5cjs.videoTitleFrame; exports.videoTrackSyncLocked = _chunkIWSMDQE5cjs.videoTrackSyncLocked; exports.videoTranscriptEdit = videoTranscriptEdit; exports.videoTranscriptTrack = videoTranscriptTrack; exports.videoTransformAt = _chunkIWSMDQE5cjs.videoTransformAt; exports.videoTransitionAudioCurve = _chunkIWSMDQE5cjs.videoTransitionAudioCurve; exports.videoTransitionEase = _chunkIWSMDQE5cjs.videoTransitionEase; exports.videoTransitionHasDirection = videoTransitionHasDirection; exports.videoValueAt = _chunkIWSMDQE5cjs.videoValueAt; exports.videoVectorscope = videoVectorscope; exports.videoVectorscopeAngle = videoVectorscopeAngle; exports.videoVectorscopeImage = videoVectorscopeImage; exports.videoVectorscopePoint = videoVectorscopePoint; exports.videoWaveformImage = videoWaveformImage; exports.videoWaveformPath = videoWaveformPath; exports.videoWipeRect = _chunkIWSMDQE5cjs.videoWipeRect; exports.videoWordAt = videoWordAt; exports.videoWordsRange = videoWordsRange;
4591
5063
  //# sourceMappingURL=index.cjs.map