@pixerate/editor 0.86.0 → 0.88.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.
@@ -191,9 +191,18 @@ declare const videoTransitionAudioCurve: (t: VideoTransition) => VideoFadeCurve;
191
191
  */
192
192
  type VideoBlendMode = 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'add';
193
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
+ /** A 3D LUT a grade applies after its other steps (see `VideoGrade.lut`). */
195
+ interface VideoGradeLut {
196
+ /** A `.cube` file: whatever the host can load (URL, path) and the exporter can open. */
197
+ src: string;
198
+ /** How much of the LUT's change to apply, 0–1 (default 1). */
199
+ strength?: number;
200
+ /** A label for the look (default the file's TITLE or name). */
201
+ name?: string;
202
+ }
194
203
  /**
195
204
  * 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).
205
+ * order: exposure, contrast, saturation, hue, white balance (temperature and tint), then the LUT.
197
206
  */
198
207
  interface VideoGrade {
199
208
  /** Stops: +1 doubles every channel (default 0). */
@@ -208,6 +217,8 @@ interface VideoGrade {
208
217
  temperature?: number;
209
218
  /** -1 (green) to 1 (magenta); default 0. */
210
219
  tint?: number;
220
+ /** A 3D LUT (a `.cube` file) applied last, mixed in at its `strength`. */
221
+ lut?: VideoGradeLut;
211
222
  }
212
223
  /**
213
224
  * How a clip enters or leaves: `fade`; `rise` (up into place) or `drop` (down into place);
@@ -354,6 +365,7 @@ declare function parseVideoTransform(v: unknown, path: string): VideoTransform |
354
365
  declare function parseVideoTimeRemap(v: unknown, speed: unknown, path: string): VideoKeyframes | undefined;
355
366
  declare function parseVideoClipAnimation(v: unknown, path: string): VideoClipAnimation | undefined;
356
367
  declare function parseVideoGrade(v: unknown, path: string): VideoGrade | undefined;
368
+ declare function parseVideoGradeLut(v: unknown, path: string): VideoGradeLut | undefined;
357
369
  declare function parseVideoTransition(v: unknown, path: string): VideoTransition | undefined;
358
370
  declare function parseVideoTranscriptWords(v: unknown, path: string): VideoTranscriptWord[] | undefined;
359
371
  declare function parseVideoAsset(v: unknown, path?: string): VideoAsset;
@@ -931,6 +943,83 @@ declare class VideoAudioPeaksCache {
931
943
  private emit;
932
944
  }
933
945
 
946
+ /**
947
+ * 3D LUTs for grades: `.cube` files read into a lattice and applied with tetrahedral
948
+ * interpolation, as ffmpeg's `lut3d=interp=tetrahedral` and grading apps apply them, so the
949
+ * preview and the export agree. A grade's LUT (`VideoGrade.lut`) runs after its other steps and is
950
+ * mixed with the picture before it by `strength`.
951
+ */
952
+ /** A 3D LUT: `size`³ output colours, red changing fastest, then green, then blue (the `.cube` order). */
953
+ interface VideoLut {
954
+ title?: string;
955
+ size: number;
956
+ /** Input values mapped to the first and last lattice points, per channel (default 0 and 1). */
957
+ domainMin: [number, number, number];
958
+ domainMax: [number, number, number];
959
+ /** `size³ × 3` output values. */
960
+ data: Float32Array;
961
+ }
962
+ /** Largest `LUT_3D_SIZE` read (129³ rows is about 2 million). */
963
+ declare const VIDEO_LUT_MAX_SIZE = 129;
964
+ /** Reads a `.cube` file's 3D table. Errors give the line and what is wrong. */
965
+ declare function parseVideoCubeLut(text: string): VideoLut;
966
+ /** A LUT of `size` points a side built from a colour function (each channel 0–1 in and out). */
967
+ declare function videoLutFromFunction(size: number, fn: (rgb: [number, number, number]) => readonly [number, number, number], title?: string): VideoLut;
968
+ /** A LUT as `.cube` text. */
969
+ declare function videoLutToCube(lut: VideoLut): string;
970
+ /**
971
+ * A colour (each channel 0–1) through a LUT with tetrahedral interpolation: the lattice cube
972
+ * around the colour is split into six tetrahedra along its grey diagonal, and the colour is mixed
973
+ * from the four corners of the one it falls in. Greys stay on the diagonal, unlike trilinear.
974
+ */
975
+ declare function applyVideoLut(lut: VideoLut, rgb: readonly [number, number, number], out?: [number, number, number]): [number, number, number];
976
+ /** Runs RGBA pixels (0–255, as `ImageData` has them) through a LUT in place, mixed with the originals by `strength` (0–1). Transparent pixels are left alone. */
977
+ declare function applyVideoLutToPixels(lut: VideoLut, data: {
978
+ length: number;
979
+ [i: number]: number;
980
+ }, strength?: number): void;
981
+ /**
982
+ * An SVG approximation of a LUT for SVG frames, which have no 3D tables: per-channel curves taken
983
+ * along the LUT's grey axis (`feComponentTransfer` tables), then the colour matrix that best fits
984
+ * the rest (least squares over the lattice). Exact for LUTs that are curves or a matrix; close for
985
+ * most looks. The preview and the export apply the LUT itself.
986
+ */
987
+ interface VideoLutSvgApproximation {
988
+ /** Per-channel curve tables (`tableValues`), each 0–1. */
989
+ tables: [number[], number[], number[]];
990
+ /** A 3 × 4 matrix (rows r, g, b; columns r, g, b, offset) applied after the curves. */
991
+ matrix: number[][];
992
+ }
993
+ declare function videoLutSvgApproximation(lut: VideoLut): VideoLutSvgApproximation;
994
+ /** Where LUT files come from: their text for a `src` (default: `fetch`). */
995
+ type VideoLutLoader = (src: string) => Promise<string | VideoLut>;
996
+ /**
997
+ * Loaded LUTs by `src`, read once and shared by the preview, SVG frames and agent tools
998
+ * (`VideoEditorController.luts`). Listeners hear when one loads or fails.
999
+ */
1000
+ declare class VideoLutCache {
1001
+ private readonly loader;
1002
+ private readonly ready;
1003
+ private readonly pending;
1004
+ private readonly failed;
1005
+ private readonly listeners;
1006
+ constructor(loader?: VideoLutLoader);
1007
+ /** The LUT if loaded, without starting to load it. */
1008
+ peek(src: string): VideoLut | undefined;
1009
+ /** The LUT if loaded; otherwise `undefined`, and loading starts (once) unless it failed. */
1010
+ get(src: string): VideoLut | undefined;
1011
+ /** Why loading a LUT failed, if it did. */
1012
+ error(src: string): string | undefined;
1013
+ /** The LUT, loading and reading it if needed. Rejects with a readable error. */
1014
+ load(src: string): Promise<VideoLut>;
1015
+ /** Uses a LUT the host already has (`.cube` text or a parsed LUT), under `src`. */
1016
+ set(src: string, lut: VideoLut | string): VideoLut;
1017
+ /** Forgets a failure so the next `get` tries again. */
1018
+ retry(src: string): void;
1019
+ subscribe(fn: () => void): () => void;
1020
+ private emit;
1021
+ }
1022
+
934
1023
  /**
935
1024
  * Colour correction as a fixed series of colour-matrix steps on gamma-encoded sRGB, each clamped
936
1025
  * to 0–1, in the same order everywhere: exposure, contrast, saturation, hue, then white balance.
@@ -939,8 +1028,10 @@ declare class VideoAudioPeaksCache {
939
1028
  * formulas, so the preview, SVG frames and the export agree.
940
1029
  */
941
1030
  /** One slider of a grade: its range, default and step, for schemas, inspectors and clamping. */
1031
+ /** The numeric settings of a grade (everything but its LUT). */
1032
+ type VideoGradeSetting = Exclude<keyof VideoGrade, 'lut'>;
942
1033
  interface VideoGradeControl {
943
- key: keyof VideoGrade;
1034
+ key: VideoGradeSetting;
944
1035
  label: string;
945
1036
  min: number;
946
1037
  max: number;
@@ -984,10 +1075,14 @@ declare const VIDEO_GRADE_PRESETS: {
984
1075
  };
985
1076
  type VideoGradePreset = keyof typeof VIDEO_GRADE_PRESETS;
986
1077
  declare const VIDEO_GRADE_PRESET_NAMES: VideoGradePreset[];
1078
+ /** A LUT setting with its strength clamped to 0–1 (and 1 left out); `undefined` without a `src` or at strength 0. */
1079
+ declare function normalizeVideoGradeLut(lut: VideoGradeLut | undefined): VideoGradeLut | undefined;
987
1080
  /** A grade with every value clamped to its range and zero values left out; `undefined` when nothing is left. */
988
1081
  declare function normalizeVideoGrade(grade: VideoGrade | undefined): VideoGrade | undefined;
989
1082
  /** A preset at `amount` (0–1, default 1) of its strength. */
990
1083
  declare function videoGradePreset(name: VideoGradePreset, amount?: number): VideoGrade | undefined;
1084
+ /** A preset look on a grade, keeping the grade's LUT (a look replaces only the settings). */
1085
+ declare function videoGradeLook(current: VideoGrade | undefined, name: VideoGradePreset, amount?: number): VideoGrade | undefined;
991
1086
  /** One step of a grade. */
992
1087
  type VideoGradeStep = {
993
1088
  kind: 'brightness';
@@ -1014,12 +1109,23 @@ declare function videoGradeSteps(grade: VideoGrade | undefined): VideoGradeStep[
1014
1109
  * Filter Effects spec gives for `saturate` and `hue-rotate`.
1015
1110
  */
1016
1111
  declare function videoGradeStepMatrix(step: VideoGradeStep): number[][];
1017
- /** An RGB colour (0–255 each) through a grade, as the preview and export draw it. */
1018
- declare function applyVideoGrade(grade: VideoGrade | undefined, rgb: readonly [number, number, number]): [number, number, number];
1112
+ /**
1113
+ * An RGB colour (0–255 each) through a grade, as the preview and export draw it. A grade's LUT is
1114
+ * applied when its table is passed as `lut` (else it is left out).
1115
+ */
1116
+ declare function applyVideoGrade(grade: VideoGrade | undefined, rgb: readonly [number, number, number], lut?: VideoLut | null): [number, number, number];
1019
1117
  /** The `values` of an SVG `feColorMatrix type="matrix"` for a step. */
1020
1118
  declare function videoGradeStepSvgValues(step: VideoGradeStep): string;
1021
- /** An SVG `<filter>` applying a grade, steps in order (each clamps, as CSS filters do). */
1022
- declare function videoGradeSvgFilter(id: string, grade: VideoGrade | undefined): string;
1119
+ /**
1120
+ * SVG filter primitives approximating a LUT (see `videoLutSvgApproximation`) on the result of the
1121
+ * primitives before them, mixed with it by `strength`.
1122
+ */
1123
+ declare function videoLutSvgPrimitives(lut: VideoLut, strength?: number): string;
1124
+ /**
1125
+ * An SVG `<filter>` applying a grade, steps in order (each clamps, as CSS filters do). With the
1126
+ * grade's LUT table (`lut`), an approximation of it follows (SVG has no 3D tables).
1127
+ */
1128
+ declare function videoGradeSvgFilter(id: string, grade: VideoGrade | undefined, lut?: VideoLut | null): string;
1023
1129
  /** Id of the SVG filter for a white-balance step: the same gains always get the same id. */
1024
1130
  declare const videoGradeGainsFilterId: (step: Extract<VideoGradeStep, {
1025
1131
  kind: "gains";
@@ -1038,6 +1144,223 @@ declare function videoGradeSvgDefs(grade: VideoGrade | undefined): {
1038
1144
  /** A grade as ffmpeg filters on RGB, in order: `lutrgb` for exposure and contrast, `colorchannelmixer` for the rest. */
1039
1145
  declare function videoGradeFfmpegFilters(grade: VideoGrade | undefined): string[];
1040
1146
 
1147
+ /**
1148
+ * Colour scopes: a histogram, a luma waveform and a vectorscope, worked out from a frame's pixels,
1149
+ * plus exposure and clipping figures. Pure functions on RGBA pixels as `ImageData` holds them, so
1150
+ * the same numbers come from a preview canvas, a decoded export frame or a test.
1151
+ *
1152
+ * Luma and chroma use the Rec. 709 weights on the gamma-encoded values (Y′, Cb, Cr), as broadcast
1153
+ * scopes do: luma 0 is black and 1 white; Cb and Cr run from −0.5 to 0.5.
1154
+ */
1155
+ /** RGBA pixels, 4 values (0–255) a pixel, rows top to bottom: an `ImageData` fits. */
1156
+ interface VideoPixels {
1157
+ width: number;
1158
+ height: number;
1159
+ data: ArrayLike<number>;
1160
+ }
1161
+ type VideoScopeKind = 'histogram' | 'waveform' | 'vectorscope';
1162
+ declare const VIDEO_SCOPE_KINDS: readonly ["histogram", "waveform", "vectorscope"];
1163
+ /** Rec. 709 luma of gamma-encoded RGB (each 0–1). */
1164
+ declare const videoLuma: (r: number, g: number, b: number) => number;
1165
+ /** Rec. 709 chroma (Cb, Cr), each −0.5 to 0.5, of gamma-encoded RGB (each 0–1). */
1166
+ declare function videoChroma(r: number, g: number, b: number): [number, number];
1167
+ interface VideoScopeOptions {
1168
+ /**
1169
+ * Read at most about this many pixels, evenly spaced (default 262 144, a 512 × 512 picture), so
1170
+ * a large frame costs no more than a small one. Counts are of the pixels read.
1171
+ */
1172
+ maxPixels?: number;
1173
+ }
1174
+ /** How many pixels fall in each of `bins` equal steps of red, green, blue and luma (bin 0 is darkest). */
1175
+ interface VideoHistogram {
1176
+ bins: number;
1177
+ r: number[];
1178
+ g: number[];
1179
+ b: number[];
1180
+ luma: number[];
1181
+ /** Pixels counted. */
1182
+ total: number;
1183
+ }
1184
+ declare function videoHistogram(pixels: VideoPixels, options?: VideoScopeOptions & {
1185
+ bins?: number;
1186
+ }): VideoHistogram;
1187
+ /**
1188
+ * A luma waveform: the picture split into `columns` vertical strips, left to right, each counting
1189
+ * its pixels at each of `levels` luma steps. `data[column * levels + level]`; level 0 is black.
1190
+ */
1191
+ interface VideoWaveform {
1192
+ columns: number;
1193
+ levels: number;
1194
+ data: Uint32Array;
1195
+ /** The largest count, for scaling a drawing. */
1196
+ peak: number;
1197
+ }
1198
+ declare function videoLumaWaveform(pixels: VideoPixels, options?: VideoScopeOptions & {
1199
+ columns?: number;
1200
+ levels?: number;
1201
+ }): VideoWaveform;
1202
+ /**
1203
+ * A vectorscope: pixels counted on a `size` × `size` grid by chroma, Cb across (left −0.5, right
1204
+ * +0.5) and Cr up (top +0.5). The centre is grey; the further out, the more saturated; the angle
1205
+ * is the hue. `data[row * size + column]`.
1206
+ */
1207
+ interface VideoVectorscope {
1208
+ size: number;
1209
+ data: Uint32Array;
1210
+ peak: number;
1211
+ }
1212
+ /** Where chroma (Cb, Cr) falls on a vectorscope of `size` pixels, as `[column, row]`. */
1213
+ declare const videoVectorscopePoint: (cb: number, cr: number, size: number) => [number, number];
1214
+ declare function videoVectorscope(pixels: VideoPixels, options?: VideoScopeOptions & {
1215
+ size?: number;
1216
+ }): VideoVectorscope;
1217
+ /** Exposure and colour figures for a frame (see `videoExposureStats`). Luma and levels run 0–1. */
1218
+ interface VideoExposureStats {
1219
+ /** Pixels read. */
1220
+ pixels: number;
1221
+ luma: {
1222
+ mean: number;
1223
+ median: number;
1224
+ min: number;
1225
+ max: number;
1226
+ p1: number;
1227
+ p99: number;
1228
+ };
1229
+ /** Share (0–1) of pixels crushed to black (luma at or below `shadowLevel`) or blown to white (at or above `highlightLevel`). */
1230
+ clipped: {
1231
+ shadows: number;
1232
+ highlights: number;
1233
+ r: number;
1234
+ g: number;
1235
+ b: number;
1236
+ };
1237
+ /** Mean and highest chroma, 0 (grey) to 1 (a full primary). */
1238
+ saturation: {
1239
+ mean: number;
1240
+ max: number;
1241
+ };
1242
+ /** The mean colour as `#rrggbb`: far from grey means a colour cast. */
1243
+ average: string;
1244
+ }
1245
+ interface VideoExposureOptions extends VideoScopeOptions {
1246
+ /** Luma (0–1) at or below which a pixel counts as crushed (default 0.02). */
1247
+ shadowLevel?: number;
1248
+ /** Luma or channel (0–1) at or above which a pixel counts as blown (default 0.98). */
1249
+ highlightLevel?: number;
1250
+ }
1251
+ declare function videoExposureStats(pixels: VideoPixels, options?: VideoExposureOptions): VideoExposureStats;
1252
+ /** What a scope reading says in words: exposure, clipping and colour cast worth fixing. */
1253
+ declare function videoExposureNotes(stats: VideoExposureStats): string[];
1254
+ /** A compact reading of a frame for agents: exposure figures, notes, and coarse histogram, waveform and vectorscope summaries. */
1255
+ interface VideoScopeSummary {
1256
+ stats: VideoExposureStats;
1257
+ notes: string[];
1258
+ /** Share of pixels (0–1) in each of `bins` equal luma and channel steps, darkest first. */
1259
+ histogram: {
1260
+ bins: number;
1261
+ luma: number[];
1262
+ r: number[];
1263
+ g: number[];
1264
+ b: number[];
1265
+ };
1266
+ /** The picture in vertical strips, left to right: each strip's luma spread (0–1). */
1267
+ waveform: {
1268
+ start: number;
1269
+ end: number;
1270
+ min: number;
1271
+ median: number;
1272
+ max: number;
1273
+ }[];
1274
+ /** The chroma of the most saturated tenth of the picture: its main hue (degrees on the vectorscope, red ≈ 103°) and strength (0–1). */
1275
+ vectorscope: {
1276
+ hue: number | null;
1277
+ strength: number;
1278
+ spread: number;
1279
+ };
1280
+ }
1281
+ /** Vectorscope angle (degrees, anticlockwise from +Cb) of chroma. */
1282
+ declare const videoVectorscopeAngle: (cb: number, cr: number) => number;
1283
+ declare function summarizeVideoScopes(pixels: VideoPixels, options?: VideoExposureOptions & {
1284
+ bins?: number;
1285
+ columns?: number;
1286
+ }): VideoScopeSummary;
1287
+ /** Where the six 75% colour-bar targets sit on a vectorscope: name, Cb and Cr. */
1288
+ declare const VIDEO_VECTORSCOPE_TARGETS: readonly {
1289
+ name: string;
1290
+ rgb: [number, number, number];
1291
+ cb: number;
1292
+ cr: number;
1293
+ }[];
1294
+ /** RGBA pixels of a drawn scope, ready for `new ImageData(data, width, height)`. */
1295
+ interface VideoScopeImage {
1296
+ width: number;
1297
+ height: number;
1298
+ data: Uint8ClampedArray<ArrayBuffer>;
1299
+ }
1300
+ /** A histogram drawn `width` × `height`: red, green and blue added together, with luma as a white outline. */
1301
+ declare function videoHistogramImage(h: VideoHistogram, width?: number, height?: number): VideoScopeImage;
1302
+ /** A luma waveform drawn `width` × `height`: white at the top, black at the bottom, lines at each quarter. */
1303
+ declare function videoWaveformImage(w: VideoWaveform, width?: number, height?: number): VideoScopeImage;
1304
+ /** A vectorscope drawn `size` × `size`, with its outer circle, the skin-tone line and the colour-bar targets. */
1305
+ declare function videoVectorscopeImage(v: VideoVectorscope, size?: number): VideoScopeImage;
1306
+ /** One scope of a frame drawn `width` × `height` (a vectorscope is square: the smaller side). */
1307
+ declare function videoScopeImage(kind: VideoScopeKind, pixels: VideoPixels, width?: number, height?: number, options?: VideoScopeOptions): VideoScopeImage;
1308
+ /** A frame the preview drew: when, whether every picture in it had loaded, and its pixels. */
1309
+ interface VideoPreviewSnapshot {
1310
+ time: number;
1311
+ /** False while a picture is still loading or seeking (the frame shows a placeholder or a stale picture). */
1312
+ complete: boolean;
1313
+ pixels: VideoPixels;
1314
+ }
1315
+ /**
1316
+ * Where a preview's pixels can be read, for scopes and agents: a `VideoPreviewEngine` attaches its
1317
+ * canvas and says each time it draws. `VideoEditorController.previewPixels` is one, so a preview,
1318
+ * a scopes panel and the agent tools of one editor find each other without wiring.
1319
+ */
1320
+ declare class VideoPreviewPixels {
1321
+ private reader;
1322
+ private drawnAt;
1323
+ private readonly listeners;
1324
+ /** Gives the canvas to read (the latest preview wins). Returns a function that takes it away again. */
1325
+ attach(reader: () => VideoPreviewSnapshot | null): () => void;
1326
+ /** Whether a preview is attached. */
1327
+ get attached(): boolean;
1328
+ /** The preview drew the frame at `time`; `complete` is false while a picture was missing or stale. */
1329
+ drawn(time: number, complete: boolean): void;
1330
+ /** The last frame drawn, with its pixels; `null` without a preview. Throws when the canvas cannot be read. */
1331
+ read(): VideoPreviewSnapshot | null;
1332
+ /** Called after each frame the preview draws. */
1333
+ subscribe(listener: () => void): () => void;
1334
+ /**
1335
+ * The frame at `time` once it is complete: now, if the last frame drawn was it, else the next
1336
+ * complete drawing of it. Fails after `timeout` ms (default 5000).
1337
+ */
1338
+ next(time: number, timeout?: number): Promise<VideoPreviewSnapshot>;
1339
+ private emit;
1340
+ }
1341
+ /** What a scopes panel shows for the preview's latest frame (see `readVideoScopesPanel`). */
1342
+ type VideoScopesPanelReading = {
1343
+ ok: true;
1344
+ time: number;
1345
+ complete: boolean;
1346
+ images: Partial<Record<VideoScopeKind, VideoScopeImage>>;
1347
+ stats: VideoExposureStats;
1348
+ notes: string[];
1349
+ } | {
1350
+ ok: false;
1351
+ message: string;
1352
+ };
1353
+ /**
1354
+ * The preview's latest frame as a scopes panel draws it: an image per scope `kinds`, each
1355
+ * `width` × `height` (vectorscopes square), and the exposure figures. Reads at most `maxPixels`
1356
+ * (default 65 536) so it keeps up with playback. Says why when there is nothing to show.
1357
+ */
1358
+ declare function readVideoScopesPanel(feed: VideoPreviewPixels, kinds?: readonly VideoScopeKind[], options?: {
1359
+ width?: number;
1360
+ height?: number;
1361
+ maxPixels?: number;
1362
+ }): VideoScopesPanelReading;
1363
+
1041
1364
  /** Default length of an entrance or exit animation (ms). */
1042
1365
  declare const VIDEO_CLIP_ANIMATION_DURATION = 500;
1043
1366
  declare const PROPS: readonly ["opacity", "x", "y", "scale"];
@@ -1207,6 +1530,8 @@ interface VideoSvgOptions {
1207
1530
  imageFor?: (layer: VideoLayer, frame: VideoFrame) => string | null;
1208
1531
  /** Frame rate for the timecode on placeholders (default 30). */
1209
1532
  fps?: number;
1533
+ /** The loaded table of a grade's LUT `src`; drawn as an approximation (curves and a matrix). Without it LUTs are left out. */
1534
+ lutFor?: (src: string) => VideoLut | null | undefined;
1210
1535
  }
1211
1536
  /** A frame as standalone SVG: images and posters as `<image>`, video without one as a labelled box. */
1212
1537
  declare function videoFrameToSvg(frame: VideoFrame, options?: VideoSvgOptions, assets?: VideoProject['assets']): string;
@@ -1230,16 +1555,29 @@ type VideoCanvasContext = Pick<CanvasRenderingContext2D, 'save' | 'restore' | 'f
1230
1555
  lineWidth: number;
1231
1556
  strokeRect(x: number, y: number, w: number, h: number): void;
1232
1557
  };
1558
+ /** An offscreen canvas `drawVideoFrame` draws a LUT-graded layer on before running its pixels through the LUT. */
1559
+ interface VideoScratchCanvas {
1560
+ canvas: CanvasImageSource;
1561
+ ctx: VideoCanvasContext & Pick<CanvasRenderingContext2D, 'getImageData' | 'putImageData' | 'clearRect'>;
1562
+ }
1563
+ interface VideoDrawOptions {
1564
+ /** Puts an SVG filter (white balance) in the page, so the canvas's `filter: url(#id)` finds it. */
1565
+ defineSvgFilter?: (id: string, markup: string) => void;
1566
+ /** The loaded table of a grade's LUT `src`, or nothing while it loads (the layer is drawn without it). */
1567
+ lutFor?: (src: string) => VideoLut | null | undefined;
1568
+ /** A cleared-on-use offscreen canvas of the given canvas-pixel size, for LUT layers (none: LUTs are left out). */
1569
+ scratch?: (width: number, height: number) => VideoScratchCanvas | null;
1570
+ }
1233
1571
  /**
1234
1572
  * Draws a frame on a 2D canvas scaled by `scale` (canvas pixels per frame pixel). `sourceFor`
1235
1573
  * returns what to draw for a media layer (a `<video>` seeked to `layer.sourceTime`, an `<img>`,
1236
1574
  * an `ImageBitmap`…) or `null` for a placeholder box. Grades become the context's `filter`; white
1237
1575
  * balance there refers to an SVG filter, which `options.defineSvgFilter` is given to put in the page
1238
- * (without it, white balance is left out of the canvas).
1576
+ * (without it, white balance is left out of the canvas). A grade's LUT needs `options.lutFor` and
1577
+ * `options.scratch`: the layer is drawn on the scratch canvas, its pixels run through the LUT, and
1578
+ * the result is laid on the frame with the layer's opacity and blend.
1239
1579
  */
1240
- declare function drawVideoFrame(ctx: VideoCanvasContext, frame: VideoFrame, sourceFor: (layer: VideoLayer) => CanvasImageSource | null, scale?: number, options?: {
1241
- defineSvgFilter?: (id: string, markup: string) => void;
1242
- }): void;
1580
+ declare function drawVideoFrame(ctx: VideoCanvasContext, frame: VideoFrame, sourceFor: (layer: VideoLayer) => CanvasImageSource | null, scale?: number, options?: VideoDrawOptions): void;
1243
1581
 
1244
1582
  interface VideoEdlOptions {
1245
1583
  /** Track to export (default: the bottom video track, V1 in most NLEs). */
@@ -1263,6 +1601,8 @@ interface VideoFfmpegOptions {
1263
1601
  output?: string;
1264
1602
  /** The path or URL ffmpeg should open for an asset (default its `src`). */
1265
1603
  resolve?: (asset: VideoAsset) => string;
1604
+ /** The path ffmpeg's `lut3d` should read for a grade's LUT `src` (default the `src`; it must be a local file). */
1605
+ resolveLut?: (src: string) => string;
1266
1606
  /** Default `libx264`. */
1267
1607
  videoCodec?: string;
1268
1608
  /** Default `aac`. */
@@ -1354,6 +1694,10 @@ interface VideoPreviewSource {
1354
1694
  playing: boolean;
1355
1695
  };
1356
1696
  subscribe(listener: () => void): () => void;
1697
+ /** Where to publish the drawn pixels (a controller has one), for scopes and agents. */
1698
+ previewPixels?: VideoPreviewPixels;
1699
+ /** Where grades' LUTs load from (a controller has one). */
1700
+ luts?: VideoLutCache;
1357
1701
  }
1358
1702
  /** The parts of a media element the preview drives (so tests can pass fakes). */
1359
1703
  interface VideoPreviewMedia {
@@ -1363,6 +1707,8 @@ interface VideoPreviewMedia {
1363
1707
  volume: number;
1364
1708
  muted: boolean;
1365
1709
  paused: boolean;
1710
+ /** True while a seek is under way (the element still shows the old frame). */
1711
+ seeking?: boolean;
1366
1712
  readyState: number;
1367
1713
  preload: string;
1368
1714
  play(): Promise<void> | void;
@@ -1394,6 +1740,18 @@ interface VideoPreviewOptions {
1394
1740
  * it. Default: a hidden `<svg>` added to `document.body`. `null` leaves white balance out.
1395
1741
  */
1396
1742
  defineSvgFilter?: ((id: string, markup: string) => void) | null;
1743
+ /**
1744
+ * Where to publish the canvas's pixels after each frame, for scopes and the `get_video_scopes`
1745
+ * tool (default: the source's `previewPixels`). `null` publishes nothing.
1746
+ */
1747
+ pixels?: VideoPreviewPixels | null;
1748
+ /** Where grades' LUTs load from (default: the source's `luts`). Without one, LUTs are left out. */
1749
+ luts?: VideoLutCache | null;
1750
+ /**
1751
+ * Makes the offscreen canvas LUT-graded layers are drawn on (default: a `<canvas>` with
1752
+ * `willReadFrequently`). LUTs run on the CPU, so a lower `resolution` keeps playback smooth.
1753
+ */
1754
+ createScratch?: (width: number, height: number) => VideoScratchCanvas | null;
1397
1755
  }
1398
1756
  /**
1399
1757
  * Plays a project in the browser: keeps one `<video>` or `<audio>` element per playing clip in step
@@ -1413,12 +1771,21 @@ declare class VideoPreviewEngine {
1413
1771
  private destroyed;
1414
1772
  private filterHost;
1415
1773
  private readonly filters;
1774
+ private readonly detachPixels;
1775
+ private readonly pixelsTarget;
1776
+ private drawn;
1777
+ private complete;
1778
+ private readonly lutCache;
1779
+ private readonly unsubscribeLuts;
1780
+ private scratchCanvas;
1416
1781
  constructor(source: VideoPreviewSource, canvas: {
1417
1782
  width: number;
1418
1783
  height: number;
1419
1784
  clientWidth?: number;
1420
1785
  getContext?: (id: '2d') => unknown;
1421
1786
  }, options?: VideoPreviewOptions);
1787
+ /** The canvas's pixels and the frame they show, or `null` when its context cannot be read. */
1788
+ readPixels(): VideoPreviewSnapshot | null;
1422
1789
  private createMedia;
1423
1790
  private image;
1424
1791
  private entry;
@@ -1428,6 +1795,9 @@ declare class VideoPreviewEngine {
1428
1795
  private redraw;
1429
1796
  private sourceFor;
1430
1797
  private draw;
1798
+ /** A grade's LUT once loaded; while it loads (or if it fails) the frame is drawn without it and counts as incomplete. */
1799
+ private readonly lutFor;
1800
+ private readonly scratch;
1431
1801
  private readonly defineSvgFilter;
1432
1802
  /** Stops following the editor and releases every media element. */
1433
1803
  destroy(): void;
@@ -1448,6 +1818,8 @@ interface VideoEditorOptions {
1448
1818
  * loader for one (default: fetch and decode each asset's `src` with Web Audio, in a browser).
1449
1819
  */
1450
1820
  audioPeaks?: VideoAudioPeaksCache | VideoAudioPeaksLoader;
1821
+ /** Where grades' LUT files (`.cube`) come from: a shared cache, or a loader (default: `fetch` each `src`). */
1822
+ luts?: VideoLutCache | VideoLutLoader;
1451
1823
  }
1452
1824
  /** A snapshot of the editor. The same object is returned until something changes. */
1453
1825
  interface VideoEditorState {
@@ -1487,6 +1859,10 @@ declare class VideoEditorController {
1487
1859
  readonly player: AnimationPlayer;
1488
1860
  /** Sound levels per asset, loaded on demand for waveforms and agents. */
1489
1861
  readonly audioPeaks: VideoAudioPeaksCache;
1862
+ /** The pixels the preview last drew, for scopes and `get_video_scopes` (a `VideoPreviewEngine` fills it). */
1863
+ readonly previewPixels: VideoPreviewPixels;
1864
+ /** Grades' LUTs, loaded on demand for the preview, SVG frames and agents. */
1865
+ readonly luts: VideoLutCache;
1490
1866
  private project;
1491
1867
  private issues;
1492
1868
  private selection;
@@ -1587,6 +1963,14 @@ interface VideoEditorToolProviderOptions {
1587
1963
  data: string;
1588
1964
  mimeType: string;
1589
1965
  };
1966
+ /**
1967
+ * The rendered pixels of the frame at `time` (ms), for `get_video_scopes` (e.g. a frame decoded
1968
+ * by ffmpeg on a server). Default: what the editor's `<VideoPreview>` draws, through
1969
+ * `controller.previewPixels`, seeking it there and back when `time` is not the playhead.
1970
+ */
1971
+ framePixels?: (time: number) => VideoPixels | null | Promise<VideoPixels | null>;
1972
+ /** How long `get_video_scopes` waits for the preview to finish drawing a frame (ms, default 5000). */
1973
+ framePixelsTimeout?: number;
1590
1974
  }
1591
1975
  /** A project as agents see it: settings, assets, and each track's clips in order with their times. */
1592
1976
  declare function describeVideoProject(project: VideoProject): {
@@ -1840,5 +2224,10 @@ declare function videoKeyframeValueEdit(project: VideoProject, clipId: string, p
1840
2224
  * the plain value into keys), or removes the key there (the last one leaves its value plain).
1841
2225
  */
1842
2226
  declare function videoKeyframeToggleEdit(project: VideoProject, clipId: string, property: VideoKeyframeProperty, time: number): VideoEdit | null;
2227
+ /**
2228
+ * Edits giving clips a grade LUT (keeping their other grade settings), or taking it off with
2229
+ * `null`. Clips without a grade change are left out; one `controller.apply` makes it one undo step.
2230
+ */
2231
+ declare function videoLutEdits(project: VideoProject, clips: readonly string[], lut: VideoGradeLut | null): VideoEdit[];
1843
2232
 
1844
- 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 VideoSpeedSegment, 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, checkVideoTimeRemap, 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, parseVideoTimeRemap, 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, videoClipSourceTime, videoClipSpeed, videoClipSpeedAt, videoClipTint, videoClipWaveform, videoClipWaveformPath, videoClipsAt, videoContactSheetSvg, videoDragLabel, videoDropTracks, videoEaseBezier, videoEaseProgress, videoFadeCurveGain, videoFrameAt, videoFrameDuration, videoFrameToSvg, videoFrames, videoFreezeFrameEdit, videoGradeCssFilter, videoGradeFfmpegFilters, videoGradeGainsFilterId, videoGradePreset, videoGradeStepMatrix, videoGradeStepSvgValues, videoGradeSteps, videoGradeSvgDefs, videoGradeSvgFilter, videoHourFrames, videoIrisRadius, videoIssueKey, videoKeyframeBreakpoints, videoKeyframeFfmpegExpr, videoKeyframeRows, videoKeyframeToggleEdit, videoKeyframeValueEdit, videoKeysOf, videoOverlap, videoPeakDb, videoProjectDuration, videoProjectSvg, videoRemoveRangesEdits, videoRulerTicks, videoSlowMotionRamp, videoSnapPoints, videoSpeedRampEdit, videoSpeedRampKeys, videoTextStyle, videoTimeRemapBreakpoints, videoTimeRemapSpan, videoTimecodeFrames, videoTimelineTranscript, videoTitleFrame, videoTrackSyncLocked, videoTranscriptEdit, videoTranscriptTrack, videoTransformAt, videoTransitionAudioCurve, videoTransitionEase, videoTransitionHasDirection, videoValueAt, videoWaveformPath, videoWipeRect, videoWordAt, videoWordsRange };
2233
+ 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_LUT_MAX_SIZE, VIDEO_PEAK_BLOCK, VIDEO_PLACEMENT_MODES, VIDEO_SCOPE_KINDS, VIDEO_TIME_EPSILON, VIDEO_TRANSFORM_PROPERTIES, VIDEO_TRANSITION_LABELS, VIDEO_TRANSITION_TYPES, VIDEO_VECTORSCOPE_TARGETS, 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 VideoDrawOptions, type VideoEase, type VideoEdit, type VideoEditOp, type VideoEditOutcome, type VideoEditResult, VideoEditorController, type VideoEditorOptions, type VideoEditorState, type VideoEditorToolProviderOptions, type VideoEdlOptions, type VideoExposureOptions, type VideoExposureStats, type VideoFadeCurve, type VideoFfmpegExport, type VideoFfmpegOptions, type VideoFit, type VideoFrame, type VideoGap, type VideoGrade, type VideoGradeControl, type VideoGradeLut, type VideoGradePreset, type VideoGradeSetting, type VideoGradeStep, type VideoHistogram, type VideoIssue, type VideoIssueCode, type VideoIssueSeverity, type VideoKey, type VideoKeyframeProperty, type VideoKeyframeRow, type VideoKeyframes, type VideoLayer, type VideoLoudnessMeasurement, type VideoLoudnessTarget, type VideoLut, VideoLutCache, type VideoLutLoader, type VideoLutSvgApproximation, type VideoMarker, type VideoMediaClip, type VideoMediaProbe, type VideoPauseOptions, type VideoPixels, type VideoPlacementMode, VideoPreviewEngine, type VideoPreviewImage, type VideoPreviewMedia, type VideoPreviewOptions, VideoPreviewPixels, type VideoPreviewSnapshot, type VideoPreviewSource, type VideoProject, type VideoRect, type VideoRulerTick, type VideoScopeImage, type VideoScopeKind, type VideoScopeOptions, type VideoScopeSummary, type VideoScopesPanelReading, type VideoScratchCanvas, type VideoSilenceOptions, type VideoSnapOptions, type VideoSpeedSegment, type VideoSvgOptions, type VideoTextClip, type VideoTimelineWord, type VideoTrack, type VideoTrackKind, type VideoTranscriptRange, type VideoTranscriptWord, type VideoTransform, type VideoTransition, type VideoTransitionType, type VideoVectorscope, type VideoWaveform, type VideoWaveformMode, type VideoWipeDirection, allVideoClipIds, applyVideoEdits, applyVideoGrade, applyVideoLut, applyVideoLutToPixels, buildVideoAudioPeaks, checkVideoProject, checkVideoTimeRemap, createVideoEditorToolProvider, createVideoProject, decodeVideoAudioPeaks, describeVideoProject, drawVideoFrame, ffmpegFilterValue, findVideoAudioSilences, findVideoClip, findVideoFillers, findVideoGaps, findVideoTranscriptPauses, findVideoTranscriptText, formatVideoSeconds, formatVideoTimecode, formatVideoTimecodeFrames, isVideoDropFrameRate, isVideoKeyframes, mergeVideoRanges, nextFreeVideoSlot, normalizeVideoGrade, normalizeVideoGradeLut, normalizeVideoWord, parseVideoAnimatable, parseVideoAsset, parseVideoClip, parseVideoClipAnimation, parseVideoCubeLut, parseVideoGrade, parseVideoGradeLut, parseVideoKeyframes, parseVideoLoudnessMeasurement, parseVideoMarker, parseVideoProject, parseVideoTimeRemap, parseVideoTrack, parseVideoTranscript, parseVideoTranscriptWords, parseVideoTransform, parseVideoTransition, placeVideoRect, planVideoClipDrag, probeVideoMedia, readVideoScopesPanel, removeVideoKey, retimeVideoAnimatable, setVideoKey, snapToVideoFrame, snapVideoTime, sortVideoKeys, sortedVideoClips, splitVideoAnimatable, summarizeVideoScopes, toVideoEdl, toVideoFfmpeg, toVideoLoudnessMeasure, videoAssetDropEdit, videoAssetHasSound, videoAssetKindOf, videoAssetMap, videoAudioLevels, videoAudioPeakRange, videoAudioPeakSpans, videoAudioPeaksDuration, videoChroma, videoClipAfter, videoClipAnimated, videoClipAnimationProperties, videoClipAnimationSpans, videoClipBefore, videoClipEnd, videoClipHandles, videoClipKeyframes, videoClipLabel, videoClipOverhang, videoClipShowsWaveform, videoClipSoundGain, videoClipSourceRange, videoClipSourceTime, videoClipSpeed, videoClipSpeedAt, videoClipTint, videoClipWaveform, videoClipWaveformPath, videoClipsAt, videoContactSheetSvg, videoDragLabel, videoDropTracks, videoEaseBezier, videoEaseProgress, videoExposureNotes, videoExposureStats, videoFadeCurveGain, videoFrameAt, videoFrameDuration, videoFrameToSvg, videoFrames, videoFreezeFrameEdit, videoGradeCssFilter, videoGradeFfmpegFilters, videoGradeGainsFilterId, videoGradeLook, videoGradePreset, videoGradeStepMatrix, videoGradeStepSvgValues, videoGradeSteps, videoGradeSvgDefs, videoGradeSvgFilter, videoHistogram, videoHistogramImage, videoHourFrames, videoIrisRadius, videoIssueKey, videoKeyframeBreakpoints, videoKeyframeFfmpegExpr, videoKeyframeRows, videoKeyframeToggleEdit, videoKeyframeValueEdit, videoKeysOf, videoLuma, videoLumaWaveform, videoLutEdits, videoLutFromFunction, videoLutSvgApproximation, videoLutSvgPrimitives, videoLutToCube, videoOverlap, videoPeakDb, videoProjectDuration, videoProjectSvg, videoRemoveRangesEdits, videoRulerTicks, videoScopeImage, videoSlowMotionRamp, videoSnapPoints, videoSpeedRampEdit, videoSpeedRampKeys, videoTextStyle, videoTimeRemapBreakpoints, videoTimeRemapSpan, videoTimecodeFrames, videoTimelineTranscript, videoTitleFrame, videoTrackSyncLocked, videoTranscriptEdit, videoTranscriptTrack, videoTransformAt, videoTransitionAudioCurve, videoTransitionEase, videoTransitionHasDirection, videoValueAt, videoVectorscope, videoVectorscopeAngle, videoVectorscopeImage, videoVectorscopePoint, videoWaveformImage, videoWaveformPath, videoWipeRect, videoWordAt, videoWordsRange };