@pixerate/editor 0.123.0 → 0.124.1

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-SMJGE7HM.cjs → chunk-4QQZV5Y5.cjs} +512 -39
  20. package/dist/chunk-4QQZV5Y5.cjs.map +1 -0
  21. package/dist/{chunk-TVXFHE4T.js → chunk-64PYNEHJ.js} +45 -12
  22. package/dist/chunk-64PYNEHJ.js.map +1 -0
  23. package/dist/{chunk-2IW3BWRT.cjs → chunk-7LQO6OHH.cjs} +2 -2
  24. package/dist/{chunk-2IW3BWRT.cjs.map → chunk-7LQO6OHH.cjs.map} +1 -1
  25. package/dist/chunk-CN4PJHUG.cjs +234 -0
  26. package/dist/chunk-CN4PJHUG.cjs.map +1 -0
  27. package/dist/chunk-FHYDQOPC.cjs +215 -0
  28. package/dist/chunk-FHYDQOPC.cjs.map +1 -0
  29. package/dist/{chunk-KMBC4HNV.js → chunk-J67OLQUQ.js} +2 -2
  30. package/dist/chunk-JRXJTPES.js +215 -0
  31. package/dist/chunk-JRXJTPES.js.map +1 -0
  32. package/dist/{chunk-IPFRWILU.js → chunk-ORHMVUR6.js} +488 -15
  33. package/dist/chunk-ORHMVUR6.js.map +1 -0
  34. package/dist/{chunk-6CJRDJCU.cjs → chunk-PEHYWUVV.cjs} +176 -111
  35. package/dist/chunk-PEHYWUVV.cjs.map +1 -0
  36. package/dist/chunk-QEG3GRN2.js +234 -0
  37. package/dist/chunk-QEG3GRN2.js.map +1 -0
  38. package/dist/{chunk-6ZBR4J62.js → chunk-WATAQ2Z2.js} +79 -14
  39. package/dist/chunk-WATAQ2Z2.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 +605 -0
  43. package/dist/effects/index.cjs.map +1 -0
  44. package/dist/effects/index.d.cts +163 -0
  45. package/dist/effects/index.d.ts +163 -0
  46. package/dist/effects/index.js +605 -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-BGtXgMJ3.d.ts} +536 -128
  51. package/dist/{export-Dv0-ZVrV.d.cts → export-BdfY_lH0.d.ts} +392 -5
  52. package/dist/{export-Dv0-ZVrV.d.ts → export-CbpjwxaI.d.cts} +392 -5
  53. package/dist/{export-lU5qSpHE.d.cts → export-WmYoWmLM.d.cts} +536 -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 +1296 -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 +497 -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
@@ -1,13 +1,25 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/video-editor/types.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
+
3
+
4
+
5
+
6
+
7
+
8
+ var _chunkCN4PJHUGcjs = require('./chunk-CN4PJHUG.cjs');
9
+
10
+
11
+ var _chunkRIWPYSKUcjs = require('./chunk-RIWPYSKU.cjs');
12
+
13
+ // src/video-editor/types.ts
2
14
  var VIDEO_FITS = ["contain", "cover", "fill", "none"];
3
- var VIDEO_TRANSITION_TYPES = ["crossfade", "dip", "wipe", "push", "slide", "iris"];
15
+ var VIDEO_TRANSITION_TYPES = ["crossfade", "dip", "wipe", "push", "slide", "iris", "effect"];
4
16
  var VIDEO_WIPE_DIRECTIONS = ["left", "right", "up", "down"];
5
17
  var videoTransitionAudioCurve = (t) => _nullishCoalesce(t.audioCurve, () => ( (t.type === "dip" ? "linear" : "equal-power")));
6
18
  var VIDEO_BLEND_MODES = ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "add"];
7
19
  var VIDEO_CLIP_ANIMATION_EFFECTS = ["fade", "rise", "drop", "slide-left", "slide-right", "zoom", "pop"];
8
20
  var VIDEO_FADE_CURVES = ["linear", "equal-power", "s-curve", "exponential", "logarithmic"];
9
21
  var VIDEO_PLACEMENT_MODES = ["refuse", "overwrite", "insert"];
10
- var VIDEO_CLIP_TYPES = ["media", "text", "color", "sequence"];
22
+ var VIDEO_CLIP_TYPES = ["media", "text", "color", "sequence", "effect"];
11
23
 
12
24
  // src/video-editor/keyframes.ts
13
25
  var VIDEO_EASE_NAMES = ["linear", "hold", "ease-in", "ease-out", "ease-in-out"];
@@ -953,6 +965,11 @@ function videoClipAnimated(clip, project) {
953
965
  }
954
966
 
955
967
  // src/video-editor/evaluate.ts
968
+ function videoEffectValuesAt(values, clipTime) {
969
+ const out = {};
970
+ for (const [k, v] of Object.entries(_nullishCoalesce(values, () => ( {})))) out[k] = isVideoKeyframes(v) ? videoValueAt(v, clipTime, 0) : v;
971
+ return out;
972
+ }
956
973
  function videoTransformAt(transform, clipTime = 0) {
957
974
  return { x: videoValueAt(_optionalChain([transform, 'optionalAccess', _14 => _14.x]), clipTime, 0), y: videoValueAt(_optionalChain([transform, 'optionalAccess', _15 => _15.y]), clipTime, 0), scale: videoValueAt(_optionalChain([transform, 'optionalAccess', _16 => _16.scale]), clipTime, 1), rotation: videoValueAt(_optionalChain([transform, 'optionalAccess', _17 => _17.rotation]), clipTime, 0) };
958
975
  }
@@ -1068,12 +1085,14 @@ function tracksAt(project, tracks, time, scope) {
1068
1085
  let wipe;
1069
1086
  let dip = null;
1070
1087
  let iris;
1088
+ let effectIn;
1071
1089
  let shift = 0;
1072
1090
  let shiftDirection = "right";
1073
1091
  if (incoming) {
1074
1092
  if (incoming.type === "crossfade") opacity *= incoming.progress;
1075
1093
  else if (incoming.type === "wipe") wipe = { direction: _nullishCoalesce(incoming.transition.direction, () => ( "right")), progress: incoming.progress };
1076
1094
  else if (incoming.type === "iris") iris = { progress: incoming.progress };
1095
+ else if (incoming.type === "effect") effectIn = incoming;
1077
1096
  else if (incoming.type === "push" || incoming.type === "slide") {
1078
1097
  shiftDirection = _nullishCoalesce(incoming.transition.direction, () => ( "right"));
1079
1098
  shift = videoTransitionEase(incoming.progress) - 1;
@@ -1100,14 +1119,279 @@ function tracksAt(project, tracks, time, scope) {
1100
1119
  if (clip.type === "sequence") Object.assign(layer, { sequence: clip.sequence, sourceTime, layers: nested.layers });
1101
1120
  if (clip.type === "text") layer.text = videoTextStyle(clip);
1102
1121
  if (clip.type === "color") layer.color = clip.color;
1122
+ if (clip.type === "effect") layer.generator = { effect: clip.effect, ...clip.name ? { name: clip.name } : {}, values: videoEffectValuesAt(clip.values, clipTime), time: Math.max(0, clipTime) };
1123
+ const effects = (_nullishCoalesce(clip.effects, () => ( []))).filter((e) => e.enabled !== false).map((e) => ({ id: e.id, effect: e.effect, ...e.name ? { name: e.name } : {}, opacity: clamp012(videoValueAt(e.opacity, clipTime, 1)), values: videoEffectValuesAt(e.values, clipTime), time: clipTime })).filter((e) => e.opacity > 0);
1124
+ if (effects.length) layer.effects = effects;
1125
+ if (effectIn) {
1126
+ const before = videoClipBefore(track, clip);
1127
+ const i = before ? layers.findIndex((l) => l.clip === prefix + before.id && l.track === track.id) : -1;
1128
+ const from = i >= 0 ? layers.splice(i, 1)[0] : null;
1129
+ const t = effectIn.transition;
1130
+ layer.transitionEffect = { effect: t.effect.effect, ...t.effect.name ? { name: t.effect.name } : {}, values: videoEffectValuesAt(t.effect.values, 0), progress: effectIn.progress, time: effectIn.progress * t.duration, from };
1131
+ }
1103
1132
  if (layer.opacity > 0) layers.push(layer);
1104
1133
  if (dip && dip.opacity > 0) layers.push({ clip: `transition:${prefix}${incoming ? clip.id : outgoing.next.id}`, track: track.id, type: "color", color: dip.color, opacity: clamp012(dip.opacity), rect: { x: 0, y: 0, width: project.width, height: project.height }, rotation: 0 });
1105
1134
  }
1106
1135
  }
1107
1136
  return { layers, audio };
1108
1137
  }
1138
+ function videoLayersWithoutTransitionEffects(layers) {
1139
+ return layers.flatMap((l) => {
1140
+ const t = l.transitionEffect;
1141
+ if (!t) return [l];
1142
+ const { transitionEffect: _t, ...rest } = l;
1143
+ const self = { ...rest, opacity: rest.opacity * t.progress };
1144
+ return t.from ? [t.from, self] : [self];
1145
+ });
1146
+ }
1109
1147
  function videoFrameLeafLayers(layers) {
1110
- return layers.flatMap((l) => l.layers ? videoFrameLeafLayers(l.layers) : [l]);
1148
+ return layers.flatMap((l) => [..._optionalChain([l, 'access', _27 => _27.transitionEffect, 'optionalAccess', _28 => _28.from]) ? videoFrameLeafLayers([l.transitionEffect.from]) : [], ...l.layers ? videoFrameLeafLayers(l.layers) : [l]]);
1149
+ }
1150
+
1151
+ // src/video-editor/effects.ts
1152
+ function videoProjectEffects(project) {
1153
+ const out = [];
1154
+ for (const { track } of allVideoTracks(project)) for (const clip of track.clips) out.push(...videoClipEffectUses(clip));
1155
+ return out;
1156
+ }
1157
+ var refFields = (r) => ({ effect: r.effect, ...r.name ? { name: r.name } : {}, ...r.provider ? { provider: r.provider } : {} });
1158
+ function videoClipEffectUses(clip) {
1159
+ const out = [];
1160
+ if (clip.type === "effect") out.push({ clip: clip.id, kind: "generator", ...refFields(clip), enabled: true });
1161
+ if (_optionalChain([clip, 'access', _29 => _29.transition, 'optionalAccess', _30 => _30.type]) === "effect" && clip.transition.effect) out.push({ clip: clip.id, kind: "transition", ...refFields(clip.transition.effect), enabled: true });
1162
+ for (const e of _nullishCoalesce(clip.effects, () => ( []))) out.push({ clip: clip.id, kind: "clip", instance: e.id, ...refFields(e), enabled: e.enabled !== false });
1163
+ return out;
1164
+ }
1165
+ var videoLayersUseEffects = (layers) => layers.some((l) => !!(_optionalChain([l, 'access', _31 => _31.effects, 'optionalAccess', _32 => _32.length]) || l.generator || l.transitionEffect || l.layers && videoLayersUseEffects(l.layers)));
1166
+ var videoEffectFrameTime = (time, fps) => Math.floor(time * fps / 1e3 + 1e-6) * 1e3 / fps;
1167
+ var PLACEMENT = /* @__PURE__ */ new Set(["opacity", "rect", "rotation", "blend", "wipe", "iris", "grade", "track"]);
1168
+ var round = (_k, v) => typeof v === "number" ? Math.round(v * 100) / 100 : v;
1169
+ function videoEffectLayerKey(layer, width, height) {
1170
+ const content = layer.transitionEffect ? layer : Object.fromEntries(Object.entries(layer).filter(([k]) => !PLACEMENT.has(k)));
1171
+ return `${width}x${height}:${JSON.stringify(content, round)}`;
1172
+ }
1173
+ function mixEffectPixels(a, b, k) {
1174
+ if (k >= 1) return b;
1175
+ const out = _chunkCN4PJHUGcjs.createEffectPixels.call(void 0, a.width, a.height);
1176
+ for (let i = 0; i < out.data.length; i++) out.data[i] = a.data[i] + (b.data[i] - a.data[i]) * k;
1177
+ return out;
1178
+ }
1179
+ function overEffectPixels(base, top, opacity = 1) {
1180
+ const out = _chunkCN4PJHUGcjs.createEffectPixels.call(void 0, base.width, base.height);
1181
+ const o = out.data;
1182
+ const b = base.data;
1183
+ const t = top.data;
1184
+ for (let i = 0; i < o.length; i += 4) {
1185
+ const ta = t[i + 3] / 255 * opacity;
1186
+ const ba = b[i + 3] / 255;
1187
+ const a = ta + ba * (1 - ta);
1188
+ o[i + 3] = Math.round(a * 255);
1189
+ if (a <= 0) continue;
1190
+ for (let c = 0; c < 3; c++) o[i + c] = (t[i + c] * ta + b[i + c] * ba * (1 - ta)) / a;
1191
+ }
1192
+ return out;
1193
+ }
1194
+ function defaultToImage(p) {
1195
+ const data = new Uint8ClampedArray(p.data);
1196
+ if (typeof ImageData === "undefined") return null;
1197
+ const image = new ImageData(data, p.width, p.height);
1198
+ if (typeof OffscreenCanvas !== "undefined") {
1199
+ const c = new OffscreenCanvas(p.width, p.height);
1200
+ _optionalChain([c, 'access', _33 => _33.getContext, 'call', _34 => _34("2d"), 'optionalAccess', _35 => _35.putImageData, 'call', _36 => _36(image, 0, 0)]);
1201
+ return c;
1202
+ }
1203
+ if (typeof document !== "undefined") {
1204
+ const c = document.createElement("canvas");
1205
+ c.width = p.width;
1206
+ c.height = p.height;
1207
+ _optionalChain([c, 'access', _37 => _37.getContext, 'call', _38 => _38("2d"), 'optionalAccess', _39 => _39.putImageData, 'call', _40 => _40(image, 0, 0)]);
1208
+ return c;
1209
+ }
1210
+ return null;
1211
+ }
1212
+ var VideoEffectsEngine = (_class2 = class {
1213
+
1214
+ __init5() {this.cache = /* @__PURE__ */ new Map()}
1215
+ __init6() {this.pending = /* @__PURE__ */ new Map()}
1216
+ __init7() {this.failures = /* @__PURE__ */ new Map()}
1217
+
1218
+ __init8() {this.descriptions = /* @__PURE__ */ new Map()}
1219
+ __init9() {this.listeners = /* @__PURE__ */ new Set()}
1220
+
1221
+
1222
+ __init10() {this.generation = 0}
1223
+
1224
+ constructor(options = {}) {;_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);
1225
+ this.slot = _nullishCoalesce(options.slot, () => ( new (0, _chunkCN4PJHUGcjs.EffectsSlot)()));
1226
+ this.maxEntries = _nullishCoalesce(options.maxEntries, () => ( 120));
1227
+ this.toImage = _nullishCoalesce(options.toImage, () => ( defaultToImage));
1228
+ this.pool = new (0, _chunkCN4PJHUGcjs.EffectRendererPool)({ maxRenderers: options.maxRenderers });
1229
+ this.detach = this.slot.subscribe(() => {
1230
+ this.reset();
1231
+ this.notify();
1232
+ });
1233
+ }
1234
+ get provider() {
1235
+ return this.slot.provider;
1236
+ }
1237
+ /** True when a provider is registered, so effects can be drawn. */
1238
+ get available() {
1239
+ return !!this.slot.provider;
1240
+ }
1241
+ /** The drawable picture for `key`, or `undefined` when it is not rendered (yet). */
1242
+ get(key) {
1243
+ const e = this.cache.get(key);
1244
+ if (!e) return void 0;
1245
+ this.cache.delete(key);
1246
+ this.cache.set(key, e);
1247
+ if (e.image === void 0) e.image = this.toImage(e.pixels);
1248
+ return e.image;
1249
+ }
1250
+ /** The rendered pixels for `key`. */
1251
+ pixels(key) {
1252
+ return _optionalChain([this, 'access', _41 => _41.cache, 'access', _42 => _42.get, 'call', _43 => _43(key), 'optionalAccess', _44 => _44.pixels]);
1253
+ }
1254
+ /** Why the render for `key` failed, if it did (it is not retried until the cache is cleared). */
1255
+ failure(key) {
1256
+ return this.failures.get(key);
1257
+ }
1258
+ /** Every failure so far, newest last. */
1259
+ failuresList() {
1260
+ return [...this.failures].map(([key, error]) => ({ key, error }));
1261
+ }
1262
+ /** Whether `key` is being rendered. */
1263
+ isPending(key) {
1264
+ return this.pending.has(key);
1265
+ }
1266
+ /**
1267
+ * Starts rendering `job` into `key` unless it is cached, pending or failed. Returns true while
1268
+ * the picture is on its way (so the frame is waiting for it).
1269
+ */
1270
+ request(key, job) {
1271
+ if (this.cache.has(key)) return false;
1272
+ if (this.pending.has(key)) return true;
1273
+ if (this.failures.has(key) || !this.slot.provider) return false;
1274
+ const generation = this.generation;
1275
+ const run = this.run(job).then((pixels) => {
1276
+ if (generation !== this.generation) return;
1277
+ this.cache.set(key, { pixels });
1278
+ while (this.cache.size > this.maxEntries) this.cache.delete(this.cache.keys().next().value);
1279
+ }).catch((error) => {
1280
+ if (generation !== this.generation) return;
1281
+ this.failures.set(key, error instanceof Error ? error : new Error(String(error)));
1282
+ }).finally(() => {
1283
+ if (this.pending.get(key) === run) this.pending.delete(key);
1284
+ if (generation === this.generation) this.notify();
1285
+ });
1286
+ this.pending.set(key, run);
1287
+ return true;
1288
+ }
1289
+ /** Resolves when nothing is being rendered. */
1290
+ async idle() {
1291
+ while (this.pending.size) await Promise.all([...this.pending.values()]);
1292
+ }
1293
+ /** Renders a job now, without the cache. Rejects with the provider's error. */
1294
+ async run(job) {
1295
+ const provider = this.slot.require();
1296
+ if (job.kind === "transition") {
1297
+ const out = await this.render(provider, job.effect, job.from.width, job.from.height, { time: job.time, progress: job.progress, values: job.values, inputs: { from: job.from, to: job.to } });
1298
+ return out;
1299
+ }
1300
+ let cur;
1301
+ if (job.kind === "generator") cur = await this.render(provider, job.effect, job.width, job.height, { time: job.time, values: job.values });
1302
+ else cur = job.input;
1303
+ return this.stack(provider, cur, job.effects);
1304
+ }
1305
+ async stack(provider, input, effects) {
1306
+ let cur = input;
1307
+ for (const e of effects) {
1308
+ const d = await this.describe(provider, e.effect);
1309
+ if (d.inputs.some((i) => i.name === "source")) {
1310
+ const out = await this.render(provider, e.effect, cur.width, cur.height, { time: e.time, values: e.values, inputs: { source: cur } });
1311
+ cur = mixEffectPixels(cur, out, e.opacity);
1312
+ } else {
1313
+ const out = await this.render(provider, e.effect, cur.width, cur.height, { time: e.time, values: e.values });
1314
+ cur = overEffectPixels(cur, out, e.opacity);
1315
+ }
1316
+ }
1317
+ return cur;
1318
+ }
1319
+ /** The provider's description of an effect, fetched once. */
1320
+ describe(provider, id) {
1321
+ let d = this.descriptions.get(id);
1322
+ if (!d) {
1323
+ d = Promise.resolve().then(() => provider.describe(id));
1324
+ d.catch(() => this.descriptions.delete(id));
1325
+ this.descriptions.set(id, d);
1326
+ }
1327
+ return d;
1328
+ }
1329
+ /** Renders through the pool: a few live renderers, one render at a time on each. */
1330
+ render(provider, id, width, height, request) {
1331
+ return this.pool.render(provider, id, { width, height }, request);
1332
+ }
1333
+ /** Forgets every picture and failure and disposes the renderers (e.g. after the provider changes). */
1334
+ reset() {
1335
+ this.generation++;
1336
+ this.cache.clear();
1337
+ this.pending.clear();
1338
+ this.failures.clear();
1339
+ this.descriptions.clear();
1340
+ this.pool.clear();
1341
+ }
1342
+ subscribe(listener) {
1343
+ this.listeners.add(listener);
1344
+ return () => this.listeners.delete(listener);
1345
+ }
1346
+ notify() {
1347
+ for (const l of [...this.listeners]) l();
1348
+ }
1349
+ destroy() {
1350
+ this.reset();
1351
+ this.detach();
1352
+ this.listeners.clear();
1353
+ }
1354
+ }, _class2);
1355
+ var VIDEO_EFFECT_PLACES = {
1356
+ /** A clip's effect stack: filters change the picture, overlays draw over it. */
1357
+ clip: ["filter", "overlay"],
1358
+ transition: ["transition"],
1359
+ /** An effect clip's picture. */
1360
+ generator: ["generator", "title", "overlay"]
1361
+ };
1362
+ function checkVideoEffectPlace(d, place) {
1363
+ const allowed = VIDEO_EFFECT_PLACES[place];
1364
+ if (d.kind === "motion" || !d.uses.some((u) => allowed.includes(u))) {
1365
+ const where = place === "clip" ? "on a clip" : place === "transition" ? "as a transition" : "as an effect clip";
1366
+ const instead = d.uses.includes("transition") ? "set_video_effect_transition" : d.uses.some((u) => VIDEO_EFFECT_PLACES.generator.includes(u)) ? "add_video_effect_clip" : d.uses.some((u) => u === "filter") ? "apply_effect" : null;
1367
+ throw new (0, _chunkCN4PJHUGcjs.EffectUnsupportedError)(
1368
+ `"${d.id}" (${d.name}) is a ${d.uses.join(" / ")} effect and cannot be used ${where}, which takes ${allowed.join(" or ")} effects${instead ? `; use ${instead} instead` : ""}. search_effects with use "${allowed[0]}" lists ones that fit.`,
1369
+ d.id
1370
+ );
1371
+ }
1372
+ }
1373
+ function checkVideoEffectValues(d, values, options = {}) {
1374
+ const plain = {};
1375
+ const errors = [];
1376
+ for (const [k, v] of Object.entries(_nullishCoalesce(values, () => ( {})))) {
1377
+ if (!isVideoKeyframes(v)) {
1378
+ plain[k] = v;
1379
+ continue;
1380
+ }
1381
+ const schema = d.controls.properties[k];
1382
+ const type = _optionalChain([schema, 'optionalAccess', _45 => _45.type]);
1383
+ if (!options.keyframes) errors.push({ path: `/${k}`, message: "cannot be keyframed here; give a plain value." });
1384
+ else if (!schema) errors.push({ path: `/${k}`, message: `is not a control of "${d.id}"; its controls are ${Object.keys(d.controls.properties).join(", ") || "none"}.` });
1385
+ else if (type !== "number" && type !== "integer") errors.push({ path: `/${k}`, message: "only number controls can be keyframed." });
1386
+ else for (const [i, key] of v.keys.entries()) for (const e of _chunkRIWPYSKUcjs.validateJsonSchema.call(void 0, key.v, schema)) errors.push({ path: `/${k}/keys/${i}/v`, message: e.message });
1387
+ }
1388
+ for (const e of _chunkCN4PJHUGcjs.effectValueErrors.call(void 0, d, plain)) {
1389
+ const name = e.path.split("/")[1];
1390
+ const about = name && _optionalChain([d, 'access', _46 => _46.controls, 'access', _47 => _47.properties, 'access', _48 => _48[name], 'optionalAccess', _49 => _49.description]);
1391
+ errors.push(about ? { path: e.path, message: `${e.message} (${about})` } : e);
1392
+ }
1393
+ if (errors.length) throw new (0, _chunkCN4PJHUGcjs.EffectControlError)(d.id, errors);
1394
+ return { ..._nullishCoalesce(options.base, () => ( d.defaults)), ..._nullishCoalesce(values, () => ( {})) };
1111
1395
  }
1112
1396
 
1113
1397
  // src/video-editor/render.ts
@@ -1127,7 +1411,7 @@ function videoWipeRect(rect, wipe) {
1127
1411
  function videoFrameToSvg(frame, options = {}, assets = []) {
1128
1412
  const defs = [];
1129
1413
  const posters = new Map(assets.map((a) => [a.id, a.poster]));
1130
- const draw = (layers, prefix) => layers.map((layer, index) => {
1414
+ const draw = (layers, prefix) => videoLayersWithoutTransitionEffects(layers).map((layer, index) => {
1131
1415
  const i = `${prefix}${index}`;
1132
1416
  const { rect } = layer;
1133
1417
  const attrs = [];
@@ -1137,7 +1421,7 @@ function videoFrameToSvg(frame, options = {}, assets = []) {
1137
1421
  if (layer.layers) style.push("isolation:isolate");
1138
1422
  if (style.length) attrs.push(`style="${style.join(";")}"`);
1139
1423
  if (layer.grade) {
1140
- defs.push(videoGradeSvgFilter(`g${i}`, layer.grade, layer.grade.lut ? _optionalChain([options, 'access', _27 => _27.lutFor, 'optionalCall', _28 => _28(layer.grade.lut.src)]) : null));
1424
+ defs.push(videoGradeSvgFilter(`g${i}`, layer.grade, layer.grade.lut ? _optionalChain([options, 'access', _50 => _50.lutFor, 'optionalCall', _51 => _51(layer.grade.lut.src)]) : null));
1141
1425
  attrs.push(`filter="url(#g${i})"`);
1142
1426
  }
1143
1427
  if (layer.rotation) attrs.push(`transform="rotate(${n(layer.rotation)} ${n(rect.x + rect.width / 2)} ${n(rect.y + rect.height / 2)})"`);
@@ -1168,7 +1452,7 @@ function videoFrameToSvg(frame, options = {}, assets = []) {
1168
1452
  const href = options.imageFor ? options.imageFor(layer, frame) : layer.assetKind === "image" ? _nullishCoalesce(layer.src, () => ( null)) : _nullishCoalesce(posters.get(_nullishCoalesce(layer.asset, () => ( ""))), () => ( null));
1169
1453
  if (href) inner = `<image href="${esc(href)}" ${box} preserveAspectRatio="none"/>`;
1170
1454
  else {
1171
- const label = `${_nullishCoalesce(layer.asset, () => ( layer.clip))} \xB7 ${formatVideoTimecode(_nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(options.fps, () => ( 30)))}`;
1455
+ const label = layer.generator ? `Effect: ${_nullishCoalesce(layer.generator.name, () => ( layer.generator.effect))}` : `${_nullishCoalesce(layer.asset, () => ( layer.clip))} \xB7 ${formatVideoTimecode(_nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(options.fps, () => ( 30)))}`;
1172
1456
  const size = Math.max(10, Math.min(rect.height / 8, rect.width / Math.max(8, label.length * 0.6)));
1173
1457
  inner = `<rect ${box} fill="#334155" stroke="#94a3b8" stroke-width="2"/><text x="${n(rect.x + rect.width / 2)}" y="${n(rect.y + rect.height / 2)}" text-anchor="middle" dominant-baseline="central" font-family="sans-serif" font-size="${n(size)}" fill="#e2e8f0">${esc(label)}</text>`;
1174
1458
  }
@@ -1256,6 +1540,14 @@ function paintVideoLayer(ctx, frame, layer, sourceFor, options) {
1256
1540
  ctx.strokeStyle = "#94a3b8";
1257
1541
  ctx.lineWidth = 2;
1258
1542
  ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
1543
+ if (layer.generator) {
1544
+ const label = `Effect: ${_nullishCoalesce(layer.generator.name, () => ( layer.generator.effect))}`;
1545
+ ctx.font = `600 ${Math.max(12, Math.min(rect.height / 10, rect.width / Math.max(8, label.length * 0.6)))}px sans-serif`;
1546
+ ctx.textAlign = "center";
1547
+ ctx.textBaseline = "middle";
1548
+ ctx.fillStyle = "#e2e8f0";
1549
+ ctx.fillText(label, rect.x + rect.width / 2, rect.y + rect.height / 2);
1550
+ }
1259
1551
  }
1260
1552
  }
1261
1553
  }
@@ -1265,18 +1557,118 @@ function drawVideoFrame(ctx, frame, sourceFor, scale = 1, options = {}) {
1265
1557
  ctx.globalAlpha = 1;
1266
1558
  ctx.fillStyle = frame.background;
1267
1559
  ctx.fillRect(0, 0, frame.width, frame.height);
1268
- drawVideoLayers(ctx, frame, frame.layers, sourceFor, scale, options, 0);
1560
+ const state = { missing: 0, waiting: 0 };
1561
+ const counted = (layer) => {
1562
+ const source = sourceFor(layer);
1563
+ if (!source && layer.type === "media") state.missing++;
1564
+ return source;
1565
+ };
1566
+ drawVideoLayers(ctx, frame, frame.layers, counted, scale, options, 0, state);
1269
1567
  ctx.restore();
1270
1568
  }
1271
- function drawVideoLayers(ctx, frame, layers, sourceFor, scale, options, depth) {
1569
+ var unplaced = (layer) => {
1570
+ const { rotation: _r, wipe: _w, iris: _i, grade: _g, blend: _b, effects: _e, transitionEffect: _t, ...rest } = layer;
1571
+ return { ...rest, opacity: 1, rotation: 0 };
1572
+ };
1573
+ var readPixels = (s, width, height) => {
1574
+ const img = s.ctx.getImageData(0, 0, width, height);
1575
+ return { width, height, data: img.data };
1576
+ };
1577
+ function begin(s, width, height, scale, dx = 0, dy = 0) {
1578
+ const g = s.ctx;
1579
+ g.save();
1580
+ g.setTransform(1, 0, 0, 1, 0, 0);
1581
+ g.clearRect(0, 0, width, height);
1582
+ g.setTransform(scale, 0, 0, scale, dx, dy);
1583
+ g.globalAlpha = 1;
1584
+ g.globalCompositeOperation = "source-over";
1585
+ return g;
1586
+ }
1587
+ function effectPicture(frame, layer, source, scale, options, depth, state) {
1588
+ const engine = options.effects;
1589
+ if (!_optionalChain([engine, 'optionalAccess', _52 => _52.available])) return null;
1590
+ const { rect } = layer;
1591
+ const w = Math.max(1, Math.round(rect.width * scale));
1592
+ const h = Math.max(1, Math.round(rect.height * scale));
1593
+ const key = videoEffectLayerKey(layer, w, h);
1594
+ const hit = engine.get(key);
1595
+ if (hit !== void 0 || engine.failure(key)) return _nullishCoalesce(hit, () => ( null));
1596
+ let job;
1597
+ if (layer.generator) job = { kind: "generator", width: w, height: h, ...layer.generator, effects: _nullishCoalesce(layer.effects, () => ( [])) };
1598
+ else {
1599
+ const s = _optionalChain([options, 'access', _53 => _53.scratch, 'optionalCall', _54 => _54(w, h, 1e3 + 4 * depth)]);
1600
+ if (!s) return null;
1601
+ const missing = state.missing;
1602
+ const g = begin(s, w, h, scale, -rect.x * scale, -rect.y * scale);
1603
+ const bare = unplaced(layer);
1604
+ paintVideoLayer(g, frame, bare, (l) => source(l === bare ? layer : l), options);
1605
+ g.restore();
1606
+ if (state.missing !== missing) return null;
1607
+ job = { kind: "stack", input: readPixels(s, w, h), effects: _nullishCoalesce(layer.effects, () => ( [])) };
1608
+ }
1609
+ if (engine.request(key, job)) {
1610
+ state.waiting++;
1611
+ _optionalChain([options, 'access', _55 => _55.onEffectWaiting, 'optionalCall', _56 => _56()]);
1612
+ }
1613
+ return null;
1614
+ }
1615
+ function drawEffectTransition(ctx, frame, layer, sourceFor, scale, options, depth, state) {
1616
+ const engine = options.effects;
1617
+ const t = layer.transitionEffect;
1618
+ if (!_optionalChain([engine, 'optionalAccess', _57 => _57.available])) return false;
1619
+ const cw = Math.max(1, Math.round(frame.width * scale));
1620
+ const ch = Math.max(1, Math.round(frame.height * scale));
1621
+ const key = videoEffectLayerKey(layer, cw, ch);
1622
+ const hit = engine.get(key);
1623
+ if (hit) {
1624
+ ctx.save();
1625
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
1626
+ ctx.globalAlpha = 1;
1627
+ ctx.globalCompositeOperation = "source-over";
1628
+ ctx.drawImage(hit, 0, 0, cw, ch);
1629
+ ctx.restore();
1630
+ return true;
1631
+ }
1632
+ if (hit === null || engine.failure(key) || engine.isPending(key)) {
1633
+ if (engine.isPending(key)) {
1634
+ state.waiting++;
1635
+ _optionalChain([options, 'access', _58 => _58.onEffectWaiting, 'optionalCall', _59 => _59()]);
1636
+ }
1637
+ return false;
1638
+ }
1639
+ const a = _optionalChain([options, 'access', _60 => _60.scratch, 'optionalCall', _61 => _61(cw, ch, 1e3 + 4 * depth + 1)]);
1640
+ const b = _optionalChain([options, 'access', _62 => _62.scratch, 'optionalCall', _63 => _63(cw, ch, 1e3 + 4 * depth + 2)]);
1641
+ if (!a || !b) return false;
1642
+ const before = { ...state };
1643
+ const ga = begin(a, cw, ch, scale);
1644
+ drawVideoLayers(ga, frame, t.from ? [t.from] : [], sourceFor, scale, options, depth + 1, state);
1645
+ ga.restore();
1646
+ const { transitionEffect: _t, ...incoming } = layer;
1647
+ const gb = begin(b, cw, ch, scale);
1648
+ drawVideoLayers(gb, frame, [incoming], sourceFor, scale, options, depth + 1, state);
1649
+ gb.restore();
1650
+ if (state.missing !== before.missing || state.waiting !== before.waiting) return false;
1651
+ const job = { kind: "transition", effect: t.effect, values: t.values, progress: t.progress, time: t.time, from: readPixels(a, cw, ch), to: readPixels(b, cw, ch) };
1652
+ if (engine.request(key, job)) {
1653
+ state.waiting++;
1654
+ _optionalChain([options, 'access', _64 => _64.onEffectWaiting, 'optionalCall', _65 => _65()]);
1655
+ }
1656
+ return false;
1657
+ }
1658
+ function drawVideoLayers(ctx, frame, layers, sourceFor, scale, options, depth, state) {
1272
1659
  const cw = Math.max(1, Math.round(frame.width * scale));
1273
1660
  const ch = Math.max(1, Math.round(frame.height * scale));
1274
- for (const layer of layers) {
1661
+ for (const original of layers) {
1662
+ let layer = original;
1663
+ if (layer.transitionEffect) {
1664
+ if (!drawEffectTransition(ctx, frame, layer, sourceFor, scale, options, depth, state)) drawVideoLayers(ctx, frame, videoLayersWithoutTransitionEffects([layer]), sourceFor, scale, options, depth, state);
1665
+ continue;
1666
+ }
1275
1667
  let source = sourceFor;
1276
1668
  if (layer.layers) {
1277
- const group = _optionalChain([options, 'access', _29 => _29.scratch, 'optionalCall', _30 => _30(cw, ch, 2 * depth)]);
1669
+ const group = _optionalChain([options, 'access', _66 => _66.scratch, 'optionalCall', _67 => _67(cw, ch, 2 * depth)]);
1278
1670
  if (!group) {
1279
- drawVideoLayers(ctx, frame, layer.layers, sourceFor, scale, options, depth + 1);
1671
+ drawVideoLayers(ctx, frame, layer.layers, sourceFor, scale, options, depth + 1, state);
1280
1672
  continue;
1281
1673
  }
1282
1674
  const g = group.ctx;
@@ -1286,13 +1678,23 @@ function drawVideoLayers(ctx, frame, layers, sourceFor, scale, options, depth) {
1286
1678
  g.setTransform(scale, 0, 0, scale, 0, 0);
1287
1679
  g.globalAlpha = 1;
1288
1680
  g.globalCompositeOperation = "source-over";
1289
- drawVideoLayers(g, frame, layer.layers, sourceFor, scale, options, depth + 1);
1681
+ drawVideoLayers(g, frame, layer.layers, sourceFor, scale, options, depth + 1, state);
1290
1682
  g.restore();
1291
- source = (l) => l === layer ? group.canvas : sourceFor(l);
1683
+ const self = layer;
1684
+ source = (l) => l === self ? group.canvas : sourceFor(l);
1685
+ }
1686
+ if (_optionalChain([layer, 'access', _68 => _68.effects, 'optionalAccess', _69 => _69.length]) || layer.generator) {
1687
+ const picture = effectPicture(frame, layer, source, scale, options, depth, state);
1688
+ if (picture) {
1689
+ const { layers: _l, text: _t, color: _c, generator: _g, effects: _e, ...rest } = layer;
1690
+ const drawn = { ...rest, type: "media" };
1691
+ layer = drawn;
1692
+ source = (l) => l === drawn ? picture : sourceFor(l);
1693
+ }
1292
1694
  }
1293
- const setting = _optionalChain([layer, 'access', _31 => _31.grade, 'optionalAccess', _32 => _32.lut]);
1294
- const lut = setting ? _optionalChain([options, 'access', _33 => _33.lutFor, 'optionalCall', _34 => _34(setting.src)]) : null;
1295
- const scratch = lut ? _optionalChain([options, 'access', _35 => _35.scratch, 'optionalCall', _36 => _36(cw, ch, 2 * depth + 1)]) : null;
1695
+ const setting = _optionalChain([layer, 'access', _70 => _70.grade, 'optionalAccess', _71 => _71.lut]);
1696
+ const lut = setting ? _optionalChain([options, 'access', _72 => _72.lutFor, 'optionalCall', _73 => _73(setting.src)]) : null;
1697
+ const scratch = lut ? _optionalChain([options, 'access', _74 => _74.scratch, 'optionalCall', _75 => _75(cw, ch, 2 * depth + 1)]) : null;
1296
1698
  ctx.save();
1297
1699
  ctx.setTransform(scale, 0, 0, scale, 0, 0);
1298
1700
  if (lut && scratch) {
@@ -1320,9 +1722,44 @@ function drawVideoLayers(ctx, frame, layers, sourceFor, scale, options, depth) {
1320
1722
  ctx.restore();
1321
1723
  }
1322
1724
  }
1725
+ async function renderVideoFrameExact(ctx, project, time, sourceFor, options = {}) {
1726
+ const frame = videoFrameAt(project, videoEffectFrameTime(time, project.fps));
1727
+ const engine = options.effects;
1728
+ const before = new Set(_nullishCoalesce(_optionalChain([engine, 'optionalAccess', _76 => _76.failuresList, 'call', _77 => _77(), 'access', _78 => _78.map, 'call', _79 => _79((f) => f.error)]), () => ( [])));
1729
+ let complete = false;
1730
+ for (let pass = 0; pass < (_nullishCoalesce(options.maxPasses, () => ( 8))); pass++) {
1731
+ let waiting = 0;
1732
+ let missing = 0;
1733
+ drawVideoFrame(
1734
+ ctx,
1735
+ frame,
1736
+ (layer) => {
1737
+ if (layer.type === "effect") return null;
1738
+ const s = sourceFor(layer);
1739
+ if (!s) missing++;
1740
+ return s;
1741
+ },
1742
+ _nullishCoalesce(options.scale, () => ( 1)),
1743
+ {
1744
+ ...options,
1745
+ onEffectWaiting: () => {
1746
+ waiting++;
1747
+ _optionalChain([options, 'access', _80 => _80.onEffectWaiting, 'optionalCall', _81 => _81()]);
1748
+ }
1749
+ }
1750
+ );
1751
+ if (!waiting) {
1752
+ complete = missing === 0;
1753
+ break;
1754
+ }
1755
+ await engine.idle();
1756
+ }
1757
+ const failures = (_nullishCoalesce(_optionalChain([engine, 'optionalAccess', _82 => _82.failuresList, 'call', _83 => _83()]), () => ( []))).map((f) => f.error).filter((e) => !before.has(e));
1758
+ return { frame, complete: complete && !failures.length, failures };
1759
+ }
1323
1760
 
1324
1761
  // src/video-editor/export.ts
1325
- var reelName = (asset) => (_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _37 => _37.name]), () => ( _optionalChain([asset, 'optionalAccess', _38 => _38.id]))), () => ( "AX"))).replace(/\.[a-z0-9]+$/i, "").replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 8) || "AX";
1762
+ var reelName = (asset) => (_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _84 => _84.name]), () => ( _optionalChain([asset, 'optionalAccess', _85 => _85.id]))), () => ( "AX"))).replace(/\.[a-z0-9]+$/i, "").replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 8) || "AX";
1326
1763
  function toVideoEdl(project, options = {}) {
1327
1764
  const track = options.track !== void 0 ? project.tracks.find((t) => t.id === options.track) : [...project.tracks].reverse().find((t) => t.kind === "video");
1328
1765
  if (!track) throw new Error(options.track !== void 0 ? `There is no track "${options.track}".` : "The project has no video track.");
@@ -1357,14 +1794,20 @@ function toVideoEdl(project, options = {}) {
1357
1794
  lines.push(row(n2, reel, `${t.type === "crossfade" || t.type === "dip" ? "D" : "W001"} ${frames}`, sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
1358
1795
  } else lines.push(row(n2, reel, "C", sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
1359
1796
  if (clip.type === "media" && videoClipSpeed(clip) !== 1) lines.push(`M2 ${reel.padEnd(8)} ${(videoClipSpeed(clip) * fps).toFixed(1).padStart(6)} ${tc(sourceAt(clip, recIn))}`);
1360
- if (clip.type === "media") lines.push(`* FROM CLIP NAME: ${_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _39 => _39.name]), () => ( _optionalChain([asset, 'optionalAccess', _40 => _40.src]))), () => ( clip.asset))}`);
1797
+ if (clip.type === "media") lines.push(`* FROM CLIP NAME: ${_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _86 => _86.name]), () => ( _optionalChain([asset, 'optionalAccess', _87 => _87.src]))), () => ( clip.asset))}`);
1361
1798
  if (clip.type === "text") lines.push(`* TITLE: ${clip.text.replace(/\n/g, " ")}`);
1362
1799
  if (clip.type === "color") lines.push(`* COLOR: ${clip.color}`);
1800
+ if (clip.type === "effect") lines.push(`* EFFECT CLIP: ${_nullishCoalesce(clip.name, () => ( clip.effect))} (${clip.effect})`);
1801
+ if (_optionalChain([clip, 'access', _88 => _88.transition, 'optionalAccess', _89 => _89.type]) === "effect") lines.push(`* EFFECT TRANSITION: ${_nullishCoalesce(_optionalChain([clip, 'access', _90 => _90.transition, 'access', _91 => _91.effect, 'optionalAccess', _92 => _92.name]), () => ( _optionalChain([clip, 'access', _93 => _93.transition, 'access', _94 => _94.effect, 'optionalAccess', _95 => _95.effect])))}`);
1802
+ for (const e of _nullishCoalesce(clip.effects, () => ( []))) if (e.enabled !== false) lines.push(`* EFFECT: ${_nullishCoalesce(e.name, () => ( e.effect))} (${e.effect})`);
1363
1803
  if (clip.type === "sequence") lines.push(`* COMPOUND CLIP: ${_nullishCoalesce(clip.name, () => ( clip.sequence))} (sequence ${clip.sequence} from ${tc(_nullishCoalesce(clip.in, () => ( 0)))}, not flattened)`);
1364
1804
  lines.push("");
1365
1805
  }
1366
1806
  return lines.join("\n");
1367
1807
  }
1808
+ function videoFfmpegUnsupportedEffects(project) {
1809
+ return allVideoTracks(project).filter(({ track }) => track.kind === "video" && !track.hidden).flatMap(({ track }) => track.clips.flatMap(videoClipEffectUses)).filter((u) => u.enabled);
1810
+ }
1368
1811
  function loudnormFilter(target = {}, measure = false) {
1369
1812
  const I = _nullishCoalesce(target.integrated, () => ( -14));
1370
1813
  const TP = _nullishCoalesce(target.truePeak, () => ( -1));
@@ -1447,7 +1890,21 @@ function buildFfmpeg(project, options, measure) {
1447
1890
  const H = even(project.height);
1448
1891
  const fps = project.fps;
1449
1892
  const inputs = [];
1450
- const graph = measure ? [] : [`color=c=${color(_nullishCoalesce(project.background, () => ( "#000000")))}:s=${W}x${H}:r=${fps}:d=${sec(D)},format=yuva420p[base]`];
1893
+ const frames = measure ? void 0 : options.frames;
1894
+ if (!measure && !frames) {
1895
+ const effects = videoFfmpegUnsupportedEffects(project);
1896
+ if (effects.length) {
1897
+ const list = effects.slice(0, 5).map((u) => `${u.kind === "generator" ? "effect clip" : u.kind === "transition" ? "the transition into" : "an effect on"} "${u.clip}" (${_nullishCoalesce(u.name, () => ( u.effect))})`).join(", ");
1898
+ throw new Error(
1899
+ `ffmpeg cannot draw provider effects, and this project uses ${effects.length}: ${list}${effects.length > 5 ? ", ..." : ""}. Render the picture frame by frame with renderVideoFrameExact (the preview's drawing, with the effects provider) to PNGs or raw RGBA and pass them as frames: { input: "frames/%06d.png" } (or { input: "pipe:0", format: "rawvideo" }); ffmpeg still mixes the sound. Or turn the effects off.`
1900
+ );
1901
+ }
1902
+ }
1903
+ if (frames) {
1904
+ if (frames.format === "rawvideo") inputs.push(["-f", "rawvideo", "-pix_fmt", "rgba", "-s", `${W}x${H}`, "-framerate", String(fps), "-i", frames.input]);
1905
+ else inputs.push(["-framerate", String(fps), "-i", frames.input]);
1906
+ }
1907
+ const graph = measure || frames ? [] : [`color=c=${color(_nullishCoalesce(project.background, () => ( "#000000")))}:s=${W}x${H}:r=${fps}:d=${sec(D)},format=yuva420p[base]`];
1451
1908
  let usesDrawtext = false;
1452
1909
  const animated = /* @__PURE__ */ new Set();
1453
1910
  const ramped = /* @__PURE__ */ new Set();
@@ -1565,13 +2022,13 @@ function buildFfmpeg(project, options, measure) {
1565
2022
  }
1566
2023
  let index;
1567
2024
  if (shows && asset && asset.kind !== "audio") index = input(clip, asset, lead, tail);
1568
- const audible = clip.type === "sequence" ? !!_optionalChain([compound, 'optionalAccess', _41 => _41.sound]) : videoAssetHasSound(asset);
2025
+ const audible = clip.type === "sequence" ? !!_optionalChain([compound, 'optionalAccess', _96 => _96.sound]) : videoAssetHasSound(asset);
1569
2026
  if (scope.sound && audible && (clip.type === "media" || clip.type === "sequence") && !clip.muted && !track.muted) {
1570
2027
  const trackGain = _nullishCoalesce(track.volume, () => ( 1));
1571
2028
  const volume = isVideoKeyframes(clip.volume) ? `volume='${trackGain}*(${expr(clip.volume, `(t*1000${lead ? `-${Math.round(lead)}` : ""})`, 1, "volume")})':eval=frame` : `volume=${(_nullishCoalesce(clip.volume, () => ( 1))) * trackGain}`;
1572
2029
  const ramp = clip.type === "media" ? clip.timeRemap : void 0;
1573
2030
  const ai = compound ? -1 : _nullishCoalesce(index, () => ( input(clip, asset, lead, tail)));
1574
- let source2 = _nullishCoalesce(_optionalChain([compound, 'optionalAccess', _42 => _42.sound]), () => ( `[${ai}:a]`));
2031
+ let source2 = _nullishCoalesce(_optionalChain([compound, 'optionalAccess', _97 => _97.sound]), () => ( `[${ai}:a]`));
1575
2032
  if (ramp) {
1576
2033
  source2 = `[r${ak}]`;
1577
2034
  graph.push(...rampedSound(ramp, `${ai}:a`, source2, lead, clip.duration + tail));
@@ -1585,7 +2042,7 @@ function buildFfmpeg(project, options, measure) {
1585
2042
  if (lead) chain2.push(`afade=t=in:st=0:d=${sec(2 * lead)}${inCurve}`);
1586
2043
  if (tail) chain2.push(`afade=t=out:st=${sec(span - 2 * tail)}:d=${sec(2 * tail)}${outCurve}`);
1587
2044
  if (before2 && clip.transition.type === "dip") chain2.push(`afade=t=in:st=0:d=${sec(clip.transition.duration / 2)}${inCurve}`);
1588
- if (_optionalChain([next2, 'optionalAccess', _43 => _43.transition, 'access', _44 => _44.type]) === "dip") chain2.push(`afade=t=out:st=${sec(span - next2.transition.duration / 2)}:d=${sec(next2.transition.duration / 2)}${outCurve}`);
2045
+ if (_optionalChain([next2, 'optionalAccess', _98 => _98.transition, 'access', _99 => _99.type]) === "dip") chain2.push(`afade=t=out:st=${sec(span - next2.transition.duration / 2)}:d=${sec(next2.transition.duration / 2)}${outCurve}`);
1589
2046
  if (clip.fadeIn) chain2.push(`afade=t=in:st=${sec(lead)}:d=${sec(clip.fadeIn)}${afadeCurve(clip.fadeInCurve)}`);
1590
2047
  if (clip.fadeOut) chain2.push(`afade=t=out:st=${sec(lead + clip.duration - clip.fadeOut)}:d=${sec(clip.fadeOut)}${afadeCurve(clip.fadeOutCurve)}`);
1591
2048
  chain2.push(`adelay=${Math.round(t0)}:all=1`);
@@ -1598,7 +2055,7 @@ function buildFfmpeg(project, options, measure) {
1598
2055
  const onTimeline = `(t*1000-${Math.round(clip.start)})`;
1599
2056
  const onChain = (v) => `(${v}*1000${lead ? `-${Math.round(lead)}` : ""})`;
1600
2057
  const tf = clip.transform;
1601
- const moving = VIDEO_TRANSFORM_PROPERTIES.some((p) => isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _45 => _45[p]])));
2058
+ const moving = VIDEO_TRANSFORM_PROPERTIES.some((p) => isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _100 => _100[p]])));
1602
2059
  if (clip.type === "text" && options.titleImage) {
1603
2060
  inputs.push(["-loop", "1", "-framerate", String(fps), "-t", sec(span), "-i", options.titleImage(moving ? { ...clip, transform: void 0 } : clip, { width: project.width, height: project.height })]);
1604
2061
  index = inputs.length - 1;
@@ -1608,7 +2065,7 @@ function buildFfmpeg(project, options, measure) {
1608
2065
  const op = isVideoKeyframes(clip.opacity) ? `clip(${expr(clip.opacity, onTimeline, 1, "opacity")},0,1)` : String(_nullishCoalesce(clip.opacity, () => ( 1)));
1609
2066
  const alpha = [op, clip.fadeIn ? `min(1,(t-${sec(clip.start)})/${sec(clip.fadeIn)})` : "", clip.fadeOut ? `min(1,(${sec(end)}-t)/${sec(clip.fadeOut)})` : ""].filter(Boolean).join("*");
1610
2067
  const coord = (axis) => {
1611
- const v = _optionalChain([tf, 'optionalAccess', _46 => _46[axis]]);
2068
+ const v = _optionalChain([tf, 'optionalAccess', _101 => _101[axis]]);
1612
2069
  const base2 = `(${axis === "x" ? "w-text_w" : "h-text_h"})/2`;
1613
2070
  return isVideoKeyframes(v) ? `${axis}='${base2}+(${expr(v, onTimeline, 0, "position")})'` : `${axis}=${base2}+${_nullishCoalesce(v, () => ( 0))}`;
1614
2071
  };
@@ -1616,7 +2073,7 @@ function buildFfmpeg(project, options, measure) {
1616
2073
  const opts = [
1617
2074
  `text=${ffmpegFilterValue(clip.text)}`,
1618
2075
  options.fontFile ? `fontfile=${ffmpegFilterValue(options.fontFile)}` : `font=${ffmpegFilterValue(_nullishCoalesce(clip.fontFamily, () => ( "sans-serif")))}`,
1619
- isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _47 => _47.scale])) ? `fontsize='${fontSize}*(${expr(tf.scale, onTimeline, 1, "scale")})'` : `fontsize=${Math.round(fontSize * (_nullishCoalesce(_optionalChain([tf, 'optionalAccess', _48 => _48.scale]), () => ( 1))))}`,
2076
+ isVideoKeyframes(_optionalChain([tf, 'optionalAccess', _102 => _102.scale])) ? `fontsize='${fontSize}*(${expr(tf.scale, onTimeline, 1, "scale")})'` : `fontsize=${Math.round(fontSize * (_nullishCoalesce(_optionalChain([tf, 'optionalAccess', _103 => _103.scale]), () => ( 1))))}`,
1620
2077
  `fontcolor=${color(_nullishCoalesce(clip.color, () => ( "#ffffff")))}`,
1621
2078
  coord("x"),
1622
2079
  coord("y"),
@@ -1624,8 +2081,8 @@ function buildFfmpeg(project, options, measure) {
1624
2081
  ...clip.background ? ["box=1", `boxcolor=${color(clip.background)}`, `boxborderw=${Math.round((_nullishCoalesce(clip.fontSize, () => ( 64))) / 2)}`] : [],
1625
2082
  `enable='between(t,${sec(clip.start)},${sec(end)})'`
1626
2083
  ];
1627
- if (_optionalChain([tf, 'optionalAccess', _49 => _49.rotation])) notes.push(`Title "${clip.id}" is drawn without its rotation (drawtext cannot rotate).`);
1628
- if (videoGradeFfmpegFilters(clip.grade).length || normalizeVideoGradeLut(_optionalChain([clip, 'access', _50 => _50.grade, 'optionalAccess', _51 => _51.lut]))) notes.push(`Title "${clip.id}" is drawn without its grade (drawtext draws straight onto the picture); pass titleImage to grade titles.`);
2084
+ if (_optionalChain([tf, 'optionalAccess', _104 => _104.rotation])) notes.push(`Title "${clip.id}" is drawn without its rotation (drawtext cannot rotate).`);
2085
+ if (videoGradeFfmpegFilters(clip.grade).length || normalizeVideoGradeLut(_optionalChain([clip, 'access', _105 => _105.grade, 'optionalAccess', _106 => _106.lut]))) notes.push(`Title "${clip.id}" is drawn without its grade (drawtext draws straight onto the picture); pass titleImage to grade titles.`);
1629
2086
  if (clip.blend && clip.blend !== "normal") notes.push(`Title "${clip.id}" is drawn without its blend mode (drawtext draws straight onto the picture); pass titleImage to blend titles.`);
1630
2087
  graph.push(`[${cur2}]drawtext=${opts.join(":")}[${next}]`);
1631
2088
  cur2 = next;
@@ -1638,7 +2095,7 @@ function buildFfmpeg(project, options, measure) {
1638
2095
  const chain = [];
1639
2096
  let source;
1640
2097
  if (clip.type === "color") source = `color=c=${color(clip.color)}:s=${even(rect.width)}x${even(rect.height)}:r=${fps}:d=${sec(span)}`;
1641
- else if (_optionalChain([compound, 'optionalAccess', _52 => _52.picture])) {
2098
+ else if (_optionalChain([compound, 'optionalAccess', _107 => _107.picture])) {
1642
2099
  source = compound.picture;
1643
2100
  chain.push(`scale=${even(rect.width)}:${even(rect.height)}`);
1644
2101
  } else {
@@ -1648,7 +2105,7 @@ function buildFfmpeg(project, options, measure) {
1648
2105
  }
1649
2106
  const grade = videoGradeFfmpegFilters(clip.grade);
1650
2107
  if (grade.length) chain.push("format=rgba", ...grade);
1651
- const lut = normalizeVideoGradeLut(_optionalChain([clip, 'access', _53 => _53.grade, 'optionalAccess', _54 => _54.lut]));
2108
+ const lut = normalizeVideoGradeLut(_optionalChain([clip, 'access', _108 => _108.grade, 'optionalAccess', _109 => _109.lut]));
1652
2109
  if (lut) {
1653
2110
  chain.push("format=gbrap");
1654
2111
  const path = options.resolveLut ? options.resolveLut(lut.src) : lut.src;
@@ -1679,10 +2136,10 @@ function buildFfmpeg(project, options, measure) {
1679
2136
  const r = videoIrisRadius({ width: W, height: H }, 1);
1680
2137
  chain.push(`geq=lum='lum(X,Y)':cb='cb(X,Y)':cr='cr(X,Y)':a='if(lte(hypot(X+${Math.round(rect.x)}-${W / 2},Y+${Math.round(rect.y)}-${H / 2}),${Math.round(r)}*min(1,T/${sec(2 * lead)})),alpha(X,Y),0)'`);
1681
2138
  }
1682
- const rotation = _optionalChain([placed, 'optionalAccess', _55 => _55.rotation]);
2139
+ const rotation = _optionalChain([placed, 'optionalAccess', _110 => _110.rotation]);
1683
2140
  if (isVideoKeyframes(rotation)) chain.push(`rotate=a='(${expr(rotation, onChain("t"), 0, "rotation")})*PI/180':c=black@0:ow='hypot(iw,ih)':oh=ow`);
1684
2141
  else if (rotation) chain.push(`rotate=${rotation}*PI/180:c=black@0:ow=rotw(${rotation}*PI/180):oh=roth(${rotation}*PI/180)`);
1685
- if (isVideoKeyframes(_optionalChain([placed, 'optionalAccess', _56 => _56.scale]))) {
2142
+ if (isVideoKeyframes(_optionalChain([placed, 'optionalAccess', _111 => _111.scale]))) {
1686
2143
  const s = expr(placed.scale, onChain("t"), 1, "scale");
1687
2144
  chain.push(`scale=w='max(2,trunc(iw*(${s})/2)*2)':h='max(2,trunc(ih*(${s})/2)*2)':eval=frame`);
1688
2145
  }
@@ -1701,9 +2158,9 @@ function buildFfmpeg(project, options, measure) {
1701
2158
  const into = lead ? clip.transition.type : void 0;
1702
2159
  if (into === "push" || into === "slide") shiftBy(clip.transition.direction, clip.start - lead, 2 * lead, true);
1703
2160
  const after = tail ? sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && c.transition) : void 0;
1704
- if (_optionalChain([after, 'optionalAccess', _57 => _57.transition, 'access', _58 => _58.type]) === "push") shiftBy(after.transition.direction, end - tail, 2 * tail, false);
2161
+ if (_optionalChain([after, 'optionalAccess', _112 => _112.transition, 'access', _113 => _113.type]) === "push") shiftBy(after.transition.direction, end - tail, 2 * tail, false);
1705
2162
  const at = (axis, c) => {
1706
- const v = _optionalChain([placed, 'optionalAccess', _59 => _59[axis]]);
2163
+ const v = _optionalChain([placed, 'optionalAccess', _114 => _114[axis]]);
1707
2164
  const extra = shifts[axis].map((s) => `+${s}`).join("");
1708
2165
  return isVideoKeyframes(v) ? `${axis}='${Math.round(axis === "x" ? project.width / 2 : project.height / 2)}+(${expr(v, onTimeline, 0, "position")})-${axis === "x" ? "w" : "h"}/2${extra}'` : `${axis}='${Math.round(c)}-${axis === "x" ? "w" : "h"}/2${extra}'`;
1709
2166
  };
@@ -1739,17 +2196,18 @@ function buildFfmpeg(project, options, measure) {
1739
2196
  }
1740
2197
  return { video: cur2, audio: sounds };
1741
2198
  };
1742
- const top = compose(project.tracks, measure ? null : "base", D, { within: [], picture: !measure, sound: true });
2199
+ const top = compose(project.tracks, measure || frames ? null : "base", D, { within: [], picture: !measure && !frames, sound: true });
1743
2200
  const audio = top.audio;
1744
2201
  const cur = top.video;
1745
- if (!measure) graph.push(`[${cur}]format=yuv420p[vout]`);
2202
+ if (frames) graph.push(`[0:v]scale=${W}:${H},format=yuv420p,trim=duration=${sec(D)}[vout]`);
2203
+ else if (!measure) graph.push(`[${cur}]format=yuv420p[vout]`);
1746
2204
  if (measure && !audio.length) throw new Error("Nothing on the timeline makes a sound, so there is no loudness to measure.");
1747
2205
  const loudness = options.loudness || measure ? `,${loudnormFilter(options.loudness, measure)}` : "";
1748
2206
  if (audio.length) graph.push(`${audio.join("")}amix=inputs=${audio.length}:normalize=0:duration=longest,apad,atrim=0:${sec(D)}${loudness}[aout]`);
1749
2207
  if (options.loudness && !audio.length) notes.push("Nothing makes a sound, so there was no loudness to normalise.");
1750
2208
  else if (options.loudness && !options.loudness.measured)
1751
2209
  notes.push("Loudness is normalised in one pass, which adjusts the level as it goes; for a fixed gain that keeps the dynamics, run toVideoLoudnessMeasure first and pass its result as loudness.measured.");
1752
- if (allVideoTracks(project).some(({ track: t }) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _60 => _60.get, 'call', _61 => _61(c.asset), 'optionalAccess', _62 => _62.kind]) === "video" && _optionalChain([assets, 'access', _63 => _63.get, 'call', _64 => _64(c.asset), 'optionalAccess', _65 => _65.hasAudio]) === void 0)))
2210
+ if (allVideoTracks(project).some(({ track: t }) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _115 => _115.get, 'call', _116 => _116(c.asset), 'optionalAccess', _117 => _117.kind]) === "video" && _optionalChain([assets, 'access', _118 => _118.get, 'call', _119 => _119(c.asset), 'optionalAccess', _120 => _120.hasAudio]) === void 0)))
1753
2211
  notes.push('Video assets are assumed to have sound; set "hasAudio": false on any that do not, or ffmpeg will stop at a missing audio stream.');
1754
2212
  if (animated.size)
1755
2213
  notes.push(`Keyframed ${[...animated].sort().join(", ")} ${animated.size > 1 ? "are" : "is"} rendered as straight lines between keys, with eased segments sampled every two frames${animated.has("scale") ? "; animated scale needs ffmpeg 5 or later (scale with eval=frame)" : ""}.`);
@@ -1904,5 +2362,20 @@ function buildFfmpeg(project, options, measure) {
1904
2362
 
1905
2363
 
1906
2364
 
1907
- exports.VIDEO_FITS = VIDEO_FITS; exports.VIDEO_TRANSITION_TYPES = VIDEO_TRANSITION_TYPES; exports.VIDEO_WIPE_DIRECTIONS = VIDEO_WIPE_DIRECTIONS; exports.videoTransitionAudioCurve = videoTransitionAudioCurve; exports.VIDEO_BLEND_MODES = VIDEO_BLEND_MODES; exports.VIDEO_CLIP_ANIMATION_EFFECTS = VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_FADE_CURVES = VIDEO_FADE_CURVES; exports.VIDEO_PLACEMENT_MODES = VIDEO_PLACEMENT_MODES; exports.VIDEO_CLIP_TYPES = VIDEO_CLIP_TYPES; exports.VIDEO_EASE_NAMES = VIDEO_EASE_NAMES; exports.VIDEO_KEYFRAME_PROPERTIES = VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_TRANSFORM_PROPERTIES = VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_KEYFRAME_LIMITS = VIDEO_KEYFRAME_LIMITS; exports.isVideoKeyframes = isVideoKeyframes; exports.videoEaseBezier = videoEaseBezier; exports.videoEaseProgress = videoEaseProgress; exports.videoValueAt = videoValueAt; exports.videoKeysOf = videoKeysOf; exports.retimeVideoAnimatable = retimeVideoAnimatable; exports.splitVideoAnimatable = splitVideoAnimatable; exports.sortVideoKeys = sortVideoKeys; exports.setVideoKey = setVideoKey; exports.removeVideoKey = removeVideoKey; exports.videoKeyframeBreakpoints = videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = videoKeyframeFfmpegExpr; exports.VIDEO_LUT_MAX_SIZE = VIDEO_LUT_MAX_SIZE; exports.parseVideoCubeLut = parseVideoCubeLut; exports.videoLutFromFunction = videoLutFromFunction; exports.videoLutToCube = videoLutToCube; exports.applyVideoLut = applyVideoLut; exports.applyVideoLutToPixels = applyVideoLutToPixels; exports.videoLutSvgApproximation = videoLutSvgApproximation; exports.VideoLutCache = VideoLutCache; exports.VIDEO_GRADE_CONTROLS = VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = VIDEO_GRADE_PRESET_NAMES; exports.normalizeVideoGradeLut = normalizeVideoGradeLut; exports.normalizeVideoGrade = normalizeVideoGrade; exports.videoGradePreset = videoGradePreset; exports.videoGradeLook = videoGradeLook; exports.videoGradeSteps = videoGradeSteps; exports.videoGradeStepMatrix = videoGradeStepMatrix; exports.applyVideoGrade = applyVideoGrade; exports.videoGradeStepSvgValues = videoGradeStepSvgValues; exports.videoLutSvgPrimitives = videoLutSvgPrimitives; exports.videoGradeSvgFilter = videoGradeSvgFilter; exports.videoGradeGainsFilterId = videoGradeGainsFilterId; exports.videoGradeCssFilter = videoGradeCssFilter; exports.videoGradeSvgDefs = videoGradeSvgDefs; exports.videoGradeFfmpegFilters = videoGradeFfmpegFilters; exports.videoClipSourceTime = videoClipSourceTime; exports.videoClipSpeedAt = videoClipSpeedAt; exports.videoSpeedRampKeys = videoSpeedRampKeys; exports.checkVideoTimeRemap = checkVideoTimeRemap; exports.videoTimeRemapSpan = videoTimeRemapSpan; exports.videoTimeRemapBreakpoints = videoTimeRemapBreakpoints; exports.videoSpeedRampEdit = videoSpeedRampEdit; exports.videoFreezeFrameEdit = videoFreezeFrameEdit; exports.videoSlowMotionRamp = videoSlowMotionRamp; exports.VIDEO_TIME_EPSILON = VIDEO_TIME_EPSILON; exports.videoClipEnd = videoClipEnd; exports.videoTrackSyncLocked = videoTrackSyncLocked; exports.videoClipSpeed = videoClipSpeed; exports.videoClipSourceRange = videoClipSourceRange; exports.videoFrameDuration = videoFrameDuration; exports.snapToVideoFrame = snapToVideoFrame; exports.videoFrames = videoFrames; exports.isVideoDropFrameRate = isVideoDropFrameRate; exports.videoTimecodeFrames = videoTimecodeFrames; exports.formatVideoTimecode = formatVideoTimecode; exports.formatVideoTimecodeFrames = formatVideoTimecodeFrames; exports.videoHourFrames = videoHourFrames; exports.formatVideoSeconds = formatVideoSeconds; exports.videoAssetHasSound = videoAssetHasSound; exports.videoAssetMap = videoAssetMap; exports.videoSequenceMap = videoSequenceMap; exports.videoSequenceDuration = videoSequenceDuration; exports.videoSequenceChildren = videoSequenceChildren; exports.findVideoSequenceCycle = findVideoSequenceCycle; exports.allVideoTracks = allVideoTracks; exports.sortedVideoClips = sortedVideoClips; exports.findVideoClip = findVideoClip; exports.allVideoClipIds = allVideoClipIds; exports.findVideoSequenceClip = findVideoSequenceClip; exports.videoProjectDuration = videoProjectDuration; exports.videoClipBefore = videoClipBefore; exports.videoClipAfter = videoClipAfter; exports.videoClipHandles = videoClipHandles; exports.videoClipOverhang = videoClipOverhang; exports.videoSnapPoints = videoSnapPoints; exports.snapVideoTime = snapVideoTime; exports.findVideoGaps = findVideoGaps; exports.videoOverlap = videoOverlap; exports.nextFreeVideoSlot = nextFreeVideoSlot; exports.videoClipsAt = videoClipsAt; exports.VIDEO_CLIP_ANIMATION_DURATION = VIDEO_CLIP_ANIMATION_DURATION; exports.videoClipAnimationProperties = videoClipAnimationProperties; exports.videoClipAnimationSpans = videoClipAnimationSpans; exports.videoClipAnimated = videoClipAnimated; exports.videoTransformAt = videoTransformAt; exports.placeVideoRect = placeVideoRect; exports.videoTextStyle = videoTextStyle; exports.videoTitleFrame = videoTitleFrame; exports.videoTransitionEase = videoTransitionEase; exports.videoFadeCurveGain = videoFadeCurveGain; exports.videoClipSoundGain = videoClipSoundGain; exports.videoFrameAt = videoFrameAt; exports.videoFrameLeafLayers = videoFrameLeafLayers; exports.videoIrisRadius = videoIrisRadius; exports.videoWipeRect = videoWipeRect; exports.videoFrameToSvg = videoFrameToSvg; exports.videoProjectSvg = videoProjectSvg; exports.videoContactSheetSvg = videoContactSheetSvg; exports.drawVideoFrame = drawVideoFrame; exports.toVideoEdl = toVideoEdl; exports.parseVideoLoudnessMeasurement = parseVideoLoudnessMeasurement; exports.ffmpegFilterValue = ffmpegFilterValue; exports.videoShellQuote = videoShellQuote; exports.toVideoFfmpeg = toVideoFfmpeg; exports.toVideoLoudnessMeasure = toVideoLoudnessMeasure;
1908
- //# sourceMappingURL=chunk-SMJGE7HM.cjs.map
2365
+
2366
+
2367
+
2368
+
2369
+
2370
+
2371
+
2372
+
2373
+
2374
+
2375
+
2376
+
2377
+
2378
+
2379
+
2380
+ exports.VIDEO_FITS = VIDEO_FITS; exports.VIDEO_TRANSITION_TYPES = VIDEO_TRANSITION_TYPES; exports.VIDEO_WIPE_DIRECTIONS = VIDEO_WIPE_DIRECTIONS; exports.videoTransitionAudioCurve = videoTransitionAudioCurve; exports.VIDEO_BLEND_MODES = VIDEO_BLEND_MODES; exports.VIDEO_CLIP_ANIMATION_EFFECTS = VIDEO_CLIP_ANIMATION_EFFECTS; exports.VIDEO_FADE_CURVES = VIDEO_FADE_CURVES; exports.VIDEO_PLACEMENT_MODES = VIDEO_PLACEMENT_MODES; exports.VIDEO_CLIP_TYPES = VIDEO_CLIP_TYPES; exports.VIDEO_EASE_NAMES = VIDEO_EASE_NAMES; exports.VIDEO_KEYFRAME_PROPERTIES = VIDEO_KEYFRAME_PROPERTIES; exports.VIDEO_TRANSFORM_PROPERTIES = VIDEO_TRANSFORM_PROPERTIES; exports.VIDEO_KEYFRAME_LIMITS = VIDEO_KEYFRAME_LIMITS; exports.isVideoKeyframes = isVideoKeyframes; exports.videoEaseBezier = videoEaseBezier; exports.videoEaseProgress = videoEaseProgress; exports.videoValueAt = videoValueAt; exports.videoKeysOf = videoKeysOf; exports.retimeVideoAnimatable = retimeVideoAnimatable; exports.splitVideoAnimatable = splitVideoAnimatable; exports.sortVideoKeys = sortVideoKeys; exports.setVideoKey = setVideoKey; exports.removeVideoKey = removeVideoKey; exports.videoKeyframeBreakpoints = videoKeyframeBreakpoints; exports.videoKeyframeFfmpegExpr = videoKeyframeFfmpegExpr; exports.VIDEO_LUT_MAX_SIZE = VIDEO_LUT_MAX_SIZE; exports.parseVideoCubeLut = parseVideoCubeLut; exports.videoLutFromFunction = videoLutFromFunction; exports.videoLutToCube = videoLutToCube; exports.applyVideoLut = applyVideoLut; exports.applyVideoLutToPixels = applyVideoLutToPixels; exports.videoLutSvgApproximation = videoLutSvgApproximation; exports.VideoLutCache = VideoLutCache; exports.VIDEO_GRADE_CONTROLS = VIDEO_GRADE_CONTROLS; exports.VIDEO_GRADE_PRESETS = VIDEO_GRADE_PRESETS; exports.VIDEO_GRADE_PRESET_NAMES = VIDEO_GRADE_PRESET_NAMES; exports.normalizeVideoGradeLut = normalizeVideoGradeLut; exports.normalizeVideoGrade = normalizeVideoGrade; exports.videoGradePreset = videoGradePreset; exports.videoGradeLook = videoGradeLook; exports.videoGradeSteps = videoGradeSteps; exports.videoGradeStepMatrix = videoGradeStepMatrix; exports.applyVideoGrade = applyVideoGrade; exports.videoGradeStepSvgValues = videoGradeStepSvgValues; exports.videoLutSvgPrimitives = videoLutSvgPrimitives; exports.videoGradeSvgFilter = videoGradeSvgFilter; exports.videoGradeGainsFilterId = videoGradeGainsFilterId; exports.videoGradeCssFilter = videoGradeCssFilter; exports.videoGradeSvgDefs = videoGradeSvgDefs; exports.videoGradeFfmpegFilters = videoGradeFfmpegFilters; exports.videoClipSourceTime = videoClipSourceTime; exports.videoClipSpeedAt = videoClipSpeedAt; exports.videoSpeedRampKeys = videoSpeedRampKeys; exports.checkVideoTimeRemap = checkVideoTimeRemap; exports.videoTimeRemapSpan = videoTimeRemapSpan; exports.videoTimeRemapBreakpoints = videoTimeRemapBreakpoints; exports.videoSpeedRampEdit = videoSpeedRampEdit; exports.videoFreezeFrameEdit = videoFreezeFrameEdit; exports.videoSlowMotionRamp = videoSlowMotionRamp; exports.VIDEO_TIME_EPSILON = VIDEO_TIME_EPSILON; exports.videoClipEnd = videoClipEnd; exports.videoTrackSyncLocked = videoTrackSyncLocked; exports.videoClipSpeed = videoClipSpeed; exports.videoClipSourceRange = videoClipSourceRange; exports.videoFrameDuration = videoFrameDuration; exports.snapToVideoFrame = snapToVideoFrame; exports.videoFrames = videoFrames; exports.isVideoDropFrameRate = isVideoDropFrameRate; exports.videoTimecodeFrames = videoTimecodeFrames; exports.formatVideoTimecode = formatVideoTimecode; exports.formatVideoTimecodeFrames = formatVideoTimecodeFrames; exports.videoHourFrames = videoHourFrames; exports.formatVideoSeconds = formatVideoSeconds; exports.videoAssetHasSound = videoAssetHasSound; exports.videoAssetMap = videoAssetMap; exports.videoSequenceMap = videoSequenceMap; exports.videoSequenceDuration = videoSequenceDuration; exports.videoSequenceChildren = videoSequenceChildren; exports.findVideoSequenceCycle = findVideoSequenceCycle; exports.allVideoTracks = allVideoTracks; exports.sortedVideoClips = sortedVideoClips; exports.findVideoClip = findVideoClip; exports.allVideoClipIds = allVideoClipIds; exports.findVideoSequenceClip = findVideoSequenceClip; exports.videoProjectDuration = videoProjectDuration; exports.videoClipBefore = videoClipBefore; exports.videoClipAfter = videoClipAfter; exports.videoClipHandles = videoClipHandles; exports.videoClipOverhang = videoClipOverhang; exports.videoSnapPoints = videoSnapPoints; exports.snapVideoTime = snapVideoTime; exports.findVideoGaps = findVideoGaps; exports.videoOverlap = videoOverlap; exports.nextFreeVideoSlot = nextFreeVideoSlot; exports.videoClipsAt = videoClipsAt; exports.VIDEO_CLIP_ANIMATION_DURATION = VIDEO_CLIP_ANIMATION_DURATION; exports.videoClipAnimationProperties = videoClipAnimationProperties; exports.videoClipAnimationSpans = videoClipAnimationSpans; exports.videoClipAnimated = videoClipAnimated; exports.videoEffectValuesAt = videoEffectValuesAt; exports.videoTransformAt = videoTransformAt; exports.placeVideoRect = placeVideoRect; exports.videoTextStyle = videoTextStyle; exports.videoTitleFrame = videoTitleFrame; exports.videoTransitionEase = videoTransitionEase; exports.videoFadeCurveGain = videoFadeCurveGain; exports.videoClipSoundGain = videoClipSoundGain; exports.videoFrameAt = videoFrameAt; exports.videoLayersWithoutTransitionEffects = videoLayersWithoutTransitionEffects; exports.videoFrameLeafLayers = videoFrameLeafLayers; exports.videoProjectEffects = videoProjectEffects; exports.videoClipEffectUses = videoClipEffectUses; exports.videoLayersUseEffects = videoLayersUseEffects; exports.videoEffectFrameTime = videoEffectFrameTime; exports.videoEffectLayerKey = videoEffectLayerKey; exports.mixEffectPixels = mixEffectPixels; exports.overEffectPixels = overEffectPixels; exports.VideoEffectsEngine = VideoEffectsEngine; exports.VIDEO_EFFECT_PLACES = VIDEO_EFFECT_PLACES; exports.checkVideoEffectPlace = checkVideoEffectPlace; exports.checkVideoEffectValues = checkVideoEffectValues; exports.videoIrisRadius = videoIrisRadius; exports.videoWipeRect = videoWipeRect; exports.videoFrameToSvg = videoFrameToSvg; exports.videoProjectSvg = videoProjectSvg; exports.videoContactSheetSvg = videoContactSheetSvg; exports.drawVideoFrame = drawVideoFrame; exports.renderVideoFrameExact = renderVideoFrameExact; exports.toVideoEdl = toVideoEdl; exports.videoFfmpegUnsupportedEffects = videoFfmpegUnsupportedEffects; exports.parseVideoLoudnessMeasurement = parseVideoLoudnessMeasurement; exports.ffmpegFilterValue = ffmpegFilterValue; exports.videoShellQuote = videoShellQuote; exports.toVideoFfmpeg = toVideoFfmpeg; exports.toVideoLoudnessMeasure = toVideoLoudnessMeasure;
2381
+ //# sourceMappingURL=chunk-4QQZV5Y5.cjs.map