@cutcraft/player 0.1.0 → 0.2.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.
@@ -1,55 +1,5 @@
1
- import { d as DrawRect, m as Matrix2D, r as ClipRect } from "./backdrop-BqrzCzTB.mjs";
2
- import { AssetEntry, AssetManifest, EASING_FN, FitMode, Placement, ResolvedState, ResolvedTrack } from "@cutcraft/kit";
1
+ import { AssetEntry, AssetManifest, DeclaredFont, EASING_FN, FitMode, LayerClock, Placement, ResolvedState, ResolvedTrack, Transform } from "@cutcraft/kit";
3
2
  import { Input, VideoSample } from "mediabunny";
4
- /** Seconds before a clip starts at which its decoder is mounted. */
5
- declare const MOUNT_AHEAD_S = 2;
6
- /** Seconds after a clip ends for which its decoder is kept. */
7
- declare const UNMOUNT_BEHIND_S = 0.5;
8
- /** Seconds an unreferenced mediabunny Input stays open before it is disposed. */
9
- declare const INPUT_IDLE_CLOSE_S = 10;
10
- /** Hard cap on open Inputs; idle ones are evicted LRU first. */
11
- declare const MAX_OPEN_INPUTS = 6;
12
- /** Decoded frames a clip decoder keeps queued ahead of the play head. */
13
- declare const QUEUE_TARGET = 8;
14
- declare const QUEUE_MAX = 10;
15
- /** Effective speed (clip speed × rate) above which frames are fetched by seek per tick instead of streamed. */
16
- declare const SEEK_MODE_SPEED = 4;
17
- /** Reverse playback pre-decodes this window behind the cursor. */
18
- declare const REVERSE_WINDOW_S = 1;
19
- declare const REVERSE_WINDOW_FRAMES = 16;
20
- /** Longest wait for a frame in `wait` mode (seek, export) before drawing without it. */
21
- declare const FRAME_WAIT_MS = 250;
22
- /** Audio scheduler period and horizon. */
23
- declare const SCHEDULER_MS = 100;
24
- declare const LOOKAHEAD_S = 0.2;
25
- /** Source ranges longer than twice this are decoded in chunks of this length. */
26
- declare const AUDIO_CHUNK_S = 30;
27
- /** LRU cap, in decoded seconds, on cached PCM. */
28
- declare const AUDIO_CACHE_S = 600;
29
- /** Pre-decode window on play, and how long play() waits for it. */
30
- declare const AUDIO_PRIME_S = 0.5;
31
- declare const PLAY_PRIME_TIMEOUT_MS = 500;
32
- /** Ducking defaults. */
33
- declare const DUCK_ATTACK_S = 0.1;
34
- declare const DUCK_RELEASE_S = 0.3;
35
- /** Sampling step for multiplied gain ramps. */
36
- declare const ENVELOPE_STEP_S = 0.05;
37
- /** Playback rate clamp. */
38
- declare const MIN_RATE = 0.25;
39
- declare const MAX_RATE = 4;
40
- /** Quiet time after the last setState before a paused preview fetches its exact frame. */
41
- declare const SETTLE_MS = 120;
42
- /** Tolerance when rounding a time to a frame index. */
43
- declare const FRAME_EPS = 0.000001;
44
- /**
45
- * Container timestamps are often rounded to the millisecond, so the frame for
46
- * the exact time n/fps can sit a fraction of a millisecond after it. A frame
47
- * is picked when its timestamp is at most this far past the wanted time.
48
- */
49
- declare const PICK_EPS = 0.001;
50
- /** Warn once per key. Tests capture warnings with `captureWarnings`. */
51
- declare function devWarn(key: string, message: string): void;
52
- declare function captureWarnings(fn: ((message: string) => void) | null): void;
53
3
  interface PlayerErrorEvent {
54
4
  readonly id?: string;
55
5
  readonly asset?: string;
@@ -85,7 +35,10 @@ interface PlayerEvents {
85
35
  type Ctx2D = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
86
36
  type AnyCanvas = HTMLCanvasElement | OffscreenCanvas;
87
37
  type CreateCanvas = (width: number, height: number) => AnyCanvas;
88
- /** Where an asset's bytes come from. `path` is a file on disk, for the Node renderer; browsers use `blob` or `url`. */
38
+ /**
39
+ * Where an asset's bytes come from. The player reads `blob` and `url`; `path` is a file on disk, which a Node host (the
40
+ * export's server) serves to the page as a URL.
41
+ */
89
42
  type MediaHandle = {
90
43
  readonly kind: "blob";
91
44
  readonly blob: Blob;
@@ -118,16 +71,6 @@ interface Frame {
118
71
  w: number;
119
72
  h: number;
120
73
  }): void;
121
- /**
122
- * Optional fast path for a picture that covers the whole `width`×`height` canvas, untransformed, opaque and
123
- * normally blended: replace the canvas content with it and return true, or return false to be drawn with `draw`.
124
- */
125
- paintFull?(ctx: Ctx2D, width: number, height: number): boolean;
126
- /**
127
- * Makes the picture drawable, for a frame that defers work until it is drawn (the Node renderer converts decoded
128
- * pictures to RGBA only then). The compositor awaits it before painting the frame.
129
- */
130
- prepare?(): Promise<void>;
131
74
  /** A copy that outlives the source's pools and the original's `close()`. */
132
75
  retain(): Frame;
133
76
  close(): void;
@@ -187,155 +130,6 @@ interface AudioOutput {
187
130
  setMaster(gain: number): void;
188
131
  resume(): Promise<void>;
189
132
  }
190
- declare function ease(name: string | undefined, x: number): number;
191
- /**
192
- * The keyframed value of `property` at element-relative time `rel`. Holds
193
- * before the first and after the last key; the segment between two keys uses
194
- * the easing of the key it leaves. Non-numeric values step.
195
- */
196
- declare function keyframedValue<T>(children: readonly Placement[], property: string, rel: number, fallback: T): T;
197
- declare function hasKeyframes(children: readonly Placement[], property: string): boolean;
198
- interface FilterResult {
199
- readonly filter: string;
200
- readonly unsupported: readonly string[];
201
- }
202
- /** A single canvas/CSS `filter` string for an element's effect and colour-grade children at element-relative `rel`; unsupported types are listed. */
203
- declare function filterString(children: readonly Placement[], elementId: string, rel: number): FilterResult;
204
- type PostEffect = {
205
- readonly type: "vignette";
206
- readonly amount: number;
207
- } | {
208
- readonly type: "grain";
209
- readonly amount: number;
210
- readonly seed: number;
211
- };
212
- /** Vignette and grain, in order, with `amount` on 0..1; grain is seeded by the frame, so a frame always looks the same. */
213
- declare function postEffects(children: readonly Placement[], frame: number, rel: number): PostEffect[] | undefined;
214
- interface MaskSpec {
215
- readonly shape?: Record<string, unknown> | undefined;
216
- readonly path?: {
217
- points: {
218
- x: number;
219
- y: number;
220
- handleIn?: {
221
- x: number;
222
- y: number;
223
- };
224
- handleOut?: {
225
- x: number;
226
- y: number;
227
- };
228
- }[];
229
- closed: boolean;
230
- } | undefined;
231
- readonly feather: number;
232
- readonly inverted: boolean;
233
- readonly opacity: number;
234
- }
235
- interface DrawOp {
236
- readonly id: string;
237
- readonly kind: "video" | "image" | "nested" | "error" | "adjustment";
238
- readonly asset?: string;
239
- readonly sourceTime?: number;
240
- readonly nested?: {
241
- readonly state: ResolvedState;
242
- readonly time: number;
243
- };
244
- readonly rect: DrawRect;
245
- readonly matrix: Matrix2D;
246
- readonly crop?: DrawRect;
247
- /** Dimensions used to express crop pixels; decoded proxies can have another resolution. */
248
- readonly cropReference?: {
249
- readonly width: number;
250
- readonly height: number;
251
- };
252
- readonly fit: FitMode;
253
- readonly opacity: number;
254
- readonly blend: GlobalCompositeOperation;
255
- readonly filter: string;
256
- readonly borderRadius: number;
257
- readonly mask?: MaskSpec;
258
- /** The part shown, in composition pixels (a wipe). */
259
- readonly clip?: readonly ClipRect[];
260
- /** Vignette and grain, drawn over the element's own pixels. */
261
- readonly post?: readonly PostEffect[];
262
- }
263
- /** A composition background gradient, as the schema writes it. CSS angles: 0 points up, 180 (the default) runs down. */
264
- interface BackgroundGradient {
265
- readonly type: "linear" | "radial" | "conic";
266
- readonly angle?: number;
267
- readonly center?: {
268
- readonly x: number;
269
- readonly y: number;
270
- };
271
- readonly stops: readonly {
272
- readonly offset: number;
273
- readonly color: string;
274
- readonly opacity?: number;
275
- }[];
276
- }
277
- interface FramePlan {
278
- readonly time: number;
279
- readonly frame: number;
280
- readonly background: string;
281
- /** A gradient that fills the frame instead of `background` (which is then its first colour). */
282
- readonly backgroundGradient?: BackgroundGradient;
283
- /** The footage goes over a transparent ground: overlays beneath it (see `backdropTracks`) and the background are drawn under the canvas. */
284
- readonly clear?: true;
285
- /** `background.mode: "blur"`: this op's picture, blurred to cover the frame, goes under everything. */
286
- readonly backgroundBlur?: {
287
- readonly id: string;
288
- };
289
- readonly ops: readonly DrawOp[];
290
- readonly warnings: readonly string[];
291
- }
292
- type ResolveNested = (p: Placement) => ResolvedState | null;
293
- declare function blendOf(value: unknown): GlobalCompositeOperation;
294
- /**
295
- * Everything the painter needs to draw composition time `t`, in draw order.
296
- * Pure: the same state and time give a deep-equal plan. DOM-rendered kinds
297
- * (title, shape, svg, sticker, layer, captions) are not in it; the DOM layer
298
- * reads `visiblePlacements` itself.
299
- */
300
- declare function buildFramePlan(state: ResolvedState, t: number, resolveNested?: ResolveNested): FramePlan;
301
- /** The composition's background as the painter draws it: a colour, or a gradient (whose first colour is `background`). */
302
- declare function compositionBackground(state: ResolvedState): {
303
- background: string;
304
- backgroundGradient?: BackgroundGradient;
305
- blur: boolean;
306
- };
307
- /** A gain breakpoint in composition seconds. */
308
- type GainPoint = readonly [t: number, value: number];
309
- interface AudioOccurrence {
310
- readonly id: string;
311
- readonly asset: string;
312
- readonly chunk: number;
313
- /** Composition range of this chunk, unclipped; the engine clips to "now". */
314
- readonly compStart: number;
315
- readonly compEnd: number;
316
- /** Source seconds of the chunk's buffer; stable across windows so decoded PCM caches. */
317
- readonly bufferFrom: number;
318
- readonly bufferTo: number;
319
- /** Placement speed; the engine multiplies in the transport rate. Ignored when `rate` is set. */
320
- readonly speed: number;
321
- /** Speed-key ramp: buffer seconds per composition second, piecewise linear over [compStart, compEnd]. */
322
- readonly rate?: readonly GainPoint[];
323
- readonly gain: readonly GainPoint[];
324
- readonly pan?: readonly GainPoint[];
325
- /** The buffer plays backwards: the engine reverses the decoded PCM. */
326
- readonly reverse?: true;
327
- }
328
- /** Every audio-bearing chunk that overlaps [from, to). */
329
- declare function buildAudioPlan(state: ResolvedState, from: number, to: number, resolveNested?: ResolveNested): AudioOccurrence[];
330
- /**
331
- * Gain over [winFrom, winTo] in composition seconds: volume × keyframed
332
- * `audio.volume` × fades × automation × ducking. The factors are multiplied
333
- * and sampled at their breakpoints plus a fixed step inside ramps, so the
334
- * product stays close to piecewise linear.
335
- */
336
- declare function buildGainEnvelope(p: Placement, track: ResolvedTrack, state: ResolvedState, winFrom: number, winTo: number): GainPoint[];
337
- /** Composition intervals where sound plays on the track `under` names by id, else on the tracks of that role; silent assets and muted clips do not duck. */
338
- declare function duckIntervals(state: ResolvedState, under: string, exceptId: string): [number, number][];
339
133
  declare class ManualClock implements Clock {
340
134
  private t;
341
135
  now(): number;
@@ -345,65 +139,52 @@ declare class ManualClock implements Clock {
345
139
  declare class PerformanceClock implements Clock {
346
140
  now(): number;
347
141
  }
348
- /** A resolver over a map of asset id → Blob or URL. */
349
- declare function fromMap(map: Readonly<Record<string, Blob | string>>): MediaResolver;
350
- declare function toResolver(media: MediaResolver | Readonly<Record<string, Blob | string>>): MediaResolver;
351
- declare function defaultCreateCanvas(width: number, height: number): AnyCanvas;
352
- type Crop$1 = {
353
- x: number;
354
- y: number;
355
- w: number;
356
- h: number;
357
- };
358
- /** A frame backed by an image we own (canvas or bitmap); `retain` is free. */
359
- declare class ImageFrame implements Frame {
360
- private readonly image;
361
- readonly timestamp: number;
362
- readonly duration: number;
363
- private readonly owned;
364
- constructor(image: CanvasImageSource & {
365
- width: number;
366
- height: number;
367
- }, timestamp: number, duration: number, owned: boolean);
368
- get width(): number;
369
- get height(): number;
370
- draw(ctx: Ctx2D, dx: number, dy: number, dw: number, dh: number, crop?: Crop$1): void;
371
- retain(): Frame;
372
- close(): void;
373
- }
374
- /** Copies any frame into a canvas we own. */
375
- declare function copyFrame(frame: Frame, createCanvas: CreateCanvas): Frame;
376
- /** Still images: one bitmap, returned for every time. */
377
- declare class ImageFrameSource implements FrameSource {
378
- private readonly load;
379
- private bitmap;
380
- constructor(load: () => Promise<ImageBitmap | HTMLImageElement>);
381
- open(): Promise<FrameSourceInfo>;
382
- frameAt(): Promise<Frame | null>;
383
- stream(): AsyncGenerator<Frame, void, unknown>;
384
- close(): void;
385
- private frame;
386
- }
387
- /** Draws a grey box with a label; used for missing or undecodable assets. */
388
- declare class ErrorFrame implements Frame {
389
- readonly width: number;
390
- readonly height: number;
391
- private readonly label;
392
- readonly timestamp = 0;
393
- readonly duration: number;
394
- constructor(width: number, height: number, label: string);
395
- draw(ctx: Ctx2D, dx: number, dy: number, dw: number, dh: number): void;
396
- retain(): Frame;
397
- close(): void;
398
- }
399
- declare class ErrorFrameSource implements FrameSource {
400
- private readonly frame;
401
- constructor(label: string, width?: number, height?: number);
402
- open(): Promise<FrameSourceInfo>;
403
- frameAt(): Promise<Frame | null>;
404
- stream(): AsyncGenerator<Frame, void, unknown>;
405
- close(): void;
406
- }
142
+ /** Seconds before a clip starts at which its decoder is mounted. */
143
+ declare const MOUNT_AHEAD_S = 2;
144
+ /** Seconds after a clip ends for which its decoder is kept. */
145
+ declare const UNMOUNT_BEHIND_S = 0.5;
146
+ /** Seconds an unreferenced mediabunny Input stays open before it is disposed. */
147
+ declare const INPUT_IDLE_CLOSE_S = 10;
148
+ /** Hard cap on open Inputs; idle ones are evicted LRU first. */
149
+ declare const MAX_OPEN_INPUTS = 6;
150
+ /** Decoded frames a clip decoder keeps queued ahead of the play head. */
151
+ declare const QUEUE_TARGET = 8;
152
+ declare const QUEUE_MAX = 10;
153
+ /** Effective speed (clip speed × rate) above which frames are fetched by seek per tick instead of streamed. */
154
+ declare const SEEK_MODE_SPEED = 4;
155
+ /** Reverse playback pre-decodes this window behind the cursor. */
156
+ declare const REVERSE_WINDOW_S = 1;
157
+ declare const REVERSE_WINDOW_FRAMES = 16;
158
+ /** Longest wait for a frame in `wait` mode (seek, export) before drawing without it. */
159
+ declare const FRAME_WAIT_MS = 250;
160
+ /** Audio scheduler period and horizon. */
161
+ declare const SCHEDULER_MS = 100;
162
+ declare const LOOKAHEAD_S = 0.2;
163
+ /** Source ranges longer than twice this are decoded in chunks of this length. */
164
+ declare const AUDIO_CHUNK_S = 30;
165
+ /** LRU cap, in decoded seconds, on cached PCM. */
166
+ declare const AUDIO_CACHE_S = 600;
167
+ /** Pre-decode window on play, and how long play() waits for it. */
168
+ declare const AUDIO_PRIME_S = 0.5;
169
+ declare const PLAY_PRIME_TIMEOUT_MS = 500;
170
+ /** Ducking defaults. */
171
+ declare const DUCK_ATTACK_S = 0.1;
172
+ declare const DUCK_RELEASE_S = 0.3;
173
+ /** Sampling step for multiplied gain ramps. */
174
+ declare const ENVELOPE_STEP_S = 0.05;
175
+ /** Playback rate clamp. */
176
+ declare const MIN_RATE = 0.25;
177
+ declare const MAX_RATE = 4;
178
+ /** Quiet time after the last setState before a paused preview fetches its exact frame. */
179
+ declare const SETTLE_MS = 120;
180
+ /** Tolerance when rounding a time to a frame index. */
181
+ declare const FRAME_EPS = 0.000001;
182
+ /**
183
+ * Container timestamps are often rounded to the millisecond, so the frame for
184
+ * the exact time n/fps can sit a fraction of a millisecond after it. A frame
185
+ * is picked when its timestamp is at most this far past the wanted time.
186
+ */
187
+ declare const PICK_EPS = 0.001;
407
188
  interface AssetSourceDeps {
408
189
  readonly media: MediaResolver;
409
190
  readonly manifest: AssetManifest;
@@ -527,6 +308,80 @@ declare class DecoderPool {
527
308
  dispose(): void;
528
309
  private unmount;
529
310
  }
311
+ /** A face to add to the page's fonts, from a URL or the file's bytes. */
312
+ interface FontFaceSource {
313
+ readonly family: string;
314
+ readonly weight?: number;
315
+ readonly style?: "normal" | "italic";
316
+ readonly source: string | ArrayBuffer;
317
+ }
318
+ /**
319
+ * Adds faces to `document.fonts` and resolves once every one has loaded. A URL source loads from that URL; bytes load as
320
+ * given. Does nothing where there is no `FontFace` (Node, tests).
321
+ */
322
+ declare function addFontFaces(faces: readonly FontFaceSource[]): Promise<void>;
323
+ /**
324
+ * Loads the faces a file declares (`state.fonts`) into the page: an `asset:` face is asked of `media` as an asset is,
325
+ * a Google face loads from Google's stylesheet. Resolves once all have loaded; a face that fails is reported through
326
+ * `onError` and the rest load. Does nothing where there is no `FontFace` (Node, tests).
327
+ */
328
+ declare function loadFileFonts(faces: readonly DeclaredFont[], media: MediaResolver, onError: (family: string, error: Error) => void): Promise<void>;
329
+ declare function defaultCreateCanvas(width: number, height: number): AnyCanvas;
330
+ type Crop$1 = {
331
+ x: number;
332
+ y: number;
333
+ w: number;
334
+ h: number;
335
+ };
336
+ /** A frame backed by an image we own (canvas or bitmap); `retain` is free. */
337
+ declare class ImageFrame implements Frame {
338
+ private readonly image;
339
+ readonly timestamp: number;
340
+ readonly duration: number;
341
+ private readonly owned;
342
+ constructor(image: CanvasImageSource & {
343
+ width: number;
344
+ height: number;
345
+ }, timestamp: number, duration: number, owned: boolean);
346
+ get width(): number;
347
+ get height(): number;
348
+ draw(ctx: Ctx2D, dx: number, dy: number, dw: number, dh: number, crop?: Crop$1): void;
349
+ retain(): Frame;
350
+ close(): void;
351
+ }
352
+ /** Copies any frame into a canvas we own. */
353
+ declare function copyFrame(frame: Frame, createCanvas: CreateCanvas): Frame;
354
+ /** Still images: one bitmap, returned for every time. */
355
+ declare class ImageFrameSource implements FrameSource {
356
+ private readonly load;
357
+ private bitmap;
358
+ constructor(load: () => Promise<ImageBitmap | HTMLImageElement>);
359
+ open(): Promise<FrameSourceInfo>;
360
+ frameAt(): Promise<Frame | null>;
361
+ stream(): AsyncGenerator<Frame, void, unknown>;
362
+ close(): void;
363
+ private frame;
364
+ }
365
+ /** Draws a grey box with a label; used for missing or undecodable assets. */
366
+ declare class ErrorFrame implements Frame {
367
+ readonly width: number;
368
+ readonly height: number;
369
+ private readonly label;
370
+ readonly timestamp = 0;
371
+ readonly duration: number;
372
+ constructor(width: number, height: number, label: string);
373
+ draw(ctx: Ctx2D, dx: number, dy: number, dw: number, dh: number): void;
374
+ retain(): Frame;
375
+ close(): void;
376
+ }
377
+ declare class ErrorFrameSource implements FrameSource {
378
+ private readonly frame;
379
+ constructor(label: string, width?: number, height?: number);
380
+ open(): Promise<FrameSourceInfo>;
381
+ frameAt(): Promise<Frame | null>;
382
+ stream(): AsyncGenerator<Frame, void, unknown>;
383
+ close(): void;
384
+ }
530
385
  /** One mediabunny `Input` per asset, shared by the video and audio sources of that asset. */
531
386
  declare class MediabunnyInputs {
532
387
  private readonly entries;
@@ -535,6 +390,23 @@ declare class MediabunnyInputs {
535
390
  get openCount(): number;
536
391
  dispose(): void;
537
392
  }
393
+ /** PCM ranges of one audio track, decoded on demand into AudioBuffers of the track's sample rate. */
394
+ declare class MediabunnyAudioSource implements AudioSource {
395
+ private readonly assetId;
396
+ private readonly handle;
397
+ private readonly inputs;
398
+ private readonly context;
399
+ private readonly trackIndex;
400
+ private input;
401
+ private sink;
402
+ private sampleRate;
403
+ private channels;
404
+ constructor(assetId: string, handle: MediaHandle, inputs: MediabunnyInputs, context: BaseAudioContext, trackIndex?: number);
405
+ open(): Promise<AudioSourceInfo>;
406
+ range(from: number, to: number): Promise<AudioBuffer>;
407
+ close(): void;
408
+ }
409
+ declare function mediabunnyAudioSourceFactory(inputs: MediabunnyInputs): AudioSourceFactory;
538
410
  type Crop = {
539
411
  x: number;
540
412
  y: number;
@@ -554,26 +426,17 @@ declare class SampleFrame implements Frame {
554
426
  retain(): Frame;
555
427
  close(): void;
556
428
  }
557
- /** How a host customises decoding: the Node renderer converts samples itself and decodes in software. */
558
- interface FrameSourceHooks {
559
- /** Turns a decoded sample into a frame; may convert eagerly (the sample is closed by the frame). */
560
- readonly makeFrame?: (sample: VideoSample) => Promise<Frame> | Frame;
561
- /** Loads a still image asset. */
562
- readonly loadImage?: (handle: MediaHandle) => Promise<ImageBitmap | HTMLImageElement>;
563
- readonly hardwareAcceleration?: "no-preference" | "prefer-hardware" | "prefer-software";
564
- }
565
429
  /** Frames of one video asset through a shared `VideoSampleSink`. */
566
430
  declare class MediabunnyFrameSource implements FrameSource {
567
431
  private readonly assetId;
568
432
  private readonly handle;
569
433
  private readonly inputs;
570
434
  private readonly createCanvas;
571
- private readonly hooks;
572
435
  private input;
573
436
  private track;
574
437
  private sink;
575
438
  private stillSink;
576
- constructor(assetId: string, handle: MediaHandle, inputs: MediabunnyInputs, createCanvas: CreateCanvas, hooks?: FrameSourceHooks);
439
+ constructor(assetId: string, handle: MediaHandle, inputs: MediabunnyInputs, createCanvas: CreateCanvas);
577
440
  private wrap;
578
441
  open(): Promise<FrameSourceInfo>;
579
442
  frameAt(sourceTime: number): Promise<Frame | null>;
@@ -582,75 +445,325 @@ declare class MediabunnyFrameSource implements FrameSource {
582
445
  still(sourceTime: number): Promise<Frame | null>;
583
446
  close(): void;
584
447
  }
585
- declare function mediabunnyFrameSourceFactory(inputs: MediabunnyInputs, createCanvas: CreateCanvas, hooks?: FrameSourceHooks): FrameSourceFactory;
586
- /** PCM ranges of one audio track, decoded on demand into AudioBuffers of the track's sample rate. */
587
- declare class MediabunnyAudioSource implements AudioSource {
588
- private readonly assetId;
589
- private readonly handle;
590
- private readonly inputs;
591
- private readonly context;
592
- private readonly trackIndex;
593
- private input;
594
- private track;
595
- private sink;
596
- private sampleRate;
597
- private channels;
598
- constructor(assetId: string, handle: MediaHandle, inputs: MediabunnyInputs, context: BaseAudioContext, trackIndex?: number);
599
- open(): Promise<AudioSourceInfo>;
600
- range(from: number, to: number): Promise<AudioBuffer>;
601
- close(): void;
448
+ declare function mediabunnyFrameSourceFactory(inputs: MediabunnyInputs, createCanvas: CreateCanvas): FrameSourceFactory;
449
+ /** A resolver over a map of asset id → Blob or URL. */
450
+ declare function fromMap(map: Readonly<Record<string, Blob | string>>): MediaResolver;
451
+ declare function toResolver(media: MediaResolver | Readonly<Record<string, Blob | string>>): MediaResolver;
452
+ interface FilterResult {
453
+ readonly filter: string;
454
+ readonly unsupported: readonly string[];
602
455
  }
603
- declare function mediabunnyAudioSourceFactory(inputs: MediabunnyInputs): AudioSourceFactory;
456
+ type Params = Readonly<Record<string, unknown>>;
457
+ /** An effect's params with its keyframed ones (`effect.<id>.<param>` keyframes on the element) evaluated at element-relative `rel`. */
458
+ declare function paramsAt(children: readonly Placement[], effect: Placement, rel: number): Params;
459
+ /** A single canvas/CSS `filter` string for an element's effect and colour-grade children at element-relative `rel`; unsupported types are listed. */
460
+ declare function filterString(children: readonly Placement[], elementId: string, rel: number,
461
+ /** Effect types the file declares (`defineEffect()`), drawn as shaders rather than filters. */
462
+ declared?: ReadonlySet<string>): FilterResult;
463
+ type PostEffect = {
464
+ readonly type: "vignette";
465
+ readonly amount: number;
466
+ } | {
467
+ readonly type: "grain";
468
+ readonly amount: number;
469
+ readonly seed: number;
470
+ };
471
+ /** Vignette and grain, in order, with `amount` on 0..1; grain is seeded by the frame, so a frame always looks the same. */
472
+ declare function postEffects(children: readonly Placement[], frame: number, rel: number): PostEffect[] | undefined;
473
+ interface DrawRect {
474
+ readonly x: number;
475
+ readonly y: number;
476
+ readonly w: number;
477
+ readonly h: number;
478
+ }
479
+ /** Row-major 2D affine matrix in the canvas/CSS `matrix(a, b, c, d, e, f)` convention. */
480
+ interface Matrix2D {
481
+ readonly a: number;
482
+ readonly b: number;
483
+ readonly c: number;
484
+ readonly d: number;
485
+ readonly e: number;
486
+ readonly f: number;
487
+ }
488
+ interface Layout {
489
+ /** Where the element lands in composition pixels before its transform. */
490
+ readonly rect: DrawRect;
491
+ /** Maps local element coordinates (0..rect.w, 0..rect.h) to composition coordinates. */
492
+ readonly matrix: Matrix2D;
493
+ /** Source sub-rectangle in source pixels, when cropped. */
494
+ readonly crop?: DrawRect;
495
+ readonly opacity: number;
496
+ }
497
+ declare const IDENTITY: Matrix2D;
498
+ declare function multiply(m: Matrix2D, n: Matrix2D): Matrix2D;
499
+ declare const translate: (x: number, y: number) => Matrix2D;
500
+ declare const scaleM: (sx: number, sy: number) => Matrix2D;
501
+ declare function rotate(deg: number): Matrix2D;
502
+ declare function matrixToCss(m: Matrix2D): string;
503
+ interface Box {
504
+ readonly width: number;
505
+ readonly height: number;
506
+ }
507
+ /** The fitted rectangle of a source inside the composition, centred. */
508
+ declare function fitRect(comp: Box, src: Box, fit: FitMode): DrawRect;
604
509
  /**
605
- * Trace the mask outline onto the context's current path, in local element
606
- * pixels. Shape coordinates are fractions of the element box; bezier paths
607
- * are in pixels with handles. Returns false when the spec has no usable shape.
510
+ * Lay out a source of `src` pixels in the composition: crop, fit, then the
511
+ * element transform (position offset, scale, rotation about the anchor).
608
512
  */
609
- declare function traceMask(ctx: Ctx2D, mask: MaskSpec, rect: DrawRect): boolean;
610
- declare function roundedRect(ctx: Ctx2D, x: number, y: number, w: number, h: number, r: number): void;
611
- interface PaintInputs {
612
- readonly frames: ReadonlyMap<string, Frame | null>;
613
- readonly nested: ReadonlyMap<string, AnyCanvas>;
513
+ declare function layoutRect(comp: Box, src: Box, fit: FitMode, transform?: Transform | undefined): Layout;
514
+ /** The matrix mapping an element's local pixels to the composition, given its untransformed rect. */
515
+ declare function transformMatrix(rect: DrawRect, t: Transform | undefined): Matrix2D;
516
+ /** The upright box around `rect` after `m`: where a rectangle of an element's local pixels lands in the composition. */
517
+ declare function boundsOf(rect: DrawRect, m: Matrix2D): DrawRect;
518
+ /** The transform with its keyframed properties evaluated at element-relative time `rel`. */
519
+ declare function animatedTransform(base: Transform | undefined, children: readonly Placement[], rel: number): Transform;
520
+ /** CSS for a DOM element laid out like `layoutRect` does: it sits at the origin with `transform-origin: 0 0`. */
521
+ declare function cssTransform(layout: Layout): string;
522
+ /** An entrance or exit as the schema writes it. */
523
+ interface GraphicAnimation {
524
+ readonly type: string;
525
+ readonly duration?: number;
526
+ readonly easing?: string;
527
+ }
528
+ /** A rectangle in the element's own pixels. */
529
+ interface ClipRect {
530
+ readonly x: number;
531
+ readonly y: number;
532
+ readonly w: number;
533
+ readonly h: number;
614
534
  }
615
535
  /**
616
- * Executes a FramePlan on a 2D context of composition size. Each op is
617
- * drawn under its own transform, alpha, blend and filter; masks clip; an
618
- * adjustment op re-filters everything drawn so far through a scratch canvas.
536
+ * What an element's entrance and exit do to it at one moment, in its own pixels:
537
+ * an opacity factor, a matrix applied before its layout, the part of it shown
538
+ * (null for all of it) and how much of its strokes are drawn (null when not drawing).
619
539
  */
620
- declare class CanvasPainter {
621
- readonly width: number;
622
- readonly height: number;
623
- private readonly createCanvas;
624
- private scratch;
625
- /** An element drawn on its own before compositing: a feathered mask, vignette, grain. */
626
- private layer;
627
- private grain;
628
- constructor(width: number, height: number, createCanvas: CreateCanvas);
629
- paint(ctx: Ctx2D, plan: FramePlan, inputs: PaintInputs): void;
630
- private drawOp;
631
- /** The footage's picture, blurred and scaled to cover the frame, under everything; skipped when the footage covers the frame itself. */
632
- private blurBackground;
633
- private blit;
634
- /** Applies the border radius and mask as a clip in local coordinates. Returns true when a mask clip was set. */
635
- private clip;
636
- /**
637
- * The element alone on the layer canvas, then composited: a feathered mask punches it out with a
638
- * blurred alpha there, and vignette and grain darken or speckle only its own pixels.
639
- */
640
- private drawLayered;
641
- /** A tile of black and white specks, the same for the same seed; alpha up to `amount`. */
642
- private noise;
643
- private adjust;
540
+ interface Motion {
541
+ readonly opacity: number;
542
+ readonly matrix: Matrix2D;
543
+ readonly clip: readonly ClipRect[] | null;
544
+ readonly draw: number | null;
644
545
  }
645
- declare function setMatrix(ctx: Ctx2D, m: Matrix2D): void;
646
- /** Whether a draw op puts its picture over the whole canvas as it is: no transform, crop, clip, fade, filter or blend. */
647
- declare function coversCanvas(op: DrawOp, width: number, height: number): boolean;
648
- /** The composition background (a colour or a gradient) over the whole frame. */
649
- declare function paintBackground(ctx: Ctx2D, plan: Pick<FramePlan, "background" | "backgroundGradient">, w: number, h: number): void;
650
- /** The same background as CSS, for the preview's ground under backdrop overlays. */
651
- declare function backgroundCss(plan: Pick<FramePlan, "background" | "backgroundGradient">): string;
652
- /** A canvas gradient for the frame, laid out the way CSS lays out the same gradient on a box of this size. */
653
- declare function backgroundFill(ctx: Ctx2D, g: BackgroundGradient, w: number, h: number): CanvasGradient | string;
546
+ declare const STILL: Motion;
547
+ /**
548
+ * The entrance and exit of an element `rel` seconds into its `duration`, for a
549
+ * `width` by `height` box. Both can play at once on a short element; their
550
+ * effects multiply. Pop, bounce and elastic carry their own curve; the others
551
+ * follow the animation's easing (default ease-out).
552
+ */
553
+ declare function motionAt(enter: GraphicAnimation | undefined, exit: GraphicAnimation | undefined, rel: number, duration: number, width: number, height: number): Motion;
554
+ /** One animation at raw progress `x` (0 hidden, 1 fully shown). */
555
+ declare function effect(anim: GraphicAnimation, x: number, w: number, h: number): Motion;
556
+ /** Both effects at once: opacities and draw amounts multiply, matrices compose, clips intersect. */
557
+ declare function combine(a: Motion, b: Motion): Motion;
558
+ interface TransitionRole {
559
+ readonly placement: Placement;
560
+ readonly role: "out" | "in";
561
+ /** 0..1 through the transition, eased by its curve. */
562
+ readonly progress: number;
563
+ }
564
+ interface VisibleItem {
565
+ readonly placement: Placement;
566
+ readonly track: ResolvedTrack;
567
+ readonly children: readonly Placement[];
568
+ readonly transition?: TransitionRole;
569
+ }
570
+ /** Visual, timed placements that show at `t`: tracks in document order (the first track is the bottom), items in track order. */
571
+ declare function visiblePlacements(state: ResolvedState, t: number): VisibleItem[];
572
+ declare function isVisibleAt(p: Placement, t: number, compositionDuration: number): boolean;
573
+ /** Placements that sit on a track, in track order; a multicam's generated clips follow their parent. */
574
+ declare function trackItems(state: ResolvedState, track: ResolvedTrack): Placement[];
575
+ /** One declared effect (`defineEffect()`) to run over an element's picture, with its params at this moment. */
576
+ interface ShaderPass {
577
+ readonly name: string;
578
+ readonly source: string;
579
+ readonly params: Readonly<Record<string, unknown>>;
580
+ /** Seconds into the element. */
581
+ readonly time: number;
582
+ }
583
+ /** A declared transition (`defineTransition()`) on one side of it at this moment. */
584
+ interface TransitionPass {
585
+ /** The transition's id, which pairs the outgoing side with the incoming one. */
586
+ readonly id: string;
587
+ readonly name: string;
588
+ readonly source: string;
589
+ readonly params: Readonly<Record<string, unknown>>;
590
+ /** 0..1 through the transition, eased by its curve. */
591
+ readonly progress: number;
592
+ readonly time: number;
593
+ readonly role: "out" | "in";
594
+ /** Between two clips, whose pictures the shader blends; false for one clip's edge, blended with nothing. */
595
+ readonly paired: boolean;
596
+ }
597
+ interface MaskSpec {
598
+ readonly shape?: Record<string, unknown> | undefined;
599
+ readonly path?: {
600
+ points: {
601
+ x: number;
602
+ y: number;
603
+ handleIn?: {
604
+ x: number;
605
+ y: number;
606
+ };
607
+ handleOut?: {
608
+ x: number;
609
+ y: number;
610
+ };
611
+ }[];
612
+ closed: boolean;
613
+ } | undefined;
614
+ readonly feather: number;
615
+ readonly inverted: boolean;
616
+ readonly opacity: number;
617
+ }
618
+ interface DrawOp {
619
+ readonly id: string;
620
+ readonly kind: "video" | "image" | "nested" | "error" | "adjustment";
621
+ readonly asset?: string;
622
+ readonly sourceTime?: number;
623
+ readonly nested?: {
624
+ readonly state: ResolvedState;
625
+ readonly time: number;
626
+ };
627
+ readonly rect: DrawRect;
628
+ readonly matrix: Matrix2D;
629
+ readonly crop?: DrawRect;
630
+ /** Dimensions used to express crop pixels; decoded proxies can have another resolution. */
631
+ readonly cropReference?: {
632
+ readonly width: number;
633
+ readonly height: number;
634
+ };
635
+ readonly fit: FitMode;
636
+ readonly opacity: number;
637
+ readonly blend: GlobalCompositeOperation;
638
+ readonly filter: string;
639
+ readonly borderRadius: number;
640
+ readonly mask?: MaskSpec;
641
+ /** The part shown, in composition pixels (a wipe). */
642
+ readonly clip?: readonly ClipRect[];
643
+ /** Vignette and grain, drawn over the element's own pixels. */
644
+ readonly post?: readonly PostEffect[];
645
+ /** Effects the file declares (`defineEffect()`), run over the element's picture in order. */
646
+ readonly shaders?: readonly ShaderPass[];
647
+ /** A transition the file declares (`defineTransition()`) on this side of it; replaces the built-in look. */
648
+ readonly transition?: TransitionPass;
649
+ }
650
+ /** A composition background gradient, as the schema writes it. CSS angles: 0 points up, 180 (the default) runs down. */
651
+ interface BackgroundGradient {
652
+ readonly type: "linear" | "radial" | "conic";
653
+ readonly angle?: number;
654
+ readonly center?: {
655
+ readonly x: number;
656
+ readonly y: number;
657
+ };
658
+ readonly stops: readonly {
659
+ readonly offset: number;
660
+ readonly color: string;
661
+ readonly opacity?: number;
662
+ }[];
663
+ }
664
+ interface FramePlan {
665
+ readonly time: number;
666
+ readonly frame: number;
667
+ readonly background: string;
668
+ /** A gradient that fills the frame instead of `background` (which is then its first colour). */
669
+ readonly backgroundGradient?: BackgroundGradient;
670
+ /** The footage goes over a transparent ground: overlays beneath it (see `backdropTracks`) and the background are drawn under the canvas. */
671
+ readonly clear?: true;
672
+ /** `background.mode: "blur"`: this op's picture, blurred to cover the frame, goes under everything. */
673
+ readonly backgroundBlur?: {
674
+ readonly id: string;
675
+ };
676
+ readonly ops: readonly DrawOp[];
677
+ readonly warnings: readonly string[];
678
+ }
679
+ type ResolveNested = (p: Placement) => ResolvedState | null;
680
+ declare function blendOf(value: unknown): GlobalCompositeOperation;
681
+ /**
682
+ * Everything the painter needs to draw composition time `t`, in draw order.
683
+ * Pure: the same state and time give a deep-equal plan. DOM-rendered kinds
684
+ * (title, shape, svg, sticker, layer, captions) are not in it; the DOM layer
685
+ * reads `visiblePlacements` itself.
686
+ */
687
+ declare function buildFramePlan(state: ResolvedState, t: number, resolveNested?: ResolveNested): FramePlan;
688
+ /** The composition's background as the painter draws it: a colour, or a gradient (whose first colour is `background`). */
689
+ declare function compositionBackground(state: ResolvedState): {
690
+ background: string;
691
+ backgroundGradient?: BackgroundGradient;
692
+ blur: boolean;
693
+ };
694
+ /** A gain breakpoint in composition seconds. */
695
+ type GainPoint = readonly [t: number, value: number];
696
+ interface AudioOccurrence {
697
+ readonly id: string;
698
+ readonly asset: string;
699
+ readonly chunk: number;
700
+ /** Composition range of this chunk, unclipped; the engine clips to "now". */
701
+ readonly compStart: number;
702
+ readonly compEnd: number;
703
+ /** Source seconds of the chunk's buffer; stable across windows so decoded PCM caches. */
704
+ readonly bufferFrom: number;
705
+ readonly bufferTo: number;
706
+ /** Placement speed; the engine multiplies in the transport rate. Ignored when `rate` is set. */
707
+ readonly speed: number;
708
+ /** Speed-key ramp: buffer seconds per composition second, piecewise linear over [compStart, compEnd]. */
709
+ readonly rate?: readonly GainPoint[];
710
+ readonly gain: readonly GainPoint[];
711
+ readonly pan?: readonly GainPoint[];
712
+ /** The buffer plays backwards: the engine reverses the decoded PCM. */
713
+ readonly reverse?: true;
714
+ }
715
+ /** Every audio-bearing chunk that overlaps [from, to). */
716
+ declare function buildAudioPlan(state: ResolvedState, from: number, to: number, resolveNested?: ResolveNested): AudioOccurrence[];
717
+ /**
718
+ * Gain over [winFrom, winTo] in composition seconds: volume × keyframed
719
+ * `audio.volume` × fades × automation × ducking. The factors are multiplied
720
+ * and sampled at their breakpoints plus a fixed step inside ramps, so the
721
+ * product stays close to piecewise linear.
722
+ */
723
+ declare function buildGainEnvelope(p: Placement, track: ResolvedTrack, state: ResolvedState, winFrom: number, winTo: number): GainPoint[];
724
+ /** Composition intervals where sound plays on the track `under` names by id, else on the tracks of that role; silent assets and muted clips do not duck. */
725
+ declare function duckIntervals(state: ResolvedState, under: string, exceptId: string): [number, number][];
726
+ /** Kinds the overlay plane draws (as DOM, in the preview and the export) rather than the canvas. */
727
+ declare const OVERLAY_KINDS: ReadonlySet<string>;
728
+ /**
729
+ * The tracks whose overlays draw beneath the footage: those below every
730
+ * visible track that holds footage, when one of them holds an overlay (a
731
+ * background graphic under the cut, say). Empty otherwise, and then every
732
+ * overlay draws above the footage as before. When it is not empty, the canvas
733
+ * holds only the footage over a transparent ground, and the composition
734
+ * background is painted beneath the backdrop instead.
735
+ */
736
+ declare function backdropTracks(state: ResolvedState): ReadonlySet<string>;
737
+ declare function ease(name: string | undefined, x: number): number;
738
+ /**
739
+ * The keyframed value of `property` at element-relative time `rel`. Holds
740
+ * before the first and after the last key; the segment between two keys uses
741
+ * the easing of the key it leaves. Non-numeric values step.
742
+ */
743
+ declare function keyframedValue<T>(children: readonly Placement[], property: string, rel: number, fallback: T): T;
744
+ declare function hasKeyframes(children: readonly Placement[], property: string): boolean;
745
+ declare function frameIndex(t: number, fps: number): number;
746
+ declare function frameTime(frame: number, fps: number): number;
747
+ /** `mm:ss.ff` for a composition time, what the controls show and the contact sheet labels. */
748
+ declare function timecode(t: number, fps: number): string;
749
+ /** 0..1 progress through a placement, what `useT()` returns inside a Layer. */
750
+ declare function localT(p: Placement, t: number): number;
751
+ /** What `useLayer()` returns inside a Layer: progress plus real seconds. */
752
+ declare function layerClock(p: Placement, t: number, fps: number): LayerClock;
753
+ /**
754
+ * Source seconds a media placement shows at composition time `t`: in/out
755
+ * trim, constant speed or a speed-key ramp, reverse, and freeze holds.
756
+ * A freeze is an insert hold: it shows `at` over its window, then the clip
757
+ * resumes from where it stopped; the result is clamped to the trimmed range.
758
+ */
759
+ declare function placementSourceTime(p: Placement, children: readonly Placement[], t: number): number;
760
+ declare function nestedSourceTime(p: Placement, t: number): number;
761
+ /**
762
+ * Resolves `<Nested of={Helper}>` through the kit's `resolveScene`, once per
763
+ * helper. File references (`of="file:..."`) have no loader yet and resolve
764
+ * to nothing.
765
+ */
766
+ declare function makeNestedResolver(parent: () => ResolvedState): ResolveNested;
654
767
  interface CompositorDeps {
655
768
  readonly sources: AssetSources;
656
769
  readonly createCanvas: CreateCanvas;
@@ -658,18 +771,11 @@ interface CompositorDeps {
658
771
  /** Called after a frame was painted with a new frame index. */
659
772
  readonly onFrame?: ((time: number, frame: number) => void) | undefined;
660
773
  }
661
- /**
662
- * Sees a frame's plan and its pictures before they are painted. Returning true means the host takes this frame as it
663
- * is (an export handing a decoded picture straight to its encoder): nothing is prepared or painted.
664
- */
665
- type FrameIntercept = (plan: FramePlan, frames: ReadonlyMap<string, Frame | null>) => boolean;
666
774
  interface TickOptions {
667
775
  /** Fetch missing frames before painting (seek, export). */
668
776
  readonly wait: boolean;
669
777
  /** With `wait`: no deadline. An export waits for every frame instead of drawing a stale one. */
670
778
  readonly exact?: boolean;
671
- /** This composition's frames only; nested compositions paint as usual. */
672
- readonly intercept?: FrameIntercept;
673
779
  }
674
780
  /**
675
781
  * One tick: plan the frame, sync decoders, gather frames, paint. A tick that
@@ -705,16 +811,82 @@ declare class Compositor {
705
811
  * for. Paint order and output are the same as `seek` then `tick`, at a
706
812
  * fraction of the decode work.
707
813
  */
708
- step(t: number, intercept?: FrameIntercept): Promise<void>;
814
+ step(t: number): Promise<void>;
709
815
  tick(t: number, opts: TickOptions): Promise<void>;
710
816
  dispose(): void;
711
817
  private run;
712
818
  private syncNested;
713
819
  }
714
820
  /**
715
- * Resolves `<Nested of={Helper}>` through the kit's `resolveScene`, once per
716
- * helper. File references (`of="file:..."`) have no loader yet and resolve
717
- * to nothing.
821
+ * Trace the mask outline onto the context's current path, in local element
822
+ * pixels. Shape coordinates are fractions of the element box; bezier paths
823
+ * are in pixels with handles. Returns false when the spec has no usable shape.
718
824
  */
719
- declare function makeNestedResolver(parent: () => ResolvedState): ResolveNested;
720
- export { postEffects as $, ImageFrameSource as A, FRAME_EPS as At, buildGainEnvelope as B, QUEUE_MAX as Bt, ClipDecoder as C, devWarn as Ct, ErrorFrame as D, DUCK_ATTACK_S as Dt, AssetSources as E, AUDIO_PRIME_S as Et, ManualClock as F, MAX_RATE as Ft, MaskSpec as G, SEEK_MODE_SPEED as Gt, BackgroundGradient as H, REVERSE_WINDOW_FRAMES as Ht, PerformanceClock as I, MIN_RATE as It, buildFramePlan as J, ResolveNested as K, SETTLE_MS as Kt, AudioOccurrence as L, MOUNT_AHEAD_S as Lt, defaultCreateCanvas as M, INPUT_IDLE_CLOSE_S as Mt, fromMap as N, LOOKAHEAD_S as Nt, ErrorFrameSource as O, DUCK_RELEASE_S as Ot, toResolver as P, MAX_OPEN_INPUTS as Pt, filterString as Q, GainPoint as R, PICK_EPS as Rt, DecoderPool as S, captureWarnings as St, AssetSourceDeps as T, AUDIO_CHUNK_S as Tt, DrawOp as U, REVERSE_WINDOW_S as Ut, duckIntervals as V, QUEUE_TARGET as Vt, FramePlan as W, SCHEDULER_MS as Wt, FilterResult as X, compositionBackground as Y, PostEffect as Z, FrameSourceHooks as _, MediaHandle as _t, TickOptions as a, AudioOutput as at, mediabunnyFrameSourceFactory as b, PlayerEvents as bt, backgroundCss as c, AudioSourceInfo as ct, paintBackground as d, Ctx2D as dt, EASING_FN as et, setMatrix as f, EnvelopePoint as ft, mediabunnyAudioSourceFactory as g, FrameSourceInfo as gt, MediabunnyAudioSource as h, FrameSourceFactory as ht, FrameIntercept as i, AnyCanvas as it, copyFrame as j, FRAME_WAIT_MS as jt, ImageFrame as k, ENVELOPE_STEP_S as kt, backgroundFill as l, Clock as lt, traceMask as m, FrameSource as mt, Compositor as n, hasKeyframes as nt, CanvasPainter as o, AudioSource as ot, roundedRect as p, Frame as pt, blendOf as q, UNMOUNT_BEHIND_S as qt, CompositorDeps as r, keyframedValue as rt, PaintInputs as s, AudioSourceFactory as st, makeNestedResolver as t, ease as tt, coversCanvas as u, CreateCanvas as ut, MediabunnyFrameSource as v, MediaResolver as vt, DecodeMode as w, AUDIO_CACHE_S as wt, MediabunnyInputs as x, ScheduledSource as xt, SampleFrame as y, PlayerErrorEvent as yt, buildAudioPlan as z, PLAY_PRIME_TIMEOUT_MS as zt };
825
+ declare function traceMask(ctx: Ctx2D, mask: MaskSpec, rect: DrawRect): boolean;
826
+ declare function roundedRect(ctx: Ctx2D, x: number, y: number, w: number, h: number, r: number): void;
827
+ interface PaintInputs {
828
+ readonly frames: ReadonlyMap<string, Frame | null>;
829
+ readonly nested: ReadonlyMap<string, AnyCanvas>;
830
+ }
831
+ /**
832
+ * Executes a FramePlan on a 2D context of composition size. Each op is
833
+ * drawn under its own transform, alpha, blend and filter; masks clip; an
834
+ * adjustment op re-filters everything drawn so far through a scratch canvas.
835
+ */
836
+ declare class CanvasPainter {
837
+ readonly width: number;
838
+ readonly height: number;
839
+ private readonly createCanvas;
840
+ private scratch;
841
+ /** An element drawn on its own before compositing: a feathered mask, vignette, grain. */
842
+ private layer;
843
+ private grain;
844
+ /** Runs the effects and transitions the file declares; made on first use. */
845
+ private shaders;
846
+ /** The outgoing side of a declared transition between two clips, waiting for the incoming side. */
847
+ private outgoing;
848
+ private outgoingPicture;
849
+ constructor(width: number, height: number, createCanvas: CreateCanvas);
850
+ paint(ctx: Ctx2D, plan: FramePlan, inputs: PaintInputs): void;
851
+ private drawOp;
852
+ /**
853
+ * An element with effects or a transition the file declares: drawn alone, run through its shaders, then composited.
854
+ * The outgoing side of a transition between two clips is kept until the incoming side arrives, and the two are
855
+ * blended in one pass.
856
+ */
857
+ private drawShaded;
858
+ private runner;
859
+ private outgoingCanvas;
860
+ /** The footage's picture, blurred and scaled to cover the frame, under everything; skipped when the footage covers the frame itself. */
861
+ private blurBackground;
862
+ private blit;
863
+ /** Applies the border radius and mask as a clip in local coordinates. Returns true when a mask clip was set. */
864
+ private clip;
865
+ /**
866
+ * The element alone on the layer canvas, then composited: a feathered mask punches it out with a
867
+ * blurred alpha there, and vignette and grain darken or speckle only its own pixels.
868
+ */
869
+ private drawLayered;
870
+ /** The element drawn alone on the layer canvas, at its place in the frame, its mask and vignette or grain applied. */
871
+ private alone;
872
+ /** A picture of the whole frame composited as the op: its opacity, blend, filter, wipe and rounded corners. */
873
+ private composite;
874
+ /** A tile of black and white specks, the same for the same seed; alpha up to `amount`. */
875
+ private noise;
876
+ private adjust;
877
+ /** An adjustment with declared effects: everything drawn so far, through the shaders, back over itself. */
878
+ private adjustShaded;
879
+ }
880
+ declare function setMatrix(ctx: Ctx2D, m: Matrix2D): void;
881
+ /** Whether a draw op puts its picture over the whole canvas as it is: no transform, crop, clip, fade, filter or blend. */
882
+ declare function coversCanvas(op: DrawOp, width: number, height: number): boolean;
883
+ /** The composition background (a colour or a gradient) over the whole frame. */
884
+ declare function paintBackground(ctx: Ctx2D, plan: Pick<FramePlan, "background" | "backgroundGradient">, w: number, h: number): void;
885
+ /** The same background as CSS, for the preview's ground under backdrop overlays. */
886
+ declare function backgroundCss(plan: Pick<FramePlan, "background" | "backgroundGradient">): string;
887
+ /** A canvas gradient for the frame, laid out the way CSS lays out the same gradient on a box of this size. */
888
+ declare function backgroundFill(ctx: Ctx2D, g: BackgroundGradient, w: number, h: number): CanvasGradient | string;
889
+ /** Warn once per key. Tests capture warnings with `captureWarnings`. */
890
+ declare function devWarn(key: string, message: string): void;
891
+ declare function captureWarnings(fn: ((message: string) => void) | null): void;
892
+ export { motionAt as $, MAX_OPEN_INPUTS as $t, GainPoint as A, PlayerErrorEvent as An, ErrorFrameSource as At, buildFramePlan as B, DecodeMode as Bt, EASING_FN as C, EnvelopePoint as Cn, MediabunnyFrameSource as Ct, OVERLAY_KINDS as D, FrameSourceInfo as Dn, mediabunnyAudioSourceFactory as Dt, keyframedValue as E, FrameSourceFactory as En, MediabunnyAudioSource as Et, DrawOp as F, FontFaceSource as Ft, trackItems as G, AUDIO_PRIME_S as Gt, TransitionRole as H, AssetSources as Ht, FramePlan as I, addFontFaces as It, GraphicAnimation as J, ENVELOPE_STEP_S as Jt, visiblePlacements as K, DUCK_ATTACK_S as Kt, MaskSpec as L, loadFileFonts as Lt, buildGainEnvelope as M, ScheduledSource as Mn, ImageFrameSource as Mt, duckIntervals as N, copyFrame as Nt, backdropTracks as O, MediaHandle as On, MediabunnyInputs as Ot, BackgroundGradient as P, defaultCreateCanvas as Pt, effect as Q, LOOKAHEAD_S as Qt, ResolveNested as R, DecoderPool as Rt, timecode as S, Ctx2D as Sn, toResolver as St, hasKeyframes as T, FrameSource as Tn, mediabunnyFrameSourceFactory as Tt, VisibleItem as U, AUDIO_CACHE_S as Ut, compositionBackground as V, AssetSourceDeps as Vt, isVisibleAt as W, AUDIO_CHUNK_S as Wt, STILL as X, FRAME_WAIT_MS as Xt, Motion as Y, FRAME_EPS as Yt, combine as Z, INPUT_IDLE_CLOSE_S as Zt, frameTime as _, AudioSource as _n, PostEffect as _t, backgroundCss as a, QUEUE_MAX as an, animatedTransform as at, nestedSourceTime as b, Clock as bn, postEffects as bt, paintBackground as c, REVERSE_WINDOW_S as cn, fitRect as ct, traceMask as d, SETTLE_MS as dn, multiply as dt, MAX_RATE as en, Box as et, Compositor as f, UNMOUNT_BEHIND_S as fn, rotate as ft, frameIndex as g, AudioOutput as gn, FilterResult as gt, makeNestedResolver as h, AnyCanvas as hn, translate as ht, PaintInputs as i, PLAY_PRIME_TIMEOUT_MS as in, Matrix2D as it, buildAudioPlan as j, PlayerEvents as jn, ImageFrame as jt, AudioOccurrence as k, MediaResolver as kn, ErrorFrame as kt, setMatrix as l, SCHEDULER_MS as ln, layoutRect as lt, TickOptions as m, PerformanceClock as mn, transformMatrix as mt, devWarn as n, MOUNT_AHEAD_S as nn, IDENTITY as nt, backgroundFill as o, QUEUE_TARGET as on, boundsOf as ot, CompositorDeps as p, ManualClock as pn, scaleM as pt, ClipRect as q, DUCK_RELEASE_S as qt, CanvasPainter as r, PICK_EPS as rn, Layout as rt, coversCanvas as s, REVERSE_WINDOW_FRAMES as sn, cssTransform as st, captureWarnings as t, MIN_RATE as tn, DrawRect as tt, roundedRect as u, SEEK_MODE_SPEED as un, matrixToCss as ut, layerClock as v, AudioSourceFactory as vn, filterString as vt, ease as w, Frame as wn, SampleFrame as wt, placementSourceTime as x, CreateCanvas as xn, fromMap as xt, localT as y, AudioSourceInfo as yn, paramsAt as yt, blendOf as z, ClipDecoder as zt };