@pixerate/editor 0.83.0 → 0.85.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.
@@ -92,6 +92,12 @@ declare function videoKeyframeFfmpegExpr(prop: VideoAnimatable | undefined, time
92
92
  */
93
93
 
94
94
  type VideoAssetKind = 'video' | 'audio' | 'image';
95
+ /** A spoken word in an asset's transcript, timed in the source (ms). */
96
+ interface VideoTranscriptWord {
97
+ word: string;
98
+ start: number;
99
+ end: number;
100
+ }
95
101
  /** A piece of source media. The project refers to it by id; `src` is whatever the host can load. */
96
102
  interface VideoAsset {
97
103
  id: string;
@@ -108,6 +114,8 @@ interface VideoAsset {
108
114
  hasAudio?: boolean;
109
115
  /** A still to show for a video where its frames cannot be drawn (SVG renders, thumbnails). */
110
116
  poster?: string;
117
+ /** What is said in it, word by word, timed in the source (see `parseVideoTranscript`). */
118
+ transcript?: VideoTranscriptWord[];
111
119
  }
112
120
  type VideoTrackKind = 'video' | 'audio';
113
121
  interface VideoTrack {
@@ -142,8 +150,16 @@ interface VideoTransform {
142
150
  /** How a picture is fitted to the frame before its transform: like CSS `object-fit`. */
143
151
  type VideoFit = 'contain' | 'cover' | 'fill' | 'none';
144
152
  declare const VIDEO_FITS: readonly ["contain", "cover", "fill", "none"];
145
- type VideoTransitionType = 'crossfade' | 'dip' | 'wipe';
146
- declare const VIDEO_TRANSITION_TYPES: readonly ["crossfade", "dip", "wipe"];
153
+ /**
154
+ * - `crossfade`: this clip fades up over the one before.
155
+ * - `dip`: down into a colour and up out of it.
156
+ * - `wipe`: an edge travels across, revealing this clip.
157
+ * - `push`: this clip slides in, pushing the one before out.
158
+ * - `slide`: this clip slides in over the one before, which stays put.
159
+ * - `iris`: a circle opens from the centre, revealing this clip.
160
+ */
161
+ type VideoTransitionType = 'crossfade' | 'dip' | 'wipe' | 'push' | 'slide' | 'iris';
162
+ declare const VIDEO_TRANSITION_TYPES: readonly ["crossfade", "dip", "wipe", "push", "slide", "iris"];
147
163
  type VideoWipeDirection = 'left' | 'right' | 'up' | 'down';
148
164
  declare const VIDEO_WIPE_DIRECTIONS: readonly ["left", "right", "up", "down"];
149
165
  /**
@@ -157,8 +173,54 @@ interface VideoTransition {
157
173
  duration: number;
158
174
  /** For dip: the colour passed through (default black). */
159
175
  color?: string;
160
- /** For wipe: the way the edge travels (default right, revealing from the left). */
176
+ /** For wipe, push and slide: the way the edge or picture travels (default right: in from the left). */
161
177
  direction?: VideoWipeDirection;
178
+ /**
179
+ * Shape of the sound's fades through the transition (see `VideoFadeCurve`). Default
180
+ * `equal-power` for crossfades and wipes, where two sounds overlap and a linear mix dips in
181
+ * loudness halfway; `linear` for dips, where one sound fades out before the other fades in.
182
+ */
183
+ audioCurve?: VideoFadeCurve;
184
+ }
185
+ /** The curve a transition's sound fades follow (its `audioCurve`, else the default for its type). */
186
+ declare const videoTransitionAudioCurve: (t: VideoTransition) => VideoFadeCurve;
187
+ /**
188
+ * How a clip's picture mixes with what is beneath it, as in CSS `mix-blend-mode` (`add` sums the
189
+ * colours, `plus-lighter` in CSS). These are the modes the canvas preview, SVG frames and ffmpeg's
190
+ * `blend` filter all share.
191
+ */
192
+ type VideoBlendMode = 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'add';
193
+ declare const VIDEO_BLEND_MODES: readonly ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "add"];
194
+ /**
195
+ * Colour correction for a clip's picture (see `VIDEO_GRADE_CONTROLS` for ranges). Applied in a fixed
196
+ * order: exposure, contrast, saturation, hue, then white balance (temperature and tint).
197
+ */
198
+ interface VideoGrade {
199
+ /** Stops: +1 doubles every channel (default 0). */
200
+ exposure?: number;
201
+ /** -1 (flat grey) to 1 (twice as steep), around mid grey (default 0). */
202
+ contrast?: number;
203
+ /** -1 (black and white) to 1 (twice as saturated); default 0. */
204
+ saturation?: number;
205
+ /** Hue rotation in degrees (default 0). */
206
+ hue?: number;
207
+ /** -1 (cool) to 1 (warm); default 0. */
208
+ temperature?: number;
209
+ /** -1 (green) to 1 (magenta); default 0. */
210
+ tint?: number;
211
+ }
212
+ /**
213
+ * How a clip enters or leaves: `fade`; `rise` (up into place) or `drop` (down into place);
214
+ * `slide-left` / `slide-right` (in moving that way); `zoom` (grows into place); `pop` (grows past its
215
+ * size and settles). Each also fades. An exit plays the same movement backwards.
216
+ */
217
+ type VideoClipAnimationEffect = 'fade' | 'rise' | 'drop' | 'slide-left' | 'slide-right' | 'zoom' | 'pop';
218
+ declare const VIDEO_CLIP_ANIMATION_EFFECTS: readonly ["fade", "rise", "drop", "slide-left", "slide-right", "zoom", "pop"];
219
+ /** An entrance or exit animation (see `VideoClipAnimationEffect`). */
220
+ interface VideoClipAnimation {
221
+ effect: VideoClipAnimationEffect;
222
+ /** Length (ms, default 500). */
223
+ duration?: number;
162
224
  }
163
225
  interface VideoClipBase {
164
226
  id: string;
@@ -172,6 +234,14 @@ interface VideoClipBase {
172
234
  transform?: VideoTransform;
173
235
  /** Default contain. */
174
236
  fit?: VideoFit;
237
+ /** How the picture mixes with what is beneath it (default normal). */
238
+ blend?: VideoBlendMode;
239
+ /** Colour correction of the picture. */
240
+ grade?: VideoGrade;
241
+ /** How the picture enters, from the clip's start (on top of any fade in). */
242
+ animateIn?: VideoClipAnimation;
243
+ /** How the picture leaves, up to the clip's end. */
244
+ animateOut?: VideoClipAnimation;
175
245
  /** Fade in from nothing over this long (ms), pictures and sound. */
176
246
  fadeIn?: number;
177
247
  /** Fade out over this long (ms). */
@@ -274,7 +344,10 @@ declare function parseVideoAnimatable(v: unknown, path: string, range?: {
274
344
  optional?: boolean;
275
345
  }): VideoAnimatable | undefined;
276
346
  declare function parseVideoTransform(v: unknown, path: string): VideoTransform | undefined;
347
+ declare function parseVideoClipAnimation(v: unknown, path: string): VideoClipAnimation | undefined;
348
+ declare function parseVideoGrade(v: unknown, path: string): VideoGrade | undefined;
277
349
  declare function parseVideoTransition(v: unknown, path: string): VideoTransition | undefined;
350
+ declare function parseVideoTranscriptWords(v: unknown, path: string): VideoTranscriptWord[] | undefined;
278
351
  declare function parseVideoAsset(v: unknown, path?: string): VideoAsset;
279
352
  declare function parseVideoClip(v: unknown, path?: string): VideoClip;
280
353
  declare function parseVideoTrack(v: unknown, path?: string): VideoTrack;
@@ -410,7 +483,7 @@ declare function videoClipKeyframes(clip: VideoClip): {
410
483
  keys: ReturnType<typeof videoKeysOf>;
411
484
  }[];
412
485
  type VideoIssueSeverity = 'error' | 'warning' | 'note';
413
- declare const VIDEO_ISSUE_CODES: readonly ["missing-asset", "wrong-track", "overlap", "source-overrun", "transition-without-cut", "transition-too-long", "transition-handles", "fades-too-long", "keyframes-outside-clip", "unknown-duration", "unused-asset", "marker-past-end", "empty"];
486
+ declare const VIDEO_ISSUE_CODES: readonly ["missing-asset", "wrong-track", "overlap", "source-overrun", "transition-without-cut", "transition-too-long", "transition-handles", "fades-too-long", "animations-too-long", "animation-keyed", "keyframes-outside-clip", "unknown-duration", "unused-asset", "marker-past-end", "empty"];
414
487
  type VideoIssueCode = (typeof VIDEO_ISSUE_CODES)[number];
415
488
  interface VideoIssue {
416
489
  code: VideoIssueCode;
@@ -653,6 +726,10 @@ interface VideoLayer {
653
726
  direction: VideoWipeDirection;
654
727
  progress: number;
655
728
  };
729
+ /** For an iris: only a circle on the frame's centre shows, its radius `progress` (0–1) of the way to the frame's corners. */
730
+ iris?: {
731
+ progress: number;
732
+ };
656
733
  /** For text: what to draw. */
657
734
  text?: {
658
735
  text: string;
@@ -664,6 +741,10 @@ interface VideoLayer {
664
741
  };
665
742
  /** For colour clips and dips. */
666
743
  color?: string;
744
+ /** How it mixes with the layers beneath (absent = normal). */
745
+ blend?: VideoBlendMode;
746
+ /** Colour correction (absent = none). */
747
+ grade?: VideoGrade;
667
748
  }
668
749
  /** One sound playing at a moment. */
669
750
  interface VideoAudioSource {
@@ -710,6 +791,8 @@ declare function videoTextStyle(clip: VideoTextClip): NonNullable<VideoLayer['te
710
791
  * transforms without them, and moves the image itself).
711
792
  */
712
793
  declare function videoTitleFrame(project: VideoProject, clip: VideoTextClip, clipTime?: number): VideoFrame;
794
+ /** How far a push or slide has moved at `progress` (0–1): eased in and out, (1 − cos πp) / 2. */
795
+ declare const videoTransitionEase: (progress: number) => number;
713
796
  /** Gain of a fade shape `x` of the way up (0–1); a fade out uses the time left, so it mirrors the fade in. */
714
797
  declare function videoFadeCurveGain(curve: VideoFadeCurve | undefined, x: number): number;
715
798
  /**
@@ -828,6 +911,223 @@ declare class VideoAudioPeaksCache {
828
911
  private emit;
829
912
  }
830
913
 
914
+ /**
915
+ * Colour correction as a fixed series of colour-matrix steps on gamma-encoded sRGB, each clamped
916
+ * to 0–1, in the same order everywhere: exposure, contrast, saturation, hue, then white balance.
917
+ * Every step is one the browser has (CSS `brightness`, `contrast`, `saturate`, `hue-rotate`; white
918
+ * balance as an SVG `feColorMatrix`) and ffmpeg has (`lutrgb`, `colorchannelmixer`), with the same
919
+ * formulas, so the preview, SVG frames and the export agree.
920
+ */
921
+ /** One slider of a grade: its range, default and step, for schemas, inspectors and clamping. */
922
+ interface VideoGradeControl {
923
+ key: keyof VideoGrade;
924
+ label: string;
925
+ min: number;
926
+ max: number;
927
+ step: number;
928
+ /** What the number means, for tool descriptions. */
929
+ description: string;
930
+ }
931
+ declare const VIDEO_GRADE_CONTROLS: readonly VideoGradeControl[];
932
+ /** Named looks. Apply them at a strength with `videoGradePreset`. */
933
+ declare const VIDEO_GRADE_PRESETS: {
934
+ readonly warm: {
935
+ readonly temperature: 0.4;
936
+ readonly saturation: 0.1;
937
+ };
938
+ readonly cool: {
939
+ readonly temperature: -0.4;
940
+ readonly tint: -0.05;
941
+ };
942
+ readonly punchy: {
943
+ readonly contrast: 0.25;
944
+ readonly saturation: 0.3;
945
+ };
946
+ readonly faded: {
947
+ readonly exposure: 0.15;
948
+ readonly contrast: -0.3;
949
+ readonly saturation: -0.3;
950
+ };
951
+ readonly 'black-and-white': {
952
+ readonly saturation: -1;
953
+ readonly contrast: 0.15;
954
+ };
955
+ readonly 'bleach-bypass': {
956
+ readonly saturation: -0.6;
957
+ readonly contrast: 0.4;
958
+ };
959
+ readonly 'day-for-night': {
960
+ readonly exposure: -1.5;
961
+ readonly saturation: -0.4;
962
+ readonly temperature: -0.6;
963
+ };
964
+ };
965
+ type VideoGradePreset = keyof typeof VIDEO_GRADE_PRESETS;
966
+ declare const VIDEO_GRADE_PRESET_NAMES: VideoGradePreset[];
967
+ /** A grade with every value clamped to its range and zero values left out; `undefined` when nothing is left. */
968
+ declare function normalizeVideoGrade(grade: VideoGrade | undefined): VideoGrade | undefined;
969
+ /** A preset at `amount` (0–1, default 1) of its strength. */
970
+ declare function videoGradePreset(name: VideoGradePreset, amount?: number): VideoGrade | undefined;
971
+ /** One step of a grade. */
972
+ type VideoGradeStep = {
973
+ kind: 'brightness';
974
+ amount: number;
975
+ } | {
976
+ kind: 'contrast';
977
+ amount: number;
978
+ } | {
979
+ kind: 'saturate';
980
+ amount: number;
981
+ } | {
982
+ kind: 'hue-rotate';
983
+ degrees: number;
984
+ } | {
985
+ kind: 'gains';
986
+ r: number;
987
+ g: number;
988
+ b: number;
989
+ };
990
+ /** The steps a grade applies, in order, leaving out those that change nothing. */
991
+ declare function videoGradeSteps(grade: VideoGrade | undefined): VideoGradeStep[];
992
+ /**
993
+ * A step as a 3 × 4 matrix (rows r, g, b; columns r, g, b, offset), with the coefficients the CSS
994
+ * Filter Effects spec gives for `saturate` and `hue-rotate`.
995
+ */
996
+ declare function videoGradeStepMatrix(step: VideoGradeStep): number[][];
997
+ /** An RGB colour (0–255 each) through a grade, as the preview and export draw it. */
998
+ declare function applyVideoGrade(grade: VideoGrade | undefined, rgb: readonly [number, number, number]): [number, number, number];
999
+ /** The `values` of an SVG `feColorMatrix type="matrix"` for a step. */
1000
+ declare function videoGradeStepSvgValues(step: VideoGradeStep): string;
1001
+ /** An SVG `<filter>` applying a grade, steps in order (each clamps, as CSS filters do). */
1002
+ declare function videoGradeSvgFilter(id: string, grade: VideoGrade | undefined): string;
1003
+ /** Id of the SVG filter for a white-balance step: the same gains always get the same id. */
1004
+ declare const videoGradeGainsFilterId: (step: Extract<VideoGradeStep, {
1005
+ kind: "gains";
1006
+ }>) => string;
1007
+ /**
1008
+ * A grade as a CSS / canvas `filter`: CSS functions for every step, and `url(#id)` for white balance,
1009
+ * which CSS has no function for (see `videoGradeGainsFilterId`; the host puts that filter in the page).
1010
+ * `''` when the grade changes nothing.
1011
+ */
1012
+ declare function videoGradeCssFilter(grade: VideoGrade | undefined): string;
1013
+ /** The white-balance SVG filters a grade's CSS filter refers to, as `{ id, markup }`. */
1014
+ declare function videoGradeSvgDefs(grade: VideoGrade | undefined): {
1015
+ id: string;
1016
+ markup: string;
1017
+ }[];
1018
+ /** A grade as ffmpeg filters on RGB, in order: `lutrgb` for exposure and contrast, `colorchannelmixer` for the rest. */
1019
+ declare function videoGradeFfmpegFilters(grade: VideoGrade | undefined): string[];
1020
+
1021
+ /** Default length of an entrance or exit animation (ms). */
1022
+ declare const VIDEO_CLIP_ANIMATION_DURATION = 500;
1023
+ declare const PROPS: readonly ["opacity", "x", "y", "scale"];
1024
+ type Prop = (typeof PROPS)[number];
1025
+ /** The properties an animation moves (each also fades: opacity is always one). */
1026
+ declare function videoClipAnimationProperties(animation: VideoClipAnimation): Prop[];
1027
+ /** Entrance and exit lengths (ms), shortened in proportion when together they are longer than the clip. */
1028
+ declare function videoClipAnimationSpans(clip: VideoClip): {
1029
+ in: number;
1030
+ out: number;
1031
+ };
1032
+ /**
1033
+ * The clip with its entrance and exit animations written out as keyframes on opacity, x, y and
1034
+ * scale, so previews, SVG frames and the ffmpeg export all play them the same way. A property the
1035
+ * clip already keys itself is left alone (`checkVideoProject` notes it). Returns the clip unchanged
1036
+ * when it has no animations.
1037
+ */
1038
+ declare function videoClipAnimated(clip: VideoClip, project: Pick<VideoProject, 'width' | 'height'>): VideoClip;
1039
+
1040
+ /**
1041
+ * A transcript from text a speech-to-text service or captioning tool wrote: Whisper-style JSON
1042
+ * (`{ segments: [{ words: [{ word, start, end }] }] }` or `{ words: [...] }`, times in seconds, or a
1043
+ * plain `[{ word, start, end }]` array in ms), SubRip (`.srt`) or WebVTT. Captions have no word
1044
+ * timings, so their words are spread evenly across each cue (`approximate: true`). Throws when it
1045
+ * finds no words.
1046
+ */
1047
+ declare function parseVideoTranscript(input: string | unknown): {
1048
+ words: VideoTranscriptWord[];
1049
+ approximate: boolean;
1050
+ };
1051
+ /** A word where it plays on the timeline. */
1052
+ interface VideoTimelineWord {
1053
+ word: string;
1054
+ /** Timeline times (ms). */
1055
+ start: number;
1056
+ end: number;
1057
+ /** The clip that plays it. */
1058
+ clip: string;
1059
+ track: string;
1060
+ /** Its index in the asset's transcript. */
1061
+ index: number;
1062
+ }
1063
+ /**
1064
+ * The track whose words make the timeline transcript: `track` if given, else the first audio track
1065
+ * with a transcribed clip, else the first video track with one. `null` when nothing is transcribed.
1066
+ */
1067
+ declare function videoTranscriptTrack(project: VideoProject, track?: string): string | null;
1068
+ /**
1069
+ * The words the timeline plays on one track, in order: each transcribed media clip's words whose
1070
+ * middle falls inside the stretch of source it plays, moved to timeline time through its in point
1071
+ * and speed and clamped to the clip.
1072
+ */
1073
+ declare function videoTimelineTranscript(project: VideoProject, options?: {
1074
+ track?: string;
1075
+ }): VideoTimelineWord[];
1076
+ /** A stretch of the timeline (ms) and the words in it. */
1077
+ interface VideoTranscriptRange {
1078
+ from: number;
1079
+ to: number;
1080
+ text: string;
1081
+ }
1082
+ /** A word as compared: lower case, without surrounding punctuation. */
1083
+ declare const normalizeVideoWord: (word: string) => string;
1084
+ /** Every place a phrase is said (case and punctuation ignored), as timeline ranges. */
1085
+ declare function findVideoTranscriptText(words: readonly VideoTimelineWord[], query: string): VideoTranscriptRange[];
1086
+ /** Filler words and phrases removed by default. "like" and "so" are left out: too often meant. */
1087
+ declare const VIDEO_DEFAULT_FILLERS: readonly ["um", "umm", "uh", "uhh", "uhm", "erm", "er", "ah", "hmm", "mm", "you know", "i mean"];
1088
+ /** Fillers in the transcript, longest phrase first ("you know" before "you"), as timeline ranges. */
1089
+ declare function findVideoFillers(words: readonly VideoTimelineWord[], fillers?: readonly string[]): VideoTranscriptRange[];
1090
+ interface VideoPauseOptions {
1091
+ /** Shortest gap between words that counts as a pause (ms, default 700). */
1092
+ min?: number;
1093
+ /** Silence to keep next to each word so speech does not sound clipped (ms, default 150). */
1094
+ keep?: number;
1095
+ /** Frame rate to snap the cut inward to (default: none). */
1096
+ fps?: number;
1097
+ }
1098
+ /** Gaps between consecutive words on the same clip longer than `min`, less `keep` either side, as timeline ranges. */
1099
+ declare function findVideoTranscriptPauses(words: readonly VideoTimelineWord[], options?: VideoPauseOptions): VideoTranscriptRange[];
1100
+ /** Ranges sorted and merged where they touch or overlap. */
1101
+ declare function mergeVideoRanges(ranges: readonly {
1102
+ from: number;
1103
+ to: number;
1104
+ }[]): {
1105
+ from: number;
1106
+ to: number;
1107
+ }[];
1108
+ /**
1109
+ * The edits that cut ranges out of the timeline and close them up: one `extract_range` per merged
1110
+ * range, last first, so earlier ranges keep their times. Apply them together as one undo step.
1111
+ */
1112
+ declare function videoRemoveRangesEdits(ranges: readonly {
1113
+ from: number;
1114
+ to: number;
1115
+ }[], tracks?: string[]): VideoEdit[];
1116
+ /** The timeline stretch from word `a` to word `b` (either order), for deleting a selection of words. */
1117
+ declare function videoWordsRange(words: readonly VideoTimelineWord[], a: number, b: number): {
1118
+ from: number;
1119
+ to: number;
1120
+ };
1121
+ /** The edit that attaches a transcript file's text to an asset (see `parseVideoTranscript`). Throws a readable error for text it cannot read. */
1122
+ declare function videoTranscriptEdit(assetId: string, text: string): VideoEdit;
1123
+ /** The word playing at a timeline time, as its index in `words`, or -1. */
1124
+ declare function videoWordAt(words: readonly VideoTimelineWord[], time: number): number;
1125
+
1126
+ /** Radius of an iris `progress` (0–1) open: from nothing to the frame's corners. */
1127
+ declare const videoIrisRadius: (frame: {
1128
+ width: number;
1129
+ height: number;
1130
+ }, progress: number) => number;
831
1131
  /** The part of a rect a wipe shows. */
832
1132
  declare function videoWipeRect(rect: VideoRect, wipe: NonNullable<VideoLayer['wipe']>): VideoRect;
833
1133
  interface VideoSvgOptions {
@@ -849,8 +1149,10 @@ declare function videoContactSheetSvg(project: VideoProject, times: readonly num
849
1149
  width?: number;
850
1150
  }): string;
851
1151
  /** The subset of `CanvasRenderingContext2D` `drawVideoFrame` uses (so tests and workers can pass their own). */
852
- type VideoCanvasContext = Pick<CanvasRenderingContext2D, 'save' | 'restore' | 'fillRect' | 'drawImage' | 'translate' | 'rotate' | 'beginPath' | 'rect' | 'clip' | 'fillText' | 'measureText' | 'setTransform'> & {
1152
+ type VideoCanvasContext = Pick<CanvasRenderingContext2D, 'save' | 'restore' | 'fillRect' | 'drawImage' | 'translate' | 'rotate' | 'beginPath' | 'rect' | 'arc' | 'clip' | 'fillText' | 'measureText' | 'setTransform'> & {
853
1153
  globalAlpha: number;
1154
+ globalCompositeOperation: GlobalCompositeOperation;
1155
+ filter?: string;
854
1156
  fillStyle: string | CanvasGradient | CanvasPattern;
855
1157
  font: string;
856
1158
  textAlign: CanvasTextAlign;
@@ -862,9 +1164,13 @@ type VideoCanvasContext = Pick<CanvasRenderingContext2D, 'save' | 'restore' | 'f
862
1164
  /**
863
1165
  * Draws a frame on a 2D canvas scaled by `scale` (canvas pixels per frame pixel). `sourceFor`
864
1166
  * returns what to draw for a media layer (a `<video>` seeked to `layer.sourceTime`, an `<img>`,
865
- * an `ImageBitmap`…) or `null` for a placeholder box.
1167
+ * an `ImageBitmap`…) or `null` for a placeholder box. Grades become the context's `filter`; white
1168
+ * balance there refers to an SVG filter, which `options.defineSvgFilter` is given to put in the page
1169
+ * (without it, white balance is left out of the canvas).
866
1170
  */
867
- declare function drawVideoFrame(ctx: VideoCanvasContext, frame: VideoFrame, sourceFor: (layer: VideoLayer) => CanvasImageSource | null, scale?: number): void;
1171
+ declare function drawVideoFrame(ctx: VideoCanvasContext, frame: VideoFrame, sourceFor: (layer: VideoLayer) => CanvasImageSource | null, scale?: number, options?: {
1172
+ defineSvgFilter?: (id: string, markup: string) => void;
1173
+ }): void;
868
1174
 
869
1175
  interface VideoEdlOptions {
870
1176
  /** Track to export (default: the bottom video track, V1 in most NLEs). */
@@ -1014,6 +1320,11 @@ interface VideoPreviewOptions {
1014
1320
  context?: VideoCanvasContext | null;
1015
1321
  /** Called after each frame is drawn. */
1016
1322
  onFrame?: (frame: VideoFrame) => void;
1323
+ /**
1324
+ * Puts an SVG filter (white balance in a grade) where the canvas's `filter: url(#id)` can find
1325
+ * it. Default: a hidden `<svg>` added to `document.body`. `null` leaves white balance out.
1326
+ */
1327
+ defineSvgFilter?: ((id: string, markup: string) => void) | null;
1017
1328
  }
1018
1329
  /**
1019
1330
  * Plays a project in the browser: keeps one `<video>` or `<audio>` element per playing clip in step
@@ -1031,6 +1342,8 @@ declare class VideoPreviewEngine {
1031
1342
  private readonly unsubscribe;
1032
1343
  private scheduled;
1033
1344
  private destroyed;
1345
+ private filterHost;
1346
+ private readonly filters;
1034
1347
  constructor(source: VideoPreviewSource, canvas: {
1035
1348
  width: number;
1036
1349
  height: number;
@@ -1046,6 +1359,7 @@ declare class VideoPreviewEngine {
1046
1359
  private redraw;
1047
1360
  private sourceFor;
1048
1361
  private draw;
1362
+ private readonly defineSvgFilter;
1049
1363
  /** Stops following the editor and releases every media element. */
1050
1364
  destroy(): void;
1051
1365
  }
@@ -1207,7 +1521,28 @@ interface VideoEditorToolProviderOptions {
1207
1521
  }
1208
1522
  /** A project as agents see it: settings, assets, and each track's clips in order with their times. */
1209
1523
  declare function describeVideoProject(project: VideoProject): {
1210
- assets: VideoAsset[];
1524
+ assets: ({
1525
+ id: string;
1526
+ kind: VideoAssetKind;
1527
+ src: string;
1528
+ name?: string;
1529
+ duration?: number;
1530
+ width?: number;
1531
+ height?: number;
1532
+ hasAudio?: boolean;
1533
+ poster?: string;
1534
+ } | {
1535
+ transcriptWords: number;
1536
+ id: string;
1537
+ kind: VideoAssetKind;
1538
+ src: string;
1539
+ name?: string;
1540
+ duration?: number;
1541
+ width?: number;
1542
+ height?: number;
1543
+ hasAudio?: boolean;
1544
+ poster?: string;
1545
+ })[];
1211
1546
  tracks: {
1212
1547
  clips: ({
1213
1548
  source?: {
@@ -1230,6 +1565,10 @@ declare function describeVideoProject(project: VideoProject): {
1230
1565
  opacity?: VideoAnimatable;
1231
1566
  transform?: VideoTransform;
1232
1567
  fit?: VideoFit;
1568
+ blend?: VideoBlendMode;
1569
+ grade?: VideoGrade;
1570
+ animateIn?: VideoClipAnimation;
1571
+ animateOut?: VideoClipAnimation;
1233
1572
  fadeIn?: number;
1234
1573
  fadeOut?: number;
1235
1574
  transition?: VideoTransition;
@@ -1253,6 +1592,10 @@ declare function describeVideoProject(project: VideoProject): {
1253
1592
  opacity?: VideoAnimatable;
1254
1593
  transform?: VideoTransform;
1255
1594
  fit?: VideoFit;
1595
+ blend?: VideoBlendMode;
1596
+ grade?: VideoGrade;
1597
+ animateIn?: VideoClipAnimation;
1598
+ animateOut?: VideoClipAnimation;
1256
1599
  fadeIn?: number;
1257
1600
  fadeOut?: number;
1258
1601
  transition?: VideoTransition;
@@ -1271,6 +1614,10 @@ declare function describeVideoProject(project: VideoProject): {
1271
1614
  opacity?: VideoAnimatable;
1272
1615
  transform?: VideoTransform;
1273
1616
  fit?: VideoFit;
1617
+ blend?: VideoBlendMode;
1618
+ grade?: VideoGrade;
1619
+ animateIn?: VideoClipAnimation;
1620
+ animateOut?: VideoClipAnimation;
1274
1621
  fadeIn?: number;
1275
1622
  fadeOut?: number;
1276
1623
  transition?: VideoTransition;
@@ -1319,6 +1666,14 @@ declare function videoRulerTicks(duration: number, pxPerSecond: number, fps: num
1319
1666
  type VideoWaveformMode = 'audio' | 'all' | 'none';
1320
1667
  /** Whether a timeline in `mode` draws a waveform in this clip. */
1321
1668
  declare function videoClipShowsWaveform(clip: VideoClip, asset: VideoAsset | undefined, mode?: VideoWaveformMode): asset is VideoAsset;
1669
+ /** Names for the entrance and exit animations, for menus. */
1670
+ declare const VIDEO_CLIP_ANIMATION_LABELS: Readonly<Record<VideoClipAnimationEffect, string>>;
1671
+ /** Names for the transitions, for menus. */
1672
+ declare const VIDEO_TRANSITION_LABELS: Readonly<Record<VideoTransitionType, string>>;
1673
+ /** Whether a transition type takes a `direction`. */
1674
+ declare const videoTransitionHasDirection: (type: VideoTransitionType) => boolean;
1675
+ /** Names for the blend modes, for menus. */
1676
+ declare const VIDEO_BLEND_MODE_LABELS: Readonly<Record<VideoBlendMode, string>>;
1322
1677
  /** Names for the sound fade curves, for menus. */
1323
1678
  declare const VIDEO_FADE_CURVE_LABELS: Readonly<Record<VideoFadeCurve, string>>;
1324
1679
  declare function videoClipTint(clip: VideoClip, asset?: VideoAsset): string;
@@ -1416,4 +1771,4 @@ declare function videoKeyframeValueEdit(project: VideoProject, clipId: string, p
1416
1771
  */
1417
1772
  declare function videoKeyframeToggleEdit(project: VideoProject, clipId: string, property: VideoKeyframeProperty, time: number): VideoEdit | null;
1418
1773
 
1419
- export { type CreateVideoProjectOptions, type NewVideoClip, VIDEO_CLIP_TYPES, VIDEO_DEFAULT_STILL_DURATION, VIDEO_DEFAULT_TITLE_DURATION, VIDEO_EASE_NAMES, VIDEO_EDIT_OPS, VIDEO_FADE_CURVES, VIDEO_FADE_CURVE_LABELS, VIDEO_FITS, VIDEO_ISSUE_CODES, VIDEO_KEYFRAME_LIMITS, VIDEO_KEYFRAME_PROPERTIES, VIDEO_PEAK_BLOCK, VIDEO_PLACEMENT_MODES, VIDEO_TIME_EPSILON, VIDEO_TRANSFORM_PROPERTIES, VIDEO_TRANSITION_TYPES, VIDEO_WIPE_DIRECTIONS, type VideoAnimatable, type VideoAsset, type VideoAssetKind, type VideoAudioLevel, type VideoAudioPeaks, VideoAudioPeaksCache, type VideoAudioPeaksLoader, type VideoAudioSource, type VideoCanvasContext, type VideoClip, type VideoClipDragInput, type VideoClipDragMode, type VideoClipDragPlan, type VideoClipLocation, type VideoClipType, type VideoColorClip, type VideoEase, type VideoEdit, type VideoEditOp, type VideoEditOutcome, type VideoEditResult, VideoEditorController, type VideoEditorOptions, type VideoEditorState, type VideoEditorToolProviderOptions, type VideoEdlOptions, type VideoFadeCurve, type VideoFfmpegExport, type VideoFfmpegOptions, type VideoFit, type VideoFrame, type VideoGap, type VideoIssue, type VideoIssueCode, type VideoIssueSeverity, type VideoKey, type VideoKeyframeProperty, type VideoKeyframeRow, type VideoKeyframes, type VideoLayer, type VideoLoudnessMeasurement, type VideoLoudnessTarget, type VideoMarker, type VideoMediaClip, type VideoMediaProbe, type VideoPlacementMode, VideoPreviewEngine, type VideoPreviewImage, type VideoPreviewMedia, type VideoPreviewOptions, type VideoPreviewSource, type VideoProject, type VideoRect, type VideoRulerTick, type VideoSilenceOptions, type VideoSnapOptions, type VideoSvgOptions, type VideoTextClip, type VideoTrack, type VideoTrackKind, type VideoTransform, type VideoTransition, type VideoTransitionType, type VideoWaveformMode, type VideoWipeDirection, allVideoClipIds, applyVideoEdits, buildVideoAudioPeaks, checkVideoProject, createVideoEditorToolProvider, createVideoProject, decodeVideoAudioPeaks, describeVideoProject, drawVideoFrame, ffmpegFilterValue, findVideoAudioSilences, findVideoClip, findVideoGaps, formatVideoSeconds, formatVideoTimecode, formatVideoTimecodeFrames, isVideoDropFrameRate, isVideoKeyframes, nextFreeVideoSlot, parseVideoAnimatable, parseVideoAsset, parseVideoClip, parseVideoKeyframes, parseVideoLoudnessMeasurement, parseVideoMarker, parseVideoProject, parseVideoTrack, parseVideoTransform, parseVideoTransition, placeVideoRect, planVideoClipDrag, probeVideoMedia, removeVideoKey, retimeVideoAnimatable, setVideoKey, snapToVideoFrame, snapVideoTime, sortVideoKeys, sortedVideoClips, splitVideoAnimatable, toVideoEdl, toVideoFfmpeg, toVideoLoudnessMeasure, videoAssetDropEdit, videoAssetHasSound, videoAssetKindOf, videoAssetMap, videoAudioLevels, videoAudioPeakRange, videoAudioPeakSpans, videoAudioPeaksDuration, videoClipAfter, videoClipBefore, videoClipEnd, videoClipHandles, videoClipKeyframes, videoClipLabel, videoClipOverhang, videoClipShowsWaveform, videoClipSoundGain, videoClipSourceRange, videoClipSpeed, videoClipTint, videoClipWaveform, videoClipWaveformPath, videoClipsAt, videoContactSheetSvg, videoDragLabel, videoDropTracks, videoEaseBezier, videoEaseProgress, videoFadeCurveGain, videoFrameAt, videoFrameDuration, videoFrameToSvg, videoFrames, videoHourFrames, videoIssueKey, videoKeyframeBreakpoints, videoKeyframeFfmpegExpr, videoKeyframeRows, videoKeyframeToggleEdit, videoKeyframeValueEdit, videoKeysOf, videoOverlap, videoPeakDb, videoProjectDuration, videoProjectSvg, videoRulerTicks, videoSnapPoints, videoTextStyle, videoTimecodeFrames, videoTitleFrame, videoTrackSyncLocked, videoTransformAt, videoValueAt, videoWaveformPath, videoWipeRect };
1774
+ export { type CreateVideoProjectOptions, type NewVideoClip, VIDEO_BLEND_MODES, VIDEO_BLEND_MODE_LABELS, VIDEO_CLIP_ANIMATION_DURATION, VIDEO_CLIP_ANIMATION_EFFECTS, VIDEO_CLIP_ANIMATION_LABELS, VIDEO_CLIP_TYPES, VIDEO_DEFAULT_FILLERS, VIDEO_DEFAULT_STILL_DURATION, VIDEO_DEFAULT_TITLE_DURATION, VIDEO_EASE_NAMES, VIDEO_EDIT_OPS, VIDEO_FADE_CURVES, VIDEO_FADE_CURVE_LABELS, VIDEO_FITS, VIDEO_GRADE_CONTROLS, VIDEO_GRADE_PRESETS, VIDEO_GRADE_PRESET_NAMES, VIDEO_ISSUE_CODES, VIDEO_KEYFRAME_LIMITS, VIDEO_KEYFRAME_PROPERTIES, VIDEO_PEAK_BLOCK, VIDEO_PLACEMENT_MODES, VIDEO_TIME_EPSILON, VIDEO_TRANSFORM_PROPERTIES, VIDEO_TRANSITION_LABELS, VIDEO_TRANSITION_TYPES, VIDEO_WIPE_DIRECTIONS, type VideoAnimatable, type VideoAsset, type VideoAssetKind, type VideoAudioLevel, type VideoAudioPeaks, VideoAudioPeaksCache, type VideoAudioPeaksLoader, type VideoAudioSource, type VideoBlendMode, type VideoCanvasContext, type VideoClip, type VideoClipAnimation, type VideoClipAnimationEffect, type VideoClipDragInput, type VideoClipDragMode, type VideoClipDragPlan, type VideoClipLocation, type VideoClipType, type VideoColorClip, type VideoEase, type VideoEdit, type VideoEditOp, type VideoEditOutcome, type VideoEditResult, VideoEditorController, type VideoEditorOptions, type VideoEditorState, type VideoEditorToolProviderOptions, type VideoEdlOptions, type VideoFadeCurve, type VideoFfmpegExport, type VideoFfmpegOptions, type VideoFit, type VideoFrame, type VideoGap, type VideoGrade, type VideoGradeControl, type VideoGradePreset, type VideoGradeStep, type VideoIssue, type VideoIssueCode, type VideoIssueSeverity, type VideoKey, type VideoKeyframeProperty, type VideoKeyframeRow, type VideoKeyframes, type VideoLayer, type VideoLoudnessMeasurement, type VideoLoudnessTarget, type VideoMarker, type VideoMediaClip, type VideoMediaProbe, type VideoPauseOptions, type VideoPlacementMode, VideoPreviewEngine, type VideoPreviewImage, type VideoPreviewMedia, type VideoPreviewOptions, type VideoPreviewSource, type VideoProject, type VideoRect, type VideoRulerTick, type VideoSilenceOptions, type VideoSnapOptions, type VideoSvgOptions, type VideoTextClip, type VideoTimelineWord, type VideoTrack, type VideoTrackKind, type VideoTranscriptRange, type VideoTranscriptWord, type VideoTransform, type VideoTransition, type VideoTransitionType, type VideoWaveformMode, type VideoWipeDirection, allVideoClipIds, applyVideoEdits, applyVideoGrade, buildVideoAudioPeaks, checkVideoProject, createVideoEditorToolProvider, createVideoProject, decodeVideoAudioPeaks, describeVideoProject, drawVideoFrame, ffmpegFilterValue, findVideoAudioSilences, findVideoClip, findVideoFillers, findVideoGaps, findVideoTranscriptPauses, findVideoTranscriptText, formatVideoSeconds, formatVideoTimecode, formatVideoTimecodeFrames, isVideoDropFrameRate, isVideoKeyframes, mergeVideoRanges, nextFreeVideoSlot, normalizeVideoGrade, normalizeVideoWord, parseVideoAnimatable, parseVideoAsset, parseVideoClip, parseVideoClipAnimation, parseVideoGrade, parseVideoKeyframes, parseVideoLoudnessMeasurement, parseVideoMarker, parseVideoProject, parseVideoTrack, parseVideoTranscript, parseVideoTranscriptWords, parseVideoTransform, parseVideoTransition, placeVideoRect, planVideoClipDrag, probeVideoMedia, removeVideoKey, retimeVideoAnimatable, setVideoKey, snapToVideoFrame, snapVideoTime, sortVideoKeys, sortedVideoClips, splitVideoAnimatable, toVideoEdl, toVideoFfmpeg, toVideoLoudnessMeasure, videoAssetDropEdit, videoAssetHasSound, videoAssetKindOf, videoAssetMap, videoAudioLevels, videoAudioPeakRange, videoAudioPeakSpans, videoAudioPeaksDuration, videoClipAfter, videoClipAnimated, videoClipAnimationProperties, videoClipAnimationSpans, videoClipBefore, videoClipEnd, videoClipHandles, videoClipKeyframes, videoClipLabel, videoClipOverhang, videoClipShowsWaveform, videoClipSoundGain, videoClipSourceRange, videoClipSpeed, videoClipTint, videoClipWaveform, videoClipWaveformPath, videoClipsAt, videoContactSheetSvg, videoDragLabel, videoDropTracks, videoEaseBezier, videoEaseProgress, videoFadeCurveGain, videoFrameAt, videoFrameDuration, videoFrameToSvg, videoFrames, videoGradeCssFilter, videoGradeFfmpegFilters, videoGradeGainsFilterId, videoGradePreset, videoGradeStepMatrix, videoGradeStepSvgValues, videoGradeSteps, videoGradeSvgDefs, videoGradeSvgFilter, videoHourFrames, videoIrisRadius, videoIssueKey, videoKeyframeBreakpoints, videoKeyframeFfmpegExpr, videoKeyframeRows, videoKeyframeToggleEdit, videoKeyframeValueEdit, videoKeysOf, videoOverlap, videoPeakDb, videoProjectDuration, videoProjectSvg, videoRemoveRangesEdits, videoRulerTicks, videoSnapPoints, videoTextStyle, videoTimecodeFrames, videoTimelineTranscript, videoTitleFrame, videoTrackSyncLocked, videoTranscriptEdit, videoTranscriptTrack, videoTransformAt, videoTransitionAudioCurve, videoTransitionEase, videoTransitionHasDirection, videoValueAt, videoWaveformPath, videoWipeRect, videoWordAt, videoWordsRange };