@pixerate/editor 0.76.0 → 0.78.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.
@@ -775,6 +775,13 @@ function placeVideoRect(frame, size, fit = "contain", transform = {}) {
775
775
  const cy = frame.height / 2 + (_nullishCoalesce(_optionalChain([transform, 'optionalAccess', _11 => _11.y]), () => ( 0)));
776
776
  return { x: cx - w / 2, y: cy - h / 2, width: w, height: h };
777
777
  }
778
+ function videoTextStyle(clip) {
779
+ return { text: clip.text, color: _nullishCoalesce(clip.color, () => ( "#ffffff")), fontSize: _nullishCoalesce(clip.fontSize, () => ( 64)), fontFamily: _nullishCoalesce(clip.fontFamily, () => ( "sans-serif")), fontWeight: _nullishCoalesce(clip.fontWeight, () => ( 700)), ...clip.background ? { background: clip.background } : {} };
780
+ }
781
+ function videoTitleFrame(project, clip) {
782
+ const layer = { clip: clip.id, track: "", type: "text", opacity: 1, rect: placeVideoRect(project, project, "fill", clip.transform), rotation: _nullishCoalesce(_optionalChain([clip, 'access', _12 => _12.transform, 'optionalAccess', _13 => _13.rotation]), () => ( 0)), text: videoTextStyle(clip) };
783
+ return { time: clip.start, width: project.width, height: project.height, background: "rgba(0,0,0,0)", layers: [layer], audio: [] };
784
+ }
778
785
  var clamp01 = (v) => Math.min(1, Math.max(0, v));
779
786
  function fadeGain(clip, time) {
780
787
  let g = 1;
@@ -788,7 +795,7 @@ function activeOnTrack(track, time) {
788
795
  const before = clip.transition ? videoClipBefore(track, clip) : null;
789
796
  const lead = before ? clip.transition.duration / 2 : 0;
790
797
  const next = videoClipAfter(track, clip);
791
- const tail = _optionalChain([next, 'optionalAccess', _12 => _12.transition]) ? next.transition.duration / 2 : 0;
798
+ const tail = _optionalChain([next, 'optionalAccess', _14 => _14.transition]) ? next.transition.duration / 2 : 0;
792
799
  if (time < clip.start - lead || time >= videoClipEnd(clip) + tail) continue;
793
800
  const a = { clip };
794
801
  if (lead && time < clip.start + lead) a.incoming = { progress: clamp01((time - (clip.start - lead)) / (2 * lead)), type: clip.transition.type, transition: clip.transition };
@@ -805,8 +812,8 @@ function videoFrameAt(project, time) {
805
812
  for (let ti = project.tracks.length - 1; ti >= 0; ti--) {
806
813
  const track = project.tracks[ti];
807
814
  for (const { clip, incoming, outgoing } of activeOnTrack(track, time)) {
808
- if (_optionalChain([incoming, 'optionalAccess', _13 => _13.type]) === "dip" && incoming.progress < 0.5) continue;
809
- if (_optionalChain([outgoing, 'optionalAccess', _14 => _14.type]) === "dip" && outgoing.progress >= 0.5) continue;
815
+ if (_optionalChain([incoming, 'optionalAccess', _15 => _15.type]) === "dip" && incoming.progress < 0.5) continue;
816
+ if (_optionalChain([outgoing, 'optionalAccess', _16 => _16.type]) === "dip" && outgoing.progress >= 0.5) continue;
810
817
  const fade = fadeGain(clip, Math.min(Math.max(time, clip.start), videoClipEnd(clip)));
811
818
  const level = (t, into) => t.type === "dip" ? Math.abs(1 - 2 * t.progress) : into ? t.progress : 1 - t.progress;
812
819
  const mix = (incoming ? level(incoming, true) : 1) * (outgoing ? level(outgoing, false) : 1);
@@ -827,14 +834,14 @@ function videoFrameAt(project, time) {
827
834
  else if (incoming.type === "wipe") wipe = { direction: _nullishCoalesce(incoming.transition.direction, () => ( "right")), progress: incoming.progress };
828
835
  else dip = { color: _nullishCoalesce(incoming.transition.color, () => ( "#000000")), opacity: (1 - incoming.progress) * 2 };
829
836
  }
830
- if (_optionalChain([outgoing, 'optionalAccess', _15 => _15.type]) === "dip") dip = { color: _nullishCoalesce(outgoing.next.transition.color, () => ( "#000000")), opacity: outgoing.progress * 2 };
837
+ if (_optionalChain([outgoing, 'optionalAccess', _17 => _17.type]) === "dip") dip = { color: _nullishCoalesce(outgoing.next.transition.color, () => ( "#000000")), opacity: outgoing.progress * 2 };
831
838
  const size = clip.type === "media" ? { width: _nullishCoalesce(asset.width, () => ( project.width)), height: _nullishCoalesce(asset.height, () => ( project.height)) } : { width: project.width, height: project.height };
832
839
  const fit = _nullishCoalesce(clip.fit, () => ( (clip.type === "media" ? "contain" : "fill")));
833
840
  const rect = clip.type === "text" ? placeVideoRect(project, size, "fill", clip.transform) : placeVideoRect(project, size, fit, clip.transform);
834
- const layer = { clip: clip.id, track: track.id, type: clip.type, opacity: clamp01(opacity), rect, rotation: _nullishCoalesce(_optionalChain([clip, 'access', _16 => _16.transform, 'optionalAccess', _17 => _17.rotation]), () => ( 0)) };
841
+ const layer = { clip: clip.id, track: track.id, type: clip.type, opacity: clamp01(opacity), rect, rotation: _nullishCoalesce(_optionalChain([clip, 'access', _18 => _18.transform, 'optionalAccess', _19 => _19.rotation]), () => ( 0)) };
835
842
  if (wipe) layer.wipe = wipe;
836
843
  if (clip.type === "media") Object.assign(layer, { asset: asset.id, assetKind: asset.kind, src: asset.src, sourceTime });
837
- if (clip.type === "text") layer.text = { text: clip.text, color: _nullishCoalesce(clip.color, () => ( "#ffffff")), fontSize: _nullishCoalesce(clip.fontSize, () => ( 64)), fontFamily: _nullishCoalesce(clip.fontFamily, () => ( "sans-serif")), fontWeight: _nullishCoalesce(clip.fontWeight, () => ( 700)), ...clip.background ? { background: clip.background } : {} };
844
+ if (clip.type === "text") layer.text = videoTextStyle(clip);
838
845
  if (clip.type === "color") layer.color = clip.color;
839
846
  if (layer.opacity > 0) layers.push(layer);
840
847
  if (dip && dip.opacity > 0) layers.push({ clip: `transition:${incoming ? clip.id : outgoing.next.id}`, track: track.id, type: "color", color: dip.color, opacity: clamp01(dip.opacity), rect: { x: 0, y: 0, width: project.width, height: project.height }, rotation: 0 });
@@ -976,7 +983,7 @@ function drawVideoFrame(ctx, frame, sourceFor, scale = 1) {
976
983
  }
977
984
 
978
985
  // src/video-editor/export.ts
979
- var reelName = (asset) => (_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _18 => _18.name]), () => ( _optionalChain([asset, 'optionalAccess', _19 => _19.id]))), () => ( "AX"))).replace(/\.[a-z0-9]+$/i, "").replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 8) || "AX";
986
+ var reelName = (asset) => (_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _20 => _20.name]), () => ( _optionalChain([asset, 'optionalAccess', _21 => _21.id]))), () => ( "AX"))).replace(/\.[a-z0-9]+$/i, "").replace(/[^A-Za-z0-9]/g, "").toUpperCase().slice(0, 8) || "AX";
980
987
  function toVideoEdl(project, options = {}) {
981
988
  const track = options.track !== void 0 ? project.tracks.find((t) => t.id === options.track) : [...project.tracks].reverse().find((t) => t.kind === "video");
982
989
  if (!track) throw new Error(options.track !== void 0 ? `There is no track "${options.track}".` : "The project has no video track.");
@@ -1009,7 +1016,7 @@ function toVideoEdl(project, options = {}) {
1009
1016
  lines.push(row(n2, reel, `${t.type === "wipe" ? "W001" : "D"} ${frames}`, sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
1010
1017
  } else lines.push(row(n2, reel, "C", sourceAt(clip, recIn), sourceAt(clip, recOut), recIn, recOut));
1011
1018
  if (clip.type === "media" && videoClipSpeed(clip) !== 1) lines.push(`M2 ${reel.padEnd(8)} ${(videoClipSpeed(clip) * fps).toFixed(1).padStart(6)} ${tc(sourceAt(clip, recIn))}`);
1012
- if (clip.type === "media") lines.push(`* FROM CLIP NAME: ${_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _20 => _20.name]), () => ( _optionalChain([asset, 'optionalAccess', _21 => _21.src]))), () => ( clip.asset))}`);
1019
+ if (clip.type === "media") lines.push(`* FROM CLIP NAME: ${_nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _22 => _22.name]), () => ( _optionalChain([asset, 'optionalAccess', _23 => _23.src]))), () => ( clip.asset))}`);
1013
1020
  if (clip.type === "text") lines.push(`* TITLE: ${clip.text.replace(/\n/g, " ")}`);
1014
1021
  if (clip.type === "color") lines.push(`* COLOR: ${clip.color}`);
1015
1022
  lines.push("");
@@ -1052,6 +1059,7 @@ function toVideoFfmpeg(project, options = {}) {
1052
1059
  const graph = [`color=c=${color(_nullishCoalesce(project.background, () => ( "#000000")))}:s=${W}x${H}:r=${fps}:d=${sec(D)},format=yuva420p[base]`];
1053
1060
  const audio = [];
1054
1061
  let cur = "base";
1062
+ let usesDrawtext = false;
1055
1063
  let k = 0;
1056
1064
  const input = (clip, asset, lead, tail) => {
1057
1065
  const speed = videoClipSpeed(clip);
@@ -1083,7 +1091,7 @@ function toVideoFfmpeg(project, options = {}) {
1083
1091
  if (lead) chain2.push(`afade=t=in:st=0:d=${sec(2 * lead)}`);
1084
1092
  if (tail) chain2.push(`afade=t=out:st=${sec(span - 2 * tail)}:d=${sec(2 * tail)}`);
1085
1093
  if (before2 && clip.transition.type === "dip") chain2.push(`afade=t=in:st=0:d=${sec(clip.transition.duration / 2)}`);
1086
- const after = sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && _optionalChain([c, 'access', _22 => _22.transition, 'optionalAccess', _23 => _23.type]) === "dip");
1094
+ const after = sortedVideoClips(track).find((c) => c !== clip && Math.abs(c.start - end) < 0.5 && _optionalChain([c, 'access', _24 => _24.transition, 'optionalAccess', _25 => _25.type]) === "dip");
1087
1095
  if (after) chain2.push(`afade=t=out:st=${sec(span - after.transition.duration / 2)}:d=${sec(after.transition.duration / 2)}`);
1088
1096
  if (clip.fadeIn) chain2.push(`afade=t=in:st=${sec(lead)}:d=${sec(clip.fadeIn)}`);
1089
1097
  if (clip.fadeOut) chain2.push(`afade=t=out:st=${sec(lead + clip.duration - clip.fadeOut)}:d=${sec(clip.fadeOut)}`);
@@ -1094,15 +1102,19 @@ function toVideoFfmpeg(project, options = {}) {
1094
1102
  if (track.kind !== "video" || track.hidden) continue;
1095
1103
  const enable = `enable='between(t,${sec(t0)},${sec(t0 + span)})'`;
1096
1104
  const next = `v${k++}`;
1097
- if (clip.type === "text") {
1105
+ if (clip.type === "text" && options.titleImage) {
1106
+ inputs.push(["-loop", "1", "-framerate", String(fps), "-t", sec(span), "-i", options.titleImage(clip, { width: project.width, height: project.height })]);
1107
+ index = inputs.length - 1;
1108
+ } else if (clip.type === "text") {
1109
+ usesDrawtext = true;
1098
1110
  const op = _nullishCoalesce(clip.opacity, () => ( 1));
1099
1111
  const alpha = [String(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("*");
1100
- const x = _nullishCoalesce(_optionalChain([clip, 'access', _24 => _24.transform, 'optionalAccess', _25 => _25.x]), () => ( 0));
1101
- const y = _nullishCoalesce(_optionalChain([clip, 'access', _26 => _26.transform, 'optionalAccess', _27 => _27.y]), () => ( 0));
1112
+ const x = _nullishCoalesce(_optionalChain([clip, 'access', _26 => _26.transform, 'optionalAccess', _27 => _27.x]), () => ( 0));
1113
+ const y = _nullishCoalesce(_optionalChain([clip, 'access', _28 => _28.transform, 'optionalAccess', _29 => _29.y]), () => ( 0));
1102
1114
  const opts = [
1103
1115
  `text=${ffmpegFilterValue(clip.text)}`,
1104
1116
  options.fontFile ? `fontfile=${ffmpegFilterValue(options.fontFile)}` : `font=${ffmpegFilterValue(_nullishCoalesce(clip.fontFamily, () => ( "sans-serif")))}`,
1105
- `fontsize=${Math.round((_nullishCoalesce(clip.fontSize, () => ( 64))) * (_nullishCoalesce(_optionalChain([clip, 'access', _28 => _28.transform, 'optionalAccess', _29 => _29.scale]), () => ( 1))))}`,
1117
+ `fontsize=${Math.round((_nullishCoalesce(clip.fontSize, () => ( 64))) * (_nullishCoalesce(_optionalChain([clip, 'access', _30 => _30.transform, 'optionalAccess', _31 => _31.scale]), () => ( 1))))}`,
1106
1118
  `fontcolor=${color(_nullishCoalesce(clip.color, () => ( "#ffffff")))}`,
1107
1119
  `x=(w-text_w)/2+${x}`,
1108
1120
  `y=(h-text_h)/2+${y}`,
@@ -1110,13 +1122,13 @@ function toVideoFfmpeg(project, options = {}) {
1110
1122
  ...clip.background ? ["box=1", `boxcolor=${color(clip.background)}`, `boxborderw=${Math.round((_nullishCoalesce(clip.fontSize, () => ( 64))) / 2)}`] : [],
1111
1123
  `enable='between(t,${sec(clip.start)},${sec(end)})'`
1112
1124
  ];
1113
- if (_optionalChain([clip, 'access', _30 => _30.transform, 'optionalAccess', _31 => _31.rotation])) notes.push(`Title "${clip.id}" is drawn without its rotation (drawtext cannot rotate).`);
1125
+ if (_optionalChain([clip, 'access', _32 => _32.transform, 'optionalAccess', _33 => _33.rotation])) notes.push(`Title "${clip.id}" is drawn without its rotation (drawtext cannot rotate).`);
1114
1126
  graph.push(`[${cur}]drawtext=${opts.join(":")}[${next}]`);
1115
1127
  cur = next;
1116
1128
  continue;
1117
1129
  }
1118
1130
  const size = asset ? { width: _nullishCoalesce(asset.width, () => ( project.width)), height: _nullishCoalesce(asset.height, () => ( project.height)) } : { width: project.width, height: project.height };
1119
- const rect = placeVideoRect(project, size, _nullishCoalesce(clip.fit, () => ( (clip.type === "media" ? "contain" : "fill"))), clip.transform);
1131
+ const rect = clip.type === "text" ? { x: 0, y: 0, width: project.width, height: project.height } : placeVideoRect(project, size, _nullishCoalesce(clip.fit, () => ( (clip.type === "media" ? "contain" : "fill"))), clip.transform);
1120
1132
  const chain = [];
1121
1133
  let source;
1122
1134
  if (clip.type === "color") source = `color=c=${color(clip.color)}:s=${even(rect.width)}x${even(rect.height)}:r=${fps}:d=${sec(span)}`;
@@ -1136,7 +1148,7 @@ function toVideoFfmpeg(project, options = {}) {
1136
1148
  const test = dir === "right" ? `lt(X,W*${p})` : dir === "left" ? `gt(X,W*(1-${p}))` : dir === "down" ? `lt(Y,H*${p})` : `gt(Y,H*(1-${p}))`;
1137
1149
  chain.push(`geq=lum='lum(X,Y)':cb='cb(X,Y)':cr='cr(X,Y)':a='if(${test},alpha(X,Y),0)'`);
1138
1150
  }
1139
- if (_optionalChain([clip, 'access', _32 => _32.transform, 'optionalAccess', _33 => _33.rotation])) chain.push(`rotate=${clip.transform.rotation}*PI/180:c=none:ow=rotw(${clip.transform.rotation}*PI/180):oh=roth(${clip.transform.rotation}*PI/180)`);
1151
+ if (_optionalChain([clip, 'access', _34 => _34.transform, 'optionalAccess', _35 => _35.rotation]) && clip.type !== "text") chain.push(`rotate=${clip.transform.rotation}*PI/180:c=none:ow=rotw(${clip.transform.rotation}*PI/180):oh=roth(${clip.transform.rotation}*PI/180)`);
1140
1152
  chain.push(`setpts=PTS+${sec(t0)}/TB`);
1141
1153
  const cx = rect.x + rect.width / 2;
1142
1154
  const cy = rect.y + rect.height / 2;
@@ -1155,8 +1167,9 @@ function toVideoFfmpeg(project, options = {}) {
1155
1167
  }
1156
1168
  graph.push(`[${cur}]format=yuv420p[vout]`);
1157
1169
  if (audio.length) graph.push(`${audio.join("")}amix=inputs=${audio.length}:normalize=0:duration=longest,apad,atrim=0:${sec(D)}[aout]`);
1158
- if (project.tracks.some((t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _34 => _34.get, 'call', _35 => _35(c.asset), 'optionalAccess', _36 => _36.kind]) === "video" && _optionalChain([assets, 'access', _37 => _37.get, 'call', _38 => _38(c.asset), 'optionalAccess', _39 => _39.hasAudio]) === void 0)))
1170
+ if (project.tracks.some((t) => t.clips.some((c) => c.type === "media" && _optionalChain([assets, 'access', _36 => _36.get, 'call', _37 => _37(c.asset), 'optionalAccess', _38 => _38.kind]) === "video" && _optionalChain([assets, 'access', _39 => _39.get, 'call', _40 => _40(c.asset), 'optionalAccess', _41 => _41.hasAudio]) === void 0)))
1159
1171
  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.');
1172
+ if (usesDrawtext) notes.push("Titles use drawtext, which needs an ffmpeg built with libfreetype (Homebrew's is not: check `ffmpeg -filters | grep drawtext`); pass titleImage to render them as images instead.");
1160
1173
  const filterComplex = graph.join(";");
1161
1174
  const args = [
1162
1175
  "-y",
@@ -1186,7 +1199,7 @@ var VideoPreviewEngine = (_class2 = class {
1186
1199
  this.source = source;
1187
1200
  this.options = options;
1188
1201
  this.canvas = canvas;
1189
- this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas, 'access', _40 => _40.getContext, 'optionalCall', _41 => _41("2d")]), () => ( null));
1202
+ this.ctx = options.context !== void 0 ? options.context : _nullishCoalesce(_optionalChain([canvas, 'access', _42 => _42.getContext, 'optionalCall', _43 => _43("2d")]), () => ( null));
1190
1203
  this.unsubscribe = source.subscribe(() => this.update());
1191
1204
  this.update();
1192
1205
  }
@@ -1234,8 +1247,8 @@ var VideoPreviewEngine = (_class2 = class {
1234
1247
  entry.media.pause();
1235
1248
  entry.media.removeEventListener("seeked", entry.onReady);
1236
1249
  entry.media.removeEventListener("loadeddata", entry.onReady);
1237
- _optionalChain([entry, 'access', _42 => _42.media, 'access', _43 => _43.removeAttribute, 'optionalCall', _44 => _44("src")]);
1238
- _optionalChain([entry, 'access', _45 => _45.media, 'access', _46 => _46.load, 'optionalCall', _47 => _47()]);
1250
+ _optionalChain([entry, 'access', _44 => _44.media, 'access', _45 => _45.removeAttribute, 'optionalCall', _46 => _46("src")]);
1251
+ _optionalChain([entry, 'access', _47 => _47.media, 'access', _48 => _48.load, 'optionalCall', _49 => _49()]);
1239
1252
  this.media.delete(entry.clip);
1240
1253
  }
1241
1254
  /** Brings the media elements in step with the editor and draws the frame. */
@@ -1268,7 +1281,7 @@ var VideoPreviewEngine = (_class2 = class {
1268
1281
  for (const layer of frame.layers) {
1269
1282
  if (layer.type !== "media" || layer.assetKind !== "video" || !layer.src) continue;
1270
1283
  const sound = sounding.get(layer.clip);
1271
- sync(layer.clip, layer.src, "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _48 => _48.speed]), () => ( 1)), sound ? sound.gain : null);
1284
+ sync(layer.clip, layer.src, "video", _nullishCoalesce(layer.sourceTime, () => ( 0)), _nullishCoalesce(_optionalChain([sound, 'optionalAccess', _50 => _50.speed]), () => ( 1)), sound ? sound.gain : null);
1272
1285
  sounding.delete(layer.clip);
1273
1286
  }
1274
1287
  for (const a of sounding.values()) sync(a.clip, a.src, "audio", a.sourceTime, a.speed, a.gain);
@@ -1301,7 +1314,7 @@ var VideoPreviewEngine = (_class2 = class {
1301
1314
  if (this.canvas.width !== w) this.canvas.width = w;
1302
1315
  if (this.canvas.height !== h) this.canvas.height = h;
1303
1316
  drawVideoFrame(this.ctx, frame, this.sourceFor, resolution);
1304
- _optionalChain([this, 'access', _49 => _49.options, 'access', _50 => _50.onFrame, 'optionalCall', _51 => _51(frame)]);
1317
+ _optionalChain([this, 'access', _51 => _51.options, 'access', _52 => _52.onFrame, 'optionalCall', _53 => _53(frame)]);
1305
1318
  }
1306
1319
  /** Stops following the editor and releases every media element. */
1307
1320
  destroy() {
@@ -1408,7 +1421,7 @@ var VideoEditorController = (_class3 = class {
1408
1421
  this.applying = false;
1409
1422
  }
1410
1423
  this.notify();
1411
- _optionalChain([this, 'access', _52 => _52.onChange, 'optionalCall', _53 => _53(project)]);
1424
+ _optionalChain([this, 'access', _54 => _54.onChange, 'optionalCall', _55 => _55(project)]);
1412
1425
  }
1413
1426
  commit(label, next) {
1414
1427
  const before = this.project;
@@ -1472,7 +1485,7 @@ var VideoEditorController = (_class3 = class {
1472
1485
  }
1473
1486
  /** Selects clips (unknown ids are dropped). `add` toggles them into the current selection. */
1474
1487
  select(clips, options = {}) {
1475
- const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _54 => _54.filter, 'call', _55 => _55((id) => findVideoClip(this.project, id))]), () => ( []));
1488
+ const known = _nullishCoalesce(_optionalChain([clips, 'optionalAccess', _56 => _56.filter, 'call', _57 => _57((id) => findVideoClip(this.project, id))]), () => ( []));
1476
1489
  let next;
1477
1490
  if (options.add) {
1478
1491
  next = [...this.selection];
@@ -2069,7 +2082,7 @@ function videoClipLabel(clip, asset) {
2069
2082
  if (clip.name) return clip.name;
2070
2083
  if (clip.type === "text") return clip.text.split("\n")[0];
2071
2084
  if (clip.type === "color") return clip.color;
2072
- const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _56 => _56.name]), () => ( _optionalChain([asset, 'optionalAccess', _57 => _57.src, 'access', _58 => _58.replace, 'call', _59 => _59(/^.*[\\/]/, "")]))), () => ( clip.asset));
2085
+ const base = _nullishCoalesce(_nullishCoalesce(_optionalChain([asset, 'optionalAccess', _58 => _58.name]), () => ( _optionalChain([asset, 'optionalAccess', _59 => _59.src, 'access', _60 => _60.replace, 'call', _61 => _61(/^.*[\\/]/, "")]))), () => ( clip.asset));
2073
2086
  const speed = videoClipSpeed(clip);
2074
2087
  return speed !== 1 ? `${base} (${Math.round(speed * 100)}%)` : base;
2075
2088
  }
@@ -2108,7 +2121,7 @@ function videoAssetDropEdit(project, assetId, options = {}) {
2108
2121
  const asset = videoAssetMap(project).get(assetId);
2109
2122
  if (!asset) return null;
2110
2123
  const kind = asset.kind === "audio" ? "audio" : "video";
2111
- const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _60 => _60.tracks, 'access', _61 => _61.find, 'call', _62 => _62((t) => t.kind === kind && !t.locked), 'optionalAccess', _63 => _63.id])));
2124
+ const track = _nullishCoalesce(options.track, () => ( _optionalChain([project, 'access', _62 => _62.tracks, 'access', _63 => _63.find, 'call', _64 => _64((t) => t.kind === kind && !t.locked), 'optionalAccess', _65 => _65.id])));
2112
2125
  if (!track) return null;
2113
2126
  return { op: "add_clip", track, clip: { type: "media", asset: asset.id, ...options.start !== void 0 ? { start: options.start } : {} }, ...options.ripple ? { ripple: true } : {} };
2114
2127
  }
@@ -2215,5 +2228,7 @@ function probeVideoMedia(src, kind, timeout = 15e3) {
2215
2228
 
2216
2229
 
2217
2230
 
2218
- exports.VIDEO_CLIP_TYPES = VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_FITS = VIDEO_FITS; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_TIME_EPSILON = VIDEO_TIME_EPSILON; exports.VIDEO_TRANSITION_TYPES = VIDEO_TRANSITION_TYPES; exports.VIDEO_WIPE_DIRECTIONS = VIDEO_WIPE_DIRECTIONS; exports.VideoEditorController = VideoEditorController; exports.VideoPreviewEngine = VideoPreviewEngine; exports.allVideoClipIds = allVideoClipIds; exports.applyVideoEdits = applyVideoEdits; exports.checkVideoProject = checkVideoProject; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoProject = createVideoProject; exports.describeVideoProject = describeVideoProject; exports.drawVideoFrame = drawVideoFrame; exports.ffmpegFilterValue = ffmpegFilterValue; exports.findVideoClip = findVideoClip; exports.findVideoGaps = findVideoGaps; exports.formatVideoSeconds = formatVideoSeconds; exports.formatVideoTimecode = formatVideoTimecode; exports.nextFreeVideoSlot = nextFreeVideoSlot; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoClip = parseVideoClip; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoProject = parseVideoProject; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.probeVideoMedia = probeVideoMedia; exports.snapToVideoFrame = snapToVideoFrame; exports.snapVideoTime = snapVideoTime; exports.sortedVideoClips = sortedVideoClips; exports.toVideoEdl = toVideoEdl; exports.toVideoFfmpeg = toVideoFfmpeg; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = videoAssetMap; exports.videoClipAfter = videoClipAfter; exports.videoClipBefore = videoClipBefore; exports.videoClipEnd = videoClipEnd; exports.videoClipHandles = videoClipHandles; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = videoClipOverhang; exports.videoClipSourceRange = videoClipSourceRange; exports.videoClipSpeed = videoClipSpeed; exports.videoClipTint = videoClipTint; exports.videoClipsAt = videoClipsAt; exports.videoContactSheetSvg = videoContactSheetSvg; exports.videoDropTracks = videoDropTracks; exports.videoFrameAt = videoFrameAt; exports.videoFrameDuration = videoFrameDuration; exports.videoFrameToSvg = videoFrameToSvg; exports.videoFrames = videoFrames; exports.videoIssueKey = videoIssueKey; exports.videoOverlap = videoOverlap; exports.videoProjectDuration = videoProjectDuration; exports.videoProjectSvg = videoProjectSvg; exports.videoRulerTicks = videoRulerTicks; exports.videoSnapPoints = videoSnapPoints; exports.videoWipeRect = videoWipeRect;
2231
+
2232
+
2233
+ exports.VIDEO_CLIP_TYPES = VIDEO_CLIP_TYPES; exports.VIDEO_DEFAULT_STILL_DURATION = VIDEO_DEFAULT_STILL_DURATION; exports.VIDEO_DEFAULT_TITLE_DURATION = VIDEO_DEFAULT_TITLE_DURATION; exports.VIDEO_EDIT_OPS = VIDEO_EDIT_OPS; exports.VIDEO_FITS = VIDEO_FITS; exports.VIDEO_ISSUE_CODES = VIDEO_ISSUE_CODES; exports.VIDEO_TIME_EPSILON = VIDEO_TIME_EPSILON; exports.VIDEO_TRANSITION_TYPES = VIDEO_TRANSITION_TYPES; exports.VIDEO_WIPE_DIRECTIONS = VIDEO_WIPE_DIRECTIONS; exports.VideoEditorController = VideoEditorController; exports.VideoPreviewEngine = VideoPreviewEngine; exports.allVideoClipIds = allVideoClipIds; exports.applyVideoEdits = applyVideoEdits; exports.checkVideoProject = checkVideoProject; exports.createVideoEditorToolProvider = createVideoEditorToolProvider; exports.createVideoProject = createVideoProject; exports.describeVideoProject = describeVideoProject; exports.drawVideoFrame = drawVideoFrame; exports.ffmpegFilterValue = ffmpegFilterValue; exports.findVideoClip = findVideoClip; exports.findVideoGaps = findVideoGaps; exports.formatVideoSeconds = formatVideoSeconds; exports.formatVideoTimecode = formatVideoTimecode; exports.nextFreeVideoSlot = nextFreeVideoSlot; exports.parseVideoAsset = parseVideoAsset; exports.parseVideoClip = parseVideoClip; exports.parseVideoMarker = parseVideoMarker; exports.parseVideoProject = parseVideoProject; exports.parseVideoTrack = parseVideoTrack; exports.parseVideoTransform = parseVideoTransform; exports.parseVideoTransition = parseVideoTransition; exports.placeVideoRect = placeVideoRect; exports.planVideoClipDrag = planVideoClipDrag; exports.probeVideoMedia = probeVideoMedia; exports.snapToVideoFrame = snapToVideoFrame; exports.snapVideoTime = snapVideoTime; exports.sortedVideoClips = sortedVideoClips; exports.toVideoEdl = toVideoEdl; exports.toVideoFfmpeg = toVideoFfmpeg; exports.videoAssetDropEdit = videoAssetDropEdit; exports.videoAssetKindOf = videoAssetKindOf; exports.videoAssetMap = videoAssetMap; exports.videoClipAfter = videoClipAfter; exports.videoClipBefore = videoClipBefore; exports.videoClipEnd = videoClipEnd; exports.videoClipHandles = videoClipHandles; exports.videoClipLabel = videoClipLabel; exports.videoClipOverhang = videoClipOverhang; exports.videoClipSourceRange = videoClipSourceRange; exports.videoClipSpeed = videoClipSpeed; exports.videoClipTint = videoClipTint; exports.videoClipsAt = videoClipsAt; exports.videoContactSheetSvg = videoContactSheetSvg; exports.videoDropTracks = videoDropTracks; exports.videoFrameAt = videoFrameAt; exports.videoFrameDuration = videoFrameDuration; exports.videoFrameToSvg = videoFrameToSvg; exports.videoFrames = videoFrames; exports.videoIssueKey = videoIssueKey; exports.videoOverlap = videoOverlap; exports.videoProjectDuration = videoProjectDuration; exports.videoProjectSvg = videoProjectSvg; exports.videoRulerTicks = videoRulerTicks; exports.videoSnapPoints = videoSnapPoints; exports.videoTextStyle = videoTextStyle; exports.videoTitleFrame = videoTitleFrame; exports.videoWipeRect = videoWipeRect;
2219
2234
  //# sourceMappingURL=index.cjs.map