@pixerate/editor 0.123.0 → 0.124.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.js +3 -3
  4. package/dist/animation/index.d.cts +2 -1
  5. package/dist/animation/index.d.ts +2 -1
  6. package/dist/animation-editor/index.cjs.map +1 -1
  7. package/dist/animation-editor/index.d.cts +11 -733
  8. package/dist/animation-editor/index.d.ts +11 -733
  9. package/dist/animation-editor/index.js.map +1 -1
  10. package/dist/{bezier-C-W9LFyD.d.cts → bezier-CBzKKDjl.d.cts} +2 -66
  11. package/dist/{bezier-DQZE5dxA.d.ts → bezier-CWv6LQal.d.ts} +2 -66
  12. package/dist/{brushstrokeRender-M4S65DHT.cjs → brushstrokeRender-EELTV7U4.cjs} +8 -8
  13. package/dist/{brushstrokeRender-M4S65DHT.cjs.map → brushstrokeRender-EELTV7U4.cjs.map} +1 -1
  14. package/dist/{brushstrokeRender-CDDRSV2W.js → brushstrokeRender-LRV7GXGD.js} +3 -3
  15. package/dist/canvas/index.cjs +6 -6
  16. package/dist/canvas/index.d.cts +10 -6
  17. package/dist/canvas/index.d.ts +10 -6
  18. package/dist/canvas/index.js +1 -1
  19. package/dist/{chunk-SMJGE7HM.cjs → chunk-4QQZV5Y5.cjs} +512 -39
  20. package/dist/chunk-4QQZV5Y5.cjs.map +1 -0
  21. package/dist/{chunk-TVXFHE4T.js → chunk-64PYNEHJ.js} +45 -12
  22. package/dist/chunk-64PYNEHJ.js.map +1 -0
  23. package/dist/{chunk-2IW3BWRT.cjs → chunk-7LQO6OHH.cjs} +2 -2
  24. package/dist/{chunk-2IW3BWRT.cjs.map → chunk-7LQO6OHH.cjs.map} +1 -1
  25. package/dist/chunk-CN4PJHUG.cjs +234 -0
  26. package/dist/chunk-CN4PJHUG.cjs.map +1 -0
  27. package/dist/chunk-FHYDQOPC.cjs +215 -0
  28. package/dist/chunk-FHYDQOPC.cjs.map +1 -0
  29. package/dist/{chunk-KMBC4HNV.js → chunk-J67OLQUQ.js} +2 -2
  30. package/dist/chunk-JRXJTPES.js +215 -0
  31. package/dist/chunk-JRXJTPES.js.map +1 -0
  32. package/dist/{chunk-IPFRWILU.js → chunk-ORHMVUR6.js} +488 -15
  33. package/dist/chunk-ORHMVUR6.js.map +1 -0
  34. package/dist/{chunk-6CJRDJCU.cjs → chunk-PEHYWUVV.cjs} +176 -111
  35. package/dist/chunk-PEHYWUVV.cjs.map +1 -0
  36. package/dist/chunk-QEG3GRN2.js +234 -0
  37. package/dist/chunk-QEG3GRN2.js.map +1 -0
  38. package/dist/{chunk-6ZBR4J62.js → chunk-WATAQ2Z2.js} +79 -14
  39. package/dist/chunk-WATAQ2Z2.js.map +1 -0
  40. package/dist/{chunk-RLRUAPBJ.cjs → chunk-Z6OUCS2K.cjs} +47 -14
  41. package/dist/chunk-Z6OUCS2K.cjs.map +1 -0
  42. package/dist/effects/index.cjs +605 -0
  43. package/dist/effects/index.cjs.map +1 -0
  44. package/dist/effects/index.d.cts +163 -0
  45. package/dist/effects/index.d.ts +163 -0
  46. package/dist/effects/index.js +605 -0
  47. package/dist/effects/index.js.map +1 -0
  48. package/dist/evaluate-2S3vSPLy.d.cts +55 -0
  49. package/dist/evaluate-CfmT6xA3.d.ts +55 -0
  50. package/dist/{export-DfjzHAJI.d.ts → export-BGtXgMJ3.d.ts} +536 -128
  51. package/dist/{export-Dv0-ZVrV.d.cts → export-BdfY_lH0.d.ts} +392 -5
  52. package/dist/{export-Dv0-ZVrV.d.ts → export-CbpjwxaI.d.cts} +392 -5
  53. package/dist/{export-lU5qSpHE.d.cts → export-WmYoWmLM.d.cts} +536 -128
  54. package/dist/flair-CxB3fOcU.d.ts +739 -0
  55. package/dist/flair-D7BxyBwL.d.cts +739 -0
  56. package/dist/gradient-KDfCvhuj.d.cts +66 -0
  57. package/dist/gradient-KDfCvhuj.d.ts +66 -0
  58. package/dist/helpers-777mC6dc.d.cts +253 -0
  59. package/dist/helpers-DX2_7L5t.d.ts +253 -0
  60. package/dist/image-editor/index.cjs +1296 -805
  61. package/dist/image-editor/index.cjs.map +1 -1
  62. package/dist/image-editor/index.d.cts +39 -182
  63. package/dist/image-editor/index.d.ts +39 -182
  64. package/dist/image-editor/index.js +497 -6
  65. package/dist/image-editor/index.js.map +1 -1
  66. package/dist/{opentype-p8Xxf-Wh.d.ts → opentype-14PDI5D2.d.ts} +1 -1
  67. package/dist/{opentype-BV7wWatY.d.cts → opentype-D80AVmMu.d.cts} +1 -1
  68. package/dist/paint/index.cjs +2 -2
  69. package/dist/paint/index.d.cts +32 -10
  70. package/dist/paint/index.d.ts +32 -10
  71. package/dist/paint/index.js +1 -1
  72. package/dist/paint-editor/index.cjs +10 -8
  73. package/dist/paint-editor/index.cjs.map +1 -1
  74. package/dist/paint-editor/index.d.cts +11 -5
  75. package/dist/paint-editor/index.d.ts +11 -5
  76. package/dist/paint-editor/index.js +4 -2
  77. package/dist/paint-editor/index.js.map +1 -1
  78. package/dist/parameters/index.d.cts +4 -184
  79. package/dist/parameters/index.d.ts +4 -184
  80. package/dist/{pathfinder-IxcyhO00.d.cts → pathfinder-C0UoFypx.d.cts} +1 -1
  81. package/dist/{pathfinder-StVChJOT.d.ts → pathfinder-DjISxkUv.d.ts} +1 -1
  82. package/dist/{player-DrcP2xqj.d.cts → player-CBtEoU2x.d.cts} +2 -54
  83. package/dist/{player-DV4Jujdq.d.ts → player-cGLrngL_.d.ts} +2 -54
  84. package/dist/{svg-BtND4TJu.d.cts → svg-BDrjRnL1.d.cts} +3 -2
  85. package/dist/{svg-BfVXG7hL.d.ts → svg-C-vZ3q50.d.ts} +3 -2
  86. package/dist/tools/index.cjs +2 -2
  87. package/dist/tools/index.cjs.map +1 -1
  88. package/dist/tools/index.js +3 -3
  89. package/dist/tools-C7JtLYzo.d.ts +126 -0
  90. package/dist/tools-DHKGHiSK.d.cts +126 -0
  91. package/dist/{types-fuXEme9j.d.ts → types-BcX7sCsn.d.ts} +2 -2
  92. package/dist/{types-DJF3Ghn5.d.cts → types-CznabG7m.d.cts} +2 -2
  93. package/dist/types-D3-J3TFf.d.ts +185 -0
  94. package/dist/types-DMcf_z4J.d.cts +185 -0
  95. package/dist/vector/index.d.cts +10 -10
  96. package/dist/vector/index.d.ts +10 -10
  97. package/dist/video-editor/index.cjs +749 -277
  98. package/dist/video-editor/index.cjs.map +1 -1
  99. package/dist/video-editor/index.d.cts +265 -138
  100. package/dist/video-editor/index.d.ts +265 -138
  101. package/dist/video-editor/index.js +490 -18
  102. package/dist/video-editor/index.js.map +1 -1
  103. package/dist/{warp-BjmAgQwq.d.cts → warp-CH9MM435.d.cts} +1 -1
  104. package/dist/{warp-Ca5fedzS.d.ts → warp-k_PdtXOG.d.ts} +1 -1
  105. package/package.json +6 -1
  106. package/skills/pixerate-image-editor/SKILL.md +7 -0
  107. package/skills/pixerate-image-editor/references/provider-effects.md +35 -0
  108. package/skills/pixerate-video-editor/SKILL.md +39 -1
  109. package/dist/chunk-6CJRDJCU.cjs.map +0 -1
  110. package/dist/chunk-6ZBR4J62.js.map +0 -1
  111. package/dist/chunk-IPFRWILU.js.map +0 -1
  112. package/dist/chunk-RLRUAPBJ.cjs.map +0 -1
  113. package/dist/chunk-SMJGE7HM.cjs.map +0 -1
  114. package/dist/chunk-TVXFHE4T.js.map +0 -1
  115. /package/dist/{brushstrokeRender-CDDRSV2W.js.map → brushstrokeRender-LRV7GXGD.js.map} +0 -0
  116. /package/dist/{chunk-KMBC4HNV.js.map → chunk-J67OLQUQ.js.map} +0 -0
@@ -1,3 +1,5 @@
1
+ import { d as EffectValue, v as EffectsSlot, f as EffectPixels, E as EffectProvider, e as EffectDescription } from './helpers-DX2_7L5t.js';
2
+
1
3
  /**
2
4
  * Keyframes for a clip's opacity, volume and transform. A property is either a plain number or
3
5
  * `{ keys }`: values at clip-relative times (ms from the clip's start), each with the easing of the
@@ -165,9 +167,37 @@ declare const VIDEO_FITS: readonly ["contain", "cover", "fill", "none"];
165
167
  * - `push`: this clip slides in, pushing the one before out.
166
168
  * - `slide`: this clip slides in over the one before, which stays put.
167
169
  * - `iris`: a circle opens from the centre, revealing this clip.
170
+ * - `effect`: a transition effect from the editor's effects provider (`VideoTransition.effect`).
171
+ */
172
+ type VideoTransitionType = 'crossfade' | 'dip' | 'wipe' | 'push' | 'slide' | 'iris' | 'effect';
173
+ declare const VIDEO_TRANSITION_TYPES: readonly ["crossfade", "dip", "wipe", "push", "slide", "iris", "effect"];
174
+ /**
175
+ * Values of a provider effect's controls (see `@pixerate/editor/effects`): plain values, or
176
+ * keyframes (clip-relative ms) for numeric controls.
168
177
  */
169
- type VideoTransitionType = 'crossfade' | 'dip' | 'wipe' | 'push' | 'slide' | 'iris';
170
- declare const VIDEO_TRANSITION_TYPES: readonly ["crossfade", "dip", "wipe", "push", "slide", "iris"];
178
+ type VideoEffectValues = Record<string, EffectValue | VideoKeyframes>;
179
+ /** A provider effect used by a transition or an effect clip. Kept in the project even without a provider. */
180
+ interface VideoEffectRef {
181
+ /** The provider's effect id. */
182
+ effect: string;
183
+ /** The provider it was applied with (its `id`). */
184
+ provider?: string;
185
+ /** The effect's name when it was applied, shown where no provider can draw it. */
186
+ name?: string;
187
+ values?: VideoEffectValues;
188
+ }
189
+ /**
190
+ * A provider effect on a clip's picture (see `VideoClipBase.effects`). Effects run in order on the
191
+ * picture as it comes from the source, before the clip's grade, placement, opacity and blend.
192
+ */
193
+ interface VideoClipEffect extends VideoEffectRef {
194
+ /** Unique within the clip (e.g. `fx1`). */
195
+ id: string;
196
+ /** Default true. */
197
+ enabled?: boolean;
198
+ /** How much of the effect's result shows over its input, 0–1 (default 1), or keyframes. */
199
+ opacity?: VideoAnimatable;
200
+ }
171
201
  type VideoWipeDirection = 'left' | 'right' | 'up' | 'down';
172
202
  declare const VIDEO_WIPE_DIRECTIONS: readonly ["left", "right", "up", "down"];
173
203
  /**
@@ -183,6 +213,8 @@ interface VideoTransition {
183
213
  color?: string;
184
214
  /** For wipe, push and slide: the way the edge or picture travels (default right: in from the left). */
185
215
  direction?: VideoWipeDirection;
216
+ /** For effect: the provider's transition effect and its values (plain values only). */
217
+ effect?: VideoEffectRef;
186
218
  /**
187
219
  * Shape of the sound's fades through the transition (see `VideoFadeCurve`). Default
188
220
  * `equal-power` for crossfades and wipes, where two sounds overlap and a linear mix dips in
@@ -267,6 +299,8 @@ interface VideoClipBase {
267
299
  fadeOut?: number;
268
300
  /** Transition from the clip before (see `VideoTransition`). */
269
301
  transition?: VideoTransition;
302
+ /** Provider effects on the picture, applied in order (see `VideoClipEffect`). */
303
+ effects?: VideoClipEffect[];
270
304
  }
271
305
  /**
272
306
  * The shape of a sound fade, the same curves ffmpeg's `afade` draws, so previews and exports agree.
@@ -344,7 +378,14 @@ interface VideoSequenceClip extends VideoClipBase {
344
378
  /** Shape of the sound's fade out (default linear). */
345
379
  fadeOutCurve?: VideoFadeCurve;
346
380
  }
347
- type VideoClip = VideoMediaClip | VideoTextClip | VideoColorClip | VideoSequenceClip;
381
+ /**
382
+ * A picture drawn by a provider effect (a generator, title or overlay), filling the frame. Without
383
+ * a provider it shows as a placeholder and keeps its effect id and values.
384
+ */
385
+ interface VideoEffectClip extends VideoClipBase, VideoEffectRef {
386
+ type: 'effect';
387
+ }
388
+ type VideoClip = VideoMediaClip | VideoTextClip | VideoColorClip | VideoSequenceClip | VideoEffectClip;
348
389
  type VideoClipType = VideoClip['type'];
349
390
  /**
350
391
  * How a clip is placed where others already are: `refuse` an overlap (the default), `overwrite`
@@ -353,7 +394,7 @@ type VideoClipType = VideoClip['type'];
353
394
  */
354
395
  type VideoPlacementMode = 'refuse' | 'overwrite' | 'insert';
355
396
  declare const VIDEO_PLACEMENT_MODES: readonly ["refuse", "overwrite", "insert"];
356
- declare const VIDEO_CLIP_TYPES: readonly ["media", "text", "color", "sequence"];
397
+ declare const VIDEO_CLIP_TYPES: readonly ["media", "text", "color", "sequence", "effect"];
357
398
  interface VideoMarker {
358
399
  id: string;
359
400
  time: number;
@@ -389,6 +430,338 @@ interface VideoProject {
389
430
  markers?: VideoMarker[];
390
431
  }
391
432
 
433
+ /** A rectangle in frame pixels. */
434
+ interface VideoRect {
435
+ x: number;
436
+ y: number;
437
+ width: number;
438
+ height: number;
439
+ }
440
+ /** One picture in a frame, in draw order (first is at the back). */
441
+ interface VideoLayer {
442
+ /**
443
+ * The clip it comes from, or `transition:<clip>` for a dip's colour. Inside a compound clip it is
444
+ * the path of clip ids from the project's own track (`compound/inner`), so the same sequence
445
+ * played twice gives distinct layers.
446
+ */
447
+ clip: string;
448
+ /** The track it is on (inside a compound: the sequence's track). */
449
+ track: string;
450
+ type: VideoClip['type'];
451
+ /** For media: the asset, its kind and `src`, and the moment of the source to show (ms). */
452
+ asset?: string;
453
+ assetKind?: VideoAsset['kind'];
454
+ src?: string;
455
+ /** For media: the moment of the source to show (ms); for a compound: the moment of its sequence. */
456
+ sourceTime?: number;
457
+ /** For a compound: the sequence it plays. */
458
+ sequence?: string;
459
+ /**
460
+ * For a compound: the sequence's frame at `sourceTime`, back to front in the sequence's own frame
461
+ * (the project's size, transparent where nothing covers it). They are drawn together as one
462
+ * picture, which this layer's rect, rotation, opacity, blend, grade, wipe and iris then apply to.
463
+ */
464
+ layers?: VideoLayer[];
465
+ /** 0–1, after fades and transitions. */
466
+ opacity: number;
467
+ /** Where the fitted picture sits before rotation (its centre is the rotation centre). */
468
+ rect: VideoRect;
469
+ /** Degrees clockwise about the rect's centre. */
470
+ rotation: number;
471
+ /** For a wipe: the part shown is the `progress` (0–1) of the rect from the edge opposite `direction`. */
472
+ wipe?: {
473
+ direction: VideoWipeDirection;
474
+ progress: number;
475
+ };
476
+ /** For an iris: only a circle on the frame's centre shows, its radius `progress` (0–1) of the way to the frame's corners. */
477
+ iris?: {
478
+ progress: number;
479
+ };
480
+ /** For text: what to draw. */
481
+ text?: {
482
+ text: string;
483
+ color: string;
484
+ fontSize: number;
485
+ fontFamily: string;
486
+ fontWeight: number;
487
+ background?: string;
488
+ };
489
+ /** For colour clips and dips. */
490
+ color?: string;
491
+ /** How it mixes with the layers beneath (absent = normal). */
492
+ blend?: VideoBlendMode;
493
+ /** Colour correction (absent = none). */
494
+ grade?: VideoGrade;
495
+ /** The clip's enabled provider effects, in order, with values at this moment (see `VideoClipEffect`). */
496
+ effects?: VideoLayerEffect[];
497
+ /** For an effect clip: the provider effect drawing the picture, at `time` ms into the clip. */
498
+ generator?: {
499
+ effect: string;
500
+ name?: string;
501
+ values: Record<string, EffectValue>;
502
+ time: number;
503
+ };
504
+ /**
505
+ * For a clip coming in through an effect transition: the provider transition from the outgoing
506
+ * clip's layer (`from`, drawn in its place) to this one, `progress` (0–1) and `time` ms through it.
507
+ */
508
+ transitionEffect?: {
509
+ effect: string;
510
+ name?: string;
511
+ values: Record<string, EffectValue>;
512
+ progress: number;
513
+ time: number;
514
+ from: VideoLayer | null;
515
+ };
516
+ }
517
+ /** One provider effect on a layer at a moment. */
518
+ interface VideoLayerEffect {
519
+ /** The effect's id within its clip. */
520
+ id: string;
521
+ effect: string;
522
+ name?: string;
523
+ /** 0–1 after keyframes. */
524
+ opacity: number;
525
+ values: Record<string, EffectValue>;
526
+ /** Ms into the clip. */
527
+ time: number;
528
+ }
529
+ /** Effect values at clip-relative `clipTime` (ms): keyframed numbers resolved. */
530
+ declare function videoEffectValuesAt(values: VideoEffectValues | undefined, clipTime: number): Record<string, EffectValue>;
531
+ /** One sound playing at a moment. */
532
+ interface VideoAudioSource {
533
+ /** The clip it comes from (inside a compound: the path of clip ids, `compound/inner`). */
534
+ clip: string;
535
+ /** The track it is on (inside a compound: the sequence's track). */
536
+ track: string;
537
+ asset: string;
538
+ src: string;
539
+ /** The moment of the source playing (ms). */
540
+ sourceTime: number;
541
+ /** Gain after clip and track volume, fades and transitions, and those of any compound it plays in (0 = silent). */
542
+ gain: number;
543
+ speed: number;
544
+ }
545
+ interface VideoFrame {
546
+ time: number;
547
+ width: number;
548
+ height: number;
549
+ background: string;
550
+ layers: VideoLayer[];
551
+ audio: VideoAudioSource[];
552
+ }
553
+ /** A transform's values at clip-relative time `clipTime` (ms), keyframes resolved and defaults filled in. */
554
+ declare function videoTransformAt(transform: VideoClip['transform'], clipTime?: number): {
555
+ x: number;
556
+ y: number;
557
+ scale: number;
558
+ rotation: number;
559
+ };
560
+ /** Places a picture of `size` in the frame by `fit`, then the clip's transform at clip-relative `clipTime` (ms). */
561
+ declare function placeVideoRect(frame: {
562
+ width: number;
563
+ height: number;
564
+ }, size: {
565
+ width: number;
566
+ height: number;
567
+ }, fit?: VideoFit, transform?: VideoClip['transform'], clipTime?: number): VideoRect;
568
+ /** A title's text and style with the defaults filled in. */
569
+ declare function videoTextStyle(clip: VideoTextClip): NonNullable<VideoLayer['text']>;
570
+ /**
571
+ * A frame holding only one title, fully opaque on a transparent background, placed as the preview
572
+ * places it: draw it with `drawVideoFrame` and save the canvas as a PNG to give the ffmpeg export
573
+ * titles without `drawtext` (`VideoFfmpegOptions.titleImage`). Fades and opacity are left to the export.
574
+ * A keyframed transform is placed as it is at `clipTime` (the export passes titles with keyframed
575
+ * transforms without them, and moves the image itself).
576
+ */
577
+ declare function videoTitleFrame(project: VideoProject, clip: VideoTextClip, clipTime?: number): VideoFrame;
578
+ /** How far a push or slide has moved at `progress` (0–1): eased in and out, (1 − cos πp) / 2. */
579
+ declare const videoTransitionEase: (progress: number) => number;
580
+ /** Gain of a fade shape `x` of the way up (0–1); a fade out uses the time left, so it mirrors the fade in. */
581
+ declare function videoFadeCurveGain(curve: VideoFadeCurve | undefined, x: number): number;
582
+ /**
583
+ * A media or compound clip's own gain at clip time `clipTime` (ms): its volume (or volume keyframes) times its
584
+ * shaped fades. Leaves out track volume and transitions, which depend on the timeline around it.
585
+ */
586
+ declare function videoClipSoundGain(clip: VideoClip, clipTime: number): number;
587
+ /**
588
+ * What plays at `time` (ms): the pictures to draw, back to front, with their placement, opacity
589
+ * and the moment of source each shows, and the sounds with their gain. A pure function of the
590
+ * project and the time, so previews, exporters and agents all agree on every frame. A compound
591
+ * clip is one layer holding its sequence's frame (`layers`), and its sounds are mixed in with the
592
+ * compound's volume, fades and transitions.
593
+ */
594
+ declare function videoFrameAt(project: VideoProject, time: number): VideoFrame;
595
+ /**
596
+ * Layers as drawn without an effects provider: an effect transition becomes a crossfade (the
597
+ * outgoing layer, then this one faded up by the progress). Clip effects are left on the layers,
598
+ * where they are simply not drawn.
599
+ */
600
+ declare function videoLayersWithoutTransitionEffects(layers: readonly VideoLayer[]): VideoLayer[];
601
+ /**
602
+ * Every layer of a frame that draws a picture of its own, compounds opened up (each compound's
603
+ * layers in place of it), back to front. Hosts use it to find the media a frame needs.
604
+ */
605
+ declare function videoFrameLeafLayers(layers: readonly VideoLayer[]): VideoLayer[];
606
+
607
+ /**
608
+ * Provider effects in the video editor (see `@pixerate/editor/effects`): the per-frame cache of
609
+ * rendered effect pictures the preview and frame-exact exports draw from, and helpers to find the
610
+ * effects a project uses.
611
+ *
612
+ * Effects render asynchronously. The canvas drawing (`drawVideoFrame`) is synchronous, so it asks
613
+ * the engine for a picture by key: a cached one is drawn at once, and a missing one is requested
614
+ * and the layer drawn without its effects meanwhile (the frame counts as incomplete). When the
615
+ * render lands, subscribers redraw. `renderVideoFrameExact` repeats this until every effect of the
616
+ * frame is in, which is what exports use.
617
+ */
618
+
619
+ /** Where a project uses a provider effect. */
620
+ interface VideoEffectUse {
621
+ /** The clip it is on (for a transition: the clip it leads into). */
622
+ clip: string;
623
+ /** `clip`: in the clip's effect stack (`instance` is its id); `transition`: an effect transition; `generator`: an effect clip. */
624
+ kind: 'clip' | 'transition' | 'generator';
625
+ instance?: string;
626
+ effect: string;
627
+ name?: string;
628
+ provider?: string;
629
+ enabled: boolean;
630
+ }
631
+ /** Every provider effect in a project, sequences included, in track and clip order. */
632
+ declare function videoProjectEffects(project: VideoProject): VideoEffectUse[];
633
+ /** The provider effects of one clip: its effect clip picture, its transition and its effect stack. */
634
+ declare function videoClipEffectUses(clip: VideoClip): VideoEffectUse[];
635
+ /** True when drawing the layers needs an effects provider. */
636
+ declare const videoLayersUseEffects: (layers: readonly VideoLayer[]) => boolean;
637
+ /** The start of the frame `time` falls in (ms), on the project's frame grid. Effects render once per frame. */
638
+ declare const videoEffectFrameTime: (time: number, fps: number) => number;
639
+ /** What to render for one layer. */
640
+ type VideoEffectJob =
641
+ /** A clip's effect stack over its unprocessed picture. */
642
+ {
643
+ kind: 'stack';
644
+ input: EffectPixels;
645
+ effects: readonly VideoLayerEffect[];
646
+ }
647
+ /** An effect clip: the generator at `time`, then the clip's effect stack. */
648
+ | {
649
+ kind: 'generator';
650
+ width: number;
651
+ height: number;
652
+ effect: string;
653
+ values: Record<string, EffectValue>;
654
+ time: number;
655
+ effects: readonly VideoLayerEffect[];
656
+ }
657
+ /** An effect transition between two whole-frame pictures. */
658
+ | {
659
+ kind: 'transition';
660
+ effect: string;
661
+ values: Record<string, EffectValue>;
662
+ progress: number;
663
+ time: number;
664
+ from: EffectPixels;
665
+ to: EffectPixels;
666
+ };
667
+ /**
668
+ * The cache key of a layer's processed picture at a canvas size: everything that changes the
669
+ * picture before placement (its content, the moment of source, the effects and their values),
670
+ * not where it is placed. A transition's key covers both of its pictures, placement included.
671
+ */
672
+ declare function videoEffectLayerKey(layer: VideoLayer, width: number, height: number): string;
673
+ /** `a` mixed towards `b` by `k` (0–1), as a new picture. */
674
+ declare function mixEffectPixels(a: EffectPixels, b: EffectPixels, k: number): EffectPixels;
675
+ /** `top` laid over `base` (straight alpha, source-over) at `opacity`, as a new picture. */
676
+ declare function overEffectPixels(base: EffectPixels, top: EffectPixels, opacity?: number): EffectPixels;
677
+ interface VideoEffectsEngineOptions {
678
+ /** The provider slot to follow (a controller passes its own). Default: a new one. */
679
+ slot?: EffectsSlot;
680
+ /** Rendered pictures kept (default 120, a few seconds of one layer). */
681
+ maxEntries?: number;
682
+ /** Live renderers kept (default 4): GPU providers hold a graphics context each (see `EffectRendererPool`). */
683
+ maxRenderers?: number;
684
+ /**
685
+ * Turns rendered pixels into something `drawImage` takes. Default: an `OffscreenCanvas` (or a
686
+ * `<canvas>`) holding them; `null` where neither exists.
687
+ */
688
+ toImage?: (pixels: EffectPixels) => CanvasImageSource | null;
689
+ }
690
+ /**
691
+ * Renders and caches provider effect pictures for one editor. It follows the editor's provider
692
+ * slot: with no provider it renders nothing (`available` is false), and a new provider clears the
693
+ * cache and disposes the old renderers.
694
+ */
695
+ declare class VideoEffectsEngine {
696
+ readonly slot: EffectsSlot;
697
+ private readonly cache;
698
+ private readonly pending;
699
+ private readonly failures;
700
+ private readonly pool;
701
+ private readonly descriptions;
702
+ private readonly listeners;
703
+ private readonly maxEntries;
704
+ private readonly toImage;
705
+ private generation;
706
+ private readonly detach;
707
+ constructor(options?: VideoEffectsEngineOptions);
708
+ get provider(): EffectProvider | null;
709
+ /** True when a provider is registered, so effects can be drawn. */
710
+ get available(): boolean;
711
+ /** The drawable picture for `key`, or `undefined` when it is not rendered (yet). */
712
+ get(key: string): CanvasImageSource | null | undefined;
713
+ /** The rendered pixels for `key`. */
714
+ pixels(key: string): EffectPixels | undefined;
715
+ /** Why the render for `key` failed, if it did (it is not retried until the cache is cleared). */
716
+ failure(key: string): Error | undefined;
717
+ /** Every failure so far, newest last. */
718
+ failuresList(): {
719
+ key: string;
720
+ error: Error;
721
+ }[];
722
+ /** Whether `key` is being rendered. */
723
+ isPending(key: string): boolean;
724
+ /**
725
+ * Starts rendering `job` into `key` unless it is cached, pending or failed. Returns true while
726
+ * the picture is on its way (so the frame is waiting for it).
727
+ */
728
+ request(key: string, job: VideoEffectJob): boolean;
729
+ /** Resolves when nothing is being rendered. */
730
+ idle(): Promise<void>;
731
+ /** Renders a job now, without the cache. Rejects with the provider's error. */
732
+ run(job: VideoEffectJob): Promise<EffectPixels>;
733
+ private stack;
734
+ /** The provider's description of an effect, fetched once. */
735
+ describe(provider: EffectProvider, id: string): Promise<EffectDescription>;
736
+ /** Renders through the pool: a few live renderers, one render at a time on each. */
737
+ private render;
738
+ /** Forgets every picture and failure and disposes the renderers (e.g. after the provider changes). */
739
+ reset(): void;
740
+ subscribe(listener: () => void): () => void;
741
+ private notify;
742
+ destroy(): void;
743
+ }
744
+ /** Which uses each place accepts. */
745
+ declare const VIDEO_EFFECT_PLACES: {
746
+ /** A clip's effect stack: filters change the picture, overlays draw over it. */
747
+ readonly clip: readonly ["filter", "overlay"];
748
+ readonly transition: readonly ["transition"];
749
+ /** An effect clip's picture. */
750
+ readonly generator: readonly ["generator", "title", "overlay"];
751
+ };
752
+ type VideoEffectPlace = keyof typeof VIDEO_EFFECT_PLACES;
753
+ /** Refuses an effect that cannot go in `place`, with what to use instead. */
754
+ declare function checkVideoEffectPlace(d: EffectDescription, place: VideoEffectPlace): void;
755
+ /**
756
+ * Checks values (plain, or keyframes for numeric controls when `keyframes`) against an effect's
757
+ * controls and returns them over `base` (default the effect's defaults). Throws
758
+ * `EffectControlError` naming every bad control.
759
+ */
760
+ declare function checkVideoEffectValues(d: EffectDescription, values: VideoEffectValues | undefined, options?: {
761
+ base?: VideoEffectValues;
762
+ keyframes?: boolean;
763
+ }): VideoEffectValues;
764
+
392
765
  interface VideoEdlOptions {
393
766
  /** Track to export (default: the bottom video track, V1 in most NLEs). */
394
767
  track?: string;
@@ -433,7 +806,21 @@ interface VideoFfmpegOptions {
433
806
  }) => string;
434
807
  /** Normalise the mix's loudness with ffmpeg's `loudnorm` (EBU R128). */
435
808
  loudness?: VideoLoudnessTarget;
809
+ /**
810
+ * The picture as frames the host rendered, instead of ffmpeg's filters: one per frame of the
811
+ * project's frame grid from 0, each the project's size rounded up to even numbers, drawn with
812
+ * `renderVideoFrameExact` (the preview's own drawing, provider effects included). `input` is an
813
+ * image sequence pattern (`frames/%06d.png`, format `image2`, the default) or raw RGBA on a
814
+ * pipe (`pipe:0`, format `rawvideo`). The sound is still mixed by ffmpeg. Projects that use
815
+ * provider effects need this: ffmpeg cannot draw them, so without it the export is refused.
816
+ */
817
+ frames?: {
818
+ input: string;
819
+ format?: 'image2' | 'rawvideo';
820
+ };
436
821
  }
822
+ /** The provider effects in a project's video tracks that ffmpeg's filters cannot draw. */
823
+ declare function videoFfmpegUnsupportedEffects(project: VideoProject): VideoEffectUse[];
437
824
  /** A loudness to normalise the mix to (`loudnorm`'s I, TP and LRA). */
438
825
  interface VideoLoudnessTarget {
439
826
  /** Integrated loudness, in LUFS (default -14, as streaming services play; -16 for podcasts, -23 for EBU R128 broadcast). */
@@ -498,4 +885,4 @@ declare function toVideoFfmpeg(project: VideoProject, options?: VideoFfmpegOptio
498
885
  */
499
886
  declare function toVideoLoudnessMeasure(project: VideoProject, options?: Pick<VideoFfmpegOptions, 'resolve' | 'loudness'>): VideoFfmpegExport;
500
887
 
501
- export { removeVideoKey as $, type VideoFfmpegExport as A, type VideoEdlOptions as B, type VideoAssetKind as C, type VideoClipAnimationEffect as D, type VideoTransitionType as E, VIDEO_BLEND_MODES as F, VIDEO_CLIP_ANIMATION_EFFECTS as G, VIDEO_CLIP_TYPES as H, VIDEO_EASE_NAMES as I, VIDEO_FADE_CURVES as J, VIDEO_FITS as K, VIDEO_KEYFRAME_LIMITS as L, VIDEO_KEYFRAME_PROPERTIES as M, VIDEO_PLACEMENT_MODES as N, VIDEO_TRANSFORM_PROPERTIES as O, VIDEO_TRANSITION_TYPES as P, VIDEO_WIPE_DIRECTIONS as Q, type VideoClipType as R, type VideoColorClip as S, type VideoEase as T, type VideoLoudnessMeasurement as U, type VideoProject as V, type VideoLoudnessTarget as W, type VideoSequenceClip as X, ffmpegFilterValue as Y, isVideoKeyframes as Z, parseVideoLoudnessMeasurement as _, type VideoAnimatable as a, retimeVideoAnimatable as a0, setVideoKey as a1, sortVideoKeys as a2, splitVideoAnimatable as a3, toVideoEdl as a4, toVideoFfmpeg as a5, toVideoLoudnessMeasure as a6, videoEaseBezier as a7, videoEaseProgress as a8, videoKeyframeBreakpoints as a9, videoKeyframeFfmpegExpr as aa, videoShellQuote as ab, videoTransitionAudioCurve as ac, videoValueAt as ad, type VideoAsset as b, type VideoAssetProxy as c, type VideoClip as d, type VideoClipAnimation as e, type VideoGrade as f, type VideoGradeLut as g, type VideoKeyframes as h, type VideoMarker as i, type VideoSequence as j, type VideoTrack as k, type VideoTranscriptWord as l, type VideoTransform as m, type VideoTransition as n, type VideoTrackKind as o, type VideoPlacementMode as p, type VideoKeyframeProperty as q, type VideoKey as r, type VideoWipeDirection as s, type VideoBlendMode as t, type VideoFit as u, videoKeysOf as v, type VideoFadeCurve as w, type VideoTextClip as x, type VideoMediaClip as y, type VideoFfmpegOptions as z };
888
+ export { type VideoColorClip as $, type VideoRect as A, type VideoEffectPlace as B, type VideoFfmpegOptions as C, type VideoFfmpegExport as D, type VideoEdlOptions as E, type VideoFadeCurve as F, type VideoFit as G, type VideoBlendMode as H, type VideoAssetKind as I, type VideoClipAnimationEffect as J, type VideoTransitionType as K, VIDEO_BLEND_MODES as L, VIDEO_CLIP_ANIMATION_EFFECTS as M, VIDEO_CLIP_TYPES as N, VIDEO_EASE_NAMES as O, VIDEO_EFFECT_PLACES as P, VIDEO_FADE_CURVES as Q, VIDEO_FITS as R, VIDEO_KEYFRAME_LIMITS as S, VIDEO_KEYFRAME_PROPERTIES as T, VIDEO_PLACEMENT_MODES as U, type VideoProject as V, VIDEO_TRANSFORM_PROPERTIES as W, VIDEO_TRANSITION_TYPES as X, VIDEO_WIPE_DIRECTIONS as Y, type VideoAudioSource as Z, type VideoClipType as _, type VideoAnimatable as a, type VideoEase as a0, type VideoEffectClip as a1, type VideoEffectJob as a2, type VideoEffectUse as a3, type VideoEffectsEngineOptions as a4, type VideoLayerEffect as a5, type VideoLoudnessMeasurement as a6, type VideoLoudnessTarget as a7, type VideoSequenceClip as a8, type VideoTextClip as a9, videoFrameAt as aA, videoFrameLeafLayers as aB, videoKeyframeBreakpoints as aC, videoKeyframeFfmpegExpr as aD, videoLayersUseEffects as aE, videoLayersWithoutTransitionEffects as aF, videoProjectEffects as aG, videoShellQuote as aH, videoTextStyle as aI, videoTitleFrame as aJ, videoTransformAt as aK, videoTransitionAudioCurve as aL, videoTransitionEase as aM, videoValueAt as aN, type VideoWipeDirection as aa, checkVideoEffectPlace as ab, checkVideoEffectValues as ac, ffmpegFilterValue as ad, isVideoKeyframes as ae, mixEffectPixels as af, overEffectPixels as ag, parseVideoLoudnessMeasurement as ah, placeVideoRect as ai, removeVideoKey as aj, retimeVideoAnimatable as ak, setVideoKey as al, sortVideoKeys as am, splitVideoAnimatable as an, toVideoEdl as ao, toVideoFfmpeg as ap, toVideoLoudnessMeasure as aq, videoClipEffectUses as ar, videoClipSoundGain as as, videoEaseBezier as at, videoEaseProgress as au, videoEffectFrameTime as av, videoEffectLayerKey as aw, videoEffectValuesAt as ax, videoFadeCurveGain as ay, videoFfmpegUnsupportedEffects as az, type VideoAsset as b, type VideoAssetProxy as c, type VideoClip as d, type VideoClipAnimation as e, type VideoClipEffect as f, type VideoEffectRef as g, type VideoEffectValues as h, type VideoGrade as i, type VideoGradeLut as j, type VideoKeyframes as k, type VideoMarker as l, type VideoSequence as m, type VideoTrack as n, type VideoTranscriptWord as o, type VideoTransform as p, type VideoTransition as q, type VideoTrackKind as r, type VideoPlacementMode as s, type VideoKeyframeProperty as t, type VideoKey as u, videoKeysOf as v, type VideoMediaClip as w, VideoEffectsEngine as x, type VideoLayer as y, type VideoFrame as z };