remotion 4.0.454 → 4.0.456

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 (60) hide show
  1. package/dist/cjs/CompositionManager.d.ts +2 -0
  2. package/dist/cjs/HtmlInCanvas.d.ts +49 -22
  3. package/dist/cjs/HtmlInCanvas.js +173 -88
  4. package/dist/cjs/Img.js +1 -1
  5. package/dist/cjs/Sequence.d.ts +11 -1
  6. package/dist/cjs/Sequence.js +36 -3
  7. package/dist/cjs/audio/Audio.d.ts +34 -34
  8. package/dist/cjs/audio/Audio.js +6 -6
  9. package/dist/cjs/audio/html5-audio.d.ts +56 -0
  10. package/dist/cjs/audio/html5-audio.js +101 -0
  11. package/dist/cjs/audio/index.d.ts +1 -1
  12. package/dist/cjs/audio/index.js +3 -3
  13. package/dist/cjs/{canvas-effects → effects}/Solid.d.ts +1 -1
  14. package/dist/cjs/{canvas-effects → effects}/Solid.js +13 -8
  15. package/dist/cjs/{canvas-effects → effects}/canvas-pool.js +2 -4
  16. package/dist/cjs/{canvas-effects → effects}/define-effect.d.ts +1 -1
  17. package/dist/cjs/{canvas-effects → effects}/define-effect.js +8 -4
  18. package/dist/cjs/{canvas-effects → effects}/effect-internals.d.ts +1 -1
  19. package/dist/cjs/{canvas-effects → effects}/effect-types.d.ts +4 -5
  20. package/dist/cjs/{canvas-effects → effects}/effect-types.js +1 -2
  21. package/dist/cjs/effects/index.d.ts +1 -0
  22. package/dist/cjs/{enable-effects.js → effects/index.js} +0 -2
  23. package/dist/cjs/{canvas-effects → effects}/run-effect-chain.d.ts +3 -4
  24. package/dist/cjs/{canvas-effects → effects}/run-effect-chain.js +20 -24
  25. package/dist/cjs/effects/use-effect-chain-state.d.ts +4 -0
  26. package/dist/cjs/effects/use-effect-chain-state.js +31 -0
  27. package/dist/cjs/get-timeline-duration.d.ts +2 -1
  28. package/dist/cjs/get-timeline-duration.js +4 -1
  29. package/dist/cjs/index.d.ts +5 -0
  30. package/dist/cjs/index.js +6 -1
  31. package/dist/cjs/internals.d.ts +16 -3
  32. package/dist/cjs/internals.js +9 -0
  33. package/dist/cjs/loop/index.d.ts +2 -2
  34. package/dist/cjs/loop/index.js +2 -2
  35. package/dist/cjs/use-media-in-timeline.d.ts +8 -2
  36. package/dist/cjs/use-media-in-timeline.js +43 -15
  37. package/dist/cjs/version.d.ts +1 -1
  38. package/dist/cjs/version.js +1 -1
  39. package/dist/cjs/video/Video.d.ts +32 -32
  40. package/dist/cjs/video/Video.js +7 -7
  41. package/dist/cjs/video/html5-video.d.ts +53 -0
  42. package/dist/cjs/video/html5-video.js +85 -0
  43. package/dist/cjs/video/index.d.ts +1 -1
  44. package/dist/cjs/video/index.js +3 -3
  45. package/dist/cjs/wrap-in-schema.d.ts +1 -1
  46. package/dist/cjs/wrap-in-schema.js +2 -2
  47. package/dist/esm/index.mjs +1509 -799
  48. package/dist/esm/version.mjs +1 -1
  49. package/package.json +2 -2
  50. package/dist/cjs/canvas-effects/index.d.ts +0 -4
  51. package/dist/cjs/canvas-effects/index.js +0 -8
  52. package/dist/cjs/canvas-effects/use-effect-chain-state.d.ts +0 -2
  53. package/dist/cjs/canvas-effects/use-effect-chain-state.js +0 -27
  54. package/dist/cjs/enable-effects.d.ts +0 -1
  55. /package/dist/cjs/{canvas-effects → effects}/canvas-pool.d.ts +0 -0
  56. /package/dist/cjs/{canvas-effects → effects}/effect-internals.js +0 -0
  57. /package/dist/cjs/{canvas-effects → effects}/gpu-device.d.ts +0 -0
  58. /package/dist/cjs/{canvas-effects → effects}/gpu-device.js +0 -0
  59. /package/dist/cjs/{canvas-effects → effects}/use-memoized-effects.d.ts +0 -0
  60. /package/dist/cjs/{canvas-effects → effects}/use-memoized-effects.js +0 -0
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import type { AnyZodObject } from './any-zod-type.js';
4
4
  import type { CalculateMetadataFunction } from './Composition.js';
5
5
  import type { DownloadBehavior } from './download-behavior.js';
6
+ import type { EffectDefinitionAndStack } from './effects/effect-types.js';
6
7
  import type { NonceHistory } from './nonce.js';
7
8
  import type { InferProps, PropsIfHasProps } from './props-if-has-props.js';
8
9
  import type { SequenceSchema } from './sequence-field-schema.js';
@@ -68,6 +69,7 @@ export type TSequence = {
68
69
  premountDisplay: number | null;
69
70
  postmountDisplay: number | null;
70
71
  controls: SequenceControls | null;
72
+ effects: EffectDefinitionAndStack<unknown>[];
71
73
  } & EnhancedTSequenceData;
72
74
  export type AudioOrVideoAsset = {
73
75
  type: 'audio' | 'video';
@@ -1,32 +1,59 @@
1
1
  import React from 'react';
2
- import type { EffectsProp } from './canvas-effects/effect-types.js';
2
+ import type { EffectsProp } from './effects/effect-types.js';
3
3
  import type { AbsoluteFillLayout, LayoutAndStyle, SequenceProps } from './Sequence.js';
4
- export type HtmlInCanvasComposeParams = {
5
- readonly source: CanvasImageSource;
6
- readonly target: HTMLCanvasElement;
7
- readonly frame: number;
8
- readonly width: number;
9
- readonly height: number;
10
- readonly pixelRatio: number;
4
+ declare global {
5
+ interface ElementImage {
6
+ readonly width: number;
7
+ readonly height: number;
8
+ close(): void;
9
+ }
10
+ interface CanvasRenderingContext2D {
11
+ drawElementImage(element: Element | ElementImage, dx: number, dy: number): DOMMatrix;
12
+ drawElementImage(element: Element | ElementImage, dx: number, dy: number, dwidth: number, dheight: number): DOMMatrix;
13
+ drawElementImage(element: Element | ElementImage, sx: number, sy: number, swidth: number, sheight: number, dx: number, dy: number): DOMMatrix;
14
+ drawElementImage(element: Element | ElementImage, sx: number, sy: number, swidth: number, sheight: number, dx: number, dy: number, dwidth: number, dheight: number): DOMMatrix;
15
+ }
16
+ interface OffscreenCanvasRenderingContext2D {
17
+ drawElementImage(element: ElementImage, dx: number, dy: number): DOMMatrix;
18
+ drawElementImage(element: ElementImage, dx: number, dy: number, dwidth: number, dheight: number): DOMMatrix;
19
+ drawElementImage(element: ElementImage, sx: number, sy: number, swidth: number, sheight: number, dx: number, dy: number): DOMMatrix;
20
+ drawElementImage(element: ElementImage, sx: number, sy: number, swidth: number, sheight: number, dx: number, dy: number, dwidth: number, dheight: number): DOMMatrix;
21
+ }
22
+ interface WebGLRenderingContextBase {
23
+ texElementImage2D(target: GLenum, level: GLint, internalformat: GLint, format: GLenum, type: GLenum, element: Element | ElementImage): void;
24
+ texElementImage2D(target: GLenum, level: GLint, internalformat: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, element: Element | ElementImage): void;
25
+ texElementImage2D(target: GLenum, level: GLint, internalformat: GLint, sx: GLfloat, sy: GLfloat, swidth: GLfloat, sheight: GLfloat, format: GLenum, type: GLenum, element: Element | ElementImage): void;
26
+ texElementImage2D(target: GLenum, level: GLint, internalformat: GLint, sx: GLfloat, sy: GLfloat, swidth: GLfloat, sheight: GLfloat, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, element: Element | ElementImage): void;
27
+ }
28
+ interface HTMLCanvasElementEventMap {
29
+ paint: Event;
30
+ }
31
+ interface HTMLCanvasElement {
32
+ layoutSubtree?: boolean;
33
+ onpaint: ((this: HTMLCanvasElement, ev: Event) => unknown) | null;
34
+ requestPaint?(): void;
35
+ captureElementImage(element: Element): ElementImage;
36
+ getElementTransform(element: Element | ElementImage, drawTransform: DOMMatrix): DOMMatrix;
37
+ }
38
+ }
39
+ export type HtmlInCanvasOnPaintParams = {
40
+ readonly canvas: OffscreenCanvas;
41
+ readonly element: HTMLDivElement;
42
+ readonly elementImage: ElementImage;
11
43
  };
12
44
  export declare const isHtmlInCanvasSupported: () => boolean;
13
- export type HtmlInCanvasProps = Omit<SequenceProps, 'children' | 'durationInFrames' | keyof LayoutAndStyle> & Omit<AbsoluteFillLayout, 'layout'> & {
45
+ export type HtmlInCanvasOnPaint = (params: HtmlInCanvasOnPaintParams) => void | Promise<void>;
46
+ export type HtmlInCanvasOnInitCleanup = () => void;
47
+ export type HtmlInCanvasOnInit = (params: HtmlInCanvasOnPaintParams) => HtmlInCanvasOnInitCleanup | Promise<HtmlInCanvasOnInitCleanup>;
48
+ export type HtmlInCanvasProps = Omit<SequenceProps, 'children' | 'durationInFrames' | keyof LayoutAndStyle> & Omit<AbsoluteFillLayout, 'layout' | 'styleWhilePostmounted' | 'postmountFor' | 'premountFor' | 'styleWhilePremounted'> & {
14
49
  readonly durationInFrames?: number;
15
50
  readonly width: number;
16
51
  readonly height: number;
17
- readonly effects?: EffectsProp;
52
+ readonly _experimentalEffects?: EffectsProp;
18
53
  readonly children: React.ReactNode;
19
- readonly pixelRatio?: number;
20
- readonly onCompose?: (params: HtmlInCanvasComposeParams) => void | Promise<void>;
54
+ readonly onPaint?: HtmlInCanvasOnPaint;
55
+ readonly onInit?: HtmlInCanvasOnInit;
21
56
  };
22
- export declare const HtmlInCanvas: React.ComponentType<Omit<SequenceProps, "children" | "durationInFrames" | "layout"> & Omit<AbsoluteFillLayout, "layout"> & {
23
- readonly durationInFrames?: number | undefined;
24
- readonly width: number;
25
- readonly height: number;
26
- readonly effects?: EffectsProp | undefined;
27
- readonly children: React.ReactNode;
28
- readonly pixelRatio?: number | undefined;
29
- readonly onCompose?: ((params: HtmlInCanvasComposeParams) => void | Promise<void>) | undefined;
30
- }> & {
31
- readonly isHtmlInCanvasSupported: () => boolean;
57
+ export declare const HtmlInCanvas: React.ForwardRefExoticComponent<HtmlInCanvasProps & React.RefAttributes<HTMLCanvasElement>> & {
58
+ readonly isHtmlInCanvasSupported: typeof isHtmlInCanvasSupported;
32
59
  };
@@ -3,24 +3,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HtmlInCanvas = exports.isHtmlInCanvasSupported = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
- const run_effect_chain_js_1 = require("./canvas-effects/run-effect-chain.js");
7
- const use_effect_chain_state_js_1 = require("./canvas-effects/use-effect-chain-state.js");
6
+ const delay_render_js_1 = require("./delay-render.js");
7
+ const run_effect_chain_js_1 = require("./effects/run-effect-chain.js");
8
+ const use_effect_chain_state_js_1 = require("./effects/use-effect-chain-state.js");
8
9
  const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js");
9
10
  const Sequence_js_1 = require("./Sequence.js");
10
11
  const use_current_frame_js_1 = require("./use-current-frame.js");
11
12
  const use_delay_render_js_1 = require("./use-delay-render.js");
12
13
  const use_video_config_js_1 = require("./use-video-config.js");
13
14
  const wrap_in_schema_js_1 = require("./wrap-in-schema.js");
15
+ // Memoize the support check across the session — neither the platform
16
+ // capability nor the chrome://flags toggle can change between calls.
17
+ // SSR results are not cached so the check runs again once `document` exists.
18
+ let cachedSupport = null;
14
19
  const isHtmlInCanvasSupported = () => {
20
+ if (cachedSupport !== null) {
21
+ return cachedSupport;
22
+ }
15
23
  if (typeof document === 'undefined') {
16
24
  return false;
17
25
  }
18
26
  const canvas = document.createElement('canvas');
19
27
  const ctx = canvas.getContext('2d');
20
- return (typeof (ctx === null || ctx === void 0 ? void 0 : ctx.drawElementImage) === 'function' &&
21
- typeof canvas.requestPaint === 'function');
28
+ cachedSupport =
29
+ typeof (ctx === null || ctx === void 0 ? void 0 : ctx.drawElementImage) === 'function' &&
30
+ typeof canvas.requestPaint === 'function' &&
31
+ typeof canvas.captureElementImage === 'function';
32
+ return cachedSupport;
22
33
  };
23
34
  exports.isHtmlInCanvasSupported = isHtmlInCanvasSupported;
35
+ function assertHtmlInCanvasDimensions(width, height) {
36
+ if (typeof width !== 'number' || typeof height !== 'number') {
37
+ throw new Error(`HtmlInCanvas: \`width\` and \`height\` must be numbers. Received width=${String(width)}, height=${String(height)}.`);
38
+ }
39
+ if (!Number.isInteger(width) || width <= 0) {
40
+ throw new Error(`HtmlInCanvas: \`width\` must be a positive integer. Received: ${String(width)}.`);
41
+ }
42
+ if (!Number.isInteger(height) || height <= 0) {
43
+ throw new Error(`HtmlInCanvas: \`height\` must be a positive integer. Received: ${String(height)}.`);
44
+ }
45
+ }
46
+ const defaultOnPaint = ({ canvas, element, elementImage, }) => {
47
+ const ctx = canvas.getContext('2d');
48
+ if (!ctx) {
49
+ throw new Error('Failed to acquire 2D context for <HtmlInCanvas> canvas');
50
+ }
51
+ ctx.reset();
52
+ const transform = ctx.drawElementImage(elementImage, 0, 0);
53
+ element.style.transform = transform.toString();
54
+ };
55
+ /* eslint-enable react/require-default-props */
24
56
  const htmlInCanvasSchema = {
25
57
  'style.translate': {
26
58
  type: 'translate',
@@ -51,119 +83,172 @@ const htmlInCanvasSchema = {
51
83
  description: 'Opacity',
52
84
  },
53
85
  };
54
- const HtmlInCanvasInner = ({ width, height, effects = [], children, style, pixelRatio = 1, onCompose, controls, durationInFrames, ...sequenceProps }) => {
86
+ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, _experimentalEffects: experimentalEffects = [], children, onPaint, onInit, _experimentalControls: controls, style, durationInFrames, ...sequenceProps }, ref) => {
87
+ assertHtmlInCanvasDimensions(width, height);
88
+ const { continueRender, cancelRender } = (0, use_delay_render_js_1.useDelayRender)();
89
+ if (!(0, exports.isHtmlInCanvasSupported)()) {
90
+ cancelRender(new Error('HTML in Canvas is not supported. Open this page in Chrome Canary with chrome://flags/#canvas-draw-element enabled.'));
91
+ }
55
92
  const { durationInFrames: videoDuration } = (0, use_video_config_js_1.useVideoConfig)();
56
93
  const resolvedDuration = durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : videoDuration;
57
94
  const frame = (0, use_current_frame_js_1.useCurrentFrame)();
58
- const { delayRender, continueRender, cancelRender } = (0, use_delay_render_js_1.useDelayRender)();
59
- const canvasRef = (0, react_1.useRef)(null);
60
- const sceneRef = (0, react_1.useRef)(null);
61
- const chainState = (0, use_effect_chain_state_js_1.useEffectChainState)(width, height);
95
+ const canvas2dRef = (0, react_1.useRef)(null);
96
+ const divRef = (0, react_1.useRef)(null);
97
+ const setLayoutCanvasRef = (0, react_1.useCallback)((node) => {
98
+ canvas2dRef.current = node;
99
+ if (typeof ref === 'function') {
100
+ ref(node);
101
+ }
102
+ else if (ref) {
103
+ ref.current =
104
+ node;
105
+ }
106
+ }, [ref]);
107
+ const [offscreenCanvas] = (0, react_1.useState)(() => new OffscreenCanvas(1, 1));
108
+ const chainState = (0, use_effect_chain_state_js_1.useEffectChainState)();
62
109
  // Refs so the paint handler always reads fresh values.
63
- const effectsRef = (0, react_1.useRef)(effects);
64
- effectsRef.current = effects;
110
+ const effectsRef = (0, react_1.useRef)(experimentalEffects);
111
+ effectsRef.current = experimentalEffects;
65
112
  const frameRef = (0, react_1.useRef)(frame);
66
113
  frameRef.current = frame;
67
- const pixelRatioRef = (0, react_1.useRef)(pixelRatio);
68
- pixelRatioRef.current = pixelRatio;
69
- const widthRef = (0, react_1.useRef)(width);
70
- widthRef.current = width;
71
- const heightRef = (0, react_1.useRef)(height);
72
- heightRef.current = height;
73
- // Track the current delayRender handle so the paint handler can settle it.
74
- const pendingHandleRef = (0, react_1.useRef)(null);
75
- const onPaint = (0, react_1.useCallback)(() => {
76
- const canvas = canvasRef.current;
77
- const sceneEl = sceneRef.current;
78
- const handle = pendingHandleRef.current;
79
- if (!canvas || !sceneEl || !chainState || handle === null) {
80
- return;
114
+ const onPaintRef = (0, react_1.useRef)(onPaint);
115
+ onPaintRef.current = onPaint;
116
+ const onInitRef = (0, react_1.useRef)(onInit);
117
+ onInitRef.current = onInit;
118
+ const initializedRef = (0, react_1.useRef)(false);
119
+ const onInitCleanupRef = (0, react_1.useRef)(null);
120
+ const unmountedRef = (0, react_1.useRef)(false);
121
+ const onPaintCb = (0, react_1.useCallback)(async () => {
122
+ var _a;
123
+ const element = divRef.current;
124
+ if (!element) {
125
+ throw new Error('Canvas or scene element not found');
81
126
  }
127
+ offscreenCanvas.width = width;
128
+ offscreenCanvas.height = height;
82
129
  try {
83
- const ctx = canvas.getContext('2d');
84
- if (!ctx) {
85
- throw new Error('Failed to acquire 2D context for <HtmlInCanvas> canvas');
130
+ const layoutCanvas = canvas2dRef.current;
131
+ if (!layoutCanvas) {
132
+ throw new Error('Canvas not found');
133
+ }
134
+ // `GPUQueue.copyElementImageToTexture` / related paths validate the
135
+ // layout canvas has a rendering context. `runEffectChain` only runs
136
+ // after `onPaint`, so acquire `2d` here before any capture or handler.
137
+ const layout2d = layoutCanvas.getContext('2d');
138
+ if (!layout2d) {
139
+ throw new Error('Failed to acquire 2D context for <HtmlInCanvas> layout canvas');
86
140
  }
87
- const w = widthRef.current;
88
- const h = heightRef.current;
89
- // Layout-subtree children are not shown on-screen until rasterized here;
90
- // effects then read from and write back to this same surface (via pool).
91
- ctx.reset();
92
- ctx.drawElementImage(sceneEl, 0, 0, w, h);
93
- const capturedHandle = handle;
94
- pendingHandleRef.current = null;
95
- (0, run_effect_chain_js_1.runEffectChain)({
96
- state: chainState,
97
- source: canvas,
141
+ const handle = (0, delay_render_js_1.delayRender)('onPaint');
142
+ if (!initializedRef.current) {
143
+ initializedRef.current = true;
144
+ // `onInit` may be async (e.g. WebGPU `requestAdapter`/`requestDevice`).
145
+ // Capture an `ElementImage` here only for `onInit` consumers — do NOT
146
+ // reuse it for the paint handler below, because awaiting `onInit`
147
+ // can invalidate the capture's paint context, leaving subsequent
148
+ // uploads (e.g. `copyElementImageToTexture`) failing with
149
+ // "No context found for ElementImage" on the very first paint.
150
+ const initImage = layoutCanvas.captureElementImage(element);
151
+ const currentOnInit = onInitRef.current;
152
+ if (currentOnInit) {
153
+ const cleanup = await currentOnInit({
154
+ canvas: offscreenCanvas,
155
+ element,
156
+ elementImage: initImage,
157
+ });
158
+ if (typeof cleanup !== 'function') {
159
+ throw new Error('HtmlInCanvas: when `onInit` is provided, it must return a cleanup function, or a Promise that resolves to one.');
160
+ }
161
+ if (unmountedRef.current) {
162
+ cleanup();
163
+ }
164
+ else {
165
+ onInitCleanupRef.current = cleanup;
166
+ }
167
+ }
168
+ }
169
+ const handler = (_a = onPaintRef.current) !== null && _a !== void 0 ? _a : defaultOnPaint;
170
+ const elImage = layoutCanvas.captureElementImage(element);
171
+ await handler({
172
+ canvas: offscreenCanvas,
173
+ element,
174
+ elementImage: elImage,
175
+ });
176
+ await (0, run_effect_chain_js_1.runEffectChain)({
177
+ state: chainState.get(width, height),
178
+ source: offscreenCanvas,
98
179
  effects: effectsRef.current,
99
- output: canvas,
180
+ output: canvas2dRef.current,
100
181
  frame: frameRef.current,
101
- width: w,
102
- height: h,
103
- pixelRatio: pixelRatioRef.current,
104
- })
105
- .then((completed) => {
106
- if (completed) {
107
- continueRender(capturedHandle);
108
- }
109
- })
110
- .catch((err) => {
111
- cancelRender(err);
182
+ width,
183
+ height,
112
184
  });
185
+ continueRender(handle);
113
186
  }
114
187
  catch (error) {
115
188
  cancelRender(error);
116
189
  }
117
- }, [chainState, continueRender, cancelRender]);
118
- // Set up layoutSubtree and persistent paint listener.
119
- (0, react_1.useEffect)(() => {
120
- if (!(0, exports.isHtmlInCanvasSupported)()) {
121
- cancelRender(new Error('HTML in Canvas is not supported. Open this page in Chrome Canary with chrome://flags/#canvas-draw-element enabled.'));
122
- return;
123
- }
124
- const canvas = canvasRef.current;
190
+ }, [
191
+ chainState,
192
+ continueRender,
193
+ cancelRender,
194
+ width,
195
+ height,
196
+ offscreenCanvas,
197
+ ]);
198
+ // Set up layoutSubtree and persistent paint listener. Runs as a
199
+ // layout effect so the listener is attached before the resize effect
200
+ // below dispatches its first synthetic paint.
201
+ (0, react_1.useLayoutEffect)(() => {
202
+ const canvas = canvas2dRef.current;
125
203
  if (!canvas) {
126
- return;
204
+ throw new Error('Canvas not found');
127
205
  }
128
206
  canvas.layoutSubtree = true;
129
- canvas.addEventListener('paint', onPaint);
207
+ canvas.addEventListener('paint', onPaintCb);
130
208
  return () => {
131
- canvas.removeEventListener('paint', onPaint);
209
+ var _a;
210
+ canvas.removeEventListener('paint', onPaintCb);
211
+ unmountedRef.current = true;
212
+ (_a = onInitCleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(onInitCleanupRef);
213
+ onInitCleanupRef.current = null;
132
214
  };
133
- }, [onPaint, cancelRender]);
134
- // On each frame change: block the renderer and request a paint.
135
- (0, react_1.useEffect)(() => {
136
- const handle = delayRender(`HtmlInCanvas (frame ${frame})`);
137
- // Continue a stale handle from a previous frame that never got a paint.
138
- if (pendingHandleRef.current !== null) {
139
- continueRender(pendingHandleRef.current);
215
+ }, [onPaintCb, cancelRender]);
216
+ const onPaintChangedRef = (0, react_1.useRef)(false);
217
+ (0, react_1.useLayoutEffect)(() => {
218
+ var _a;
219
+ if (!onPaintChangedRef.current) {
220
+ onPaintChangedRef.current = true;
221
+ return;
140
222
  }
141
- pendingHandleRef.current = handle;
142
- const canvas = canvasRef.current;
143
- canvas === null || canvas === void 0 ? void 0 : canvas.requestPaint();
223
+ const canvas = canvas2dRef.current;
224
+ if (!canvas) {
225
+ return;
226
+ }
227
+ (_a = canvas.requestPaint) === null || _a === void 0 ? void 0 : _a.call(canvas);
228
+ }, [onPaint]);
229
+ (0, react_1.useLayoutEffect)(() => {
230
+ const canvas = canvas2dRef.current;
231
+ if (!canvas) {
232
+ return;
233
+ }
234
+ const handle = (0, delay_render_js_1.delayRender)('waiting for first paint after canvas resize');
235
+ canvas.addEventListener('paint', () => {
236
+ continueRender(handle);
237
+ }, { once: true });
144
238
  return () => {
145
- if (pendingHandleRef.current === handle) {
146
- continueRender(handle);
147
- pendingHandleRef.current = null;
148
- }
239
+ continueRender(handle);
149
240
  };
150
- }, [frame, delayRender, continueRender]);
151
- const outerStyle = (0, react_1.useMemo)(() => {
152
- return {
153
- position: 'absolute',
154
- inset: 0,
155
- width: width + 'px',
156
- height: height + 'px',
157
- };
158
- }, [width, height]);
241
+ }, [width, height, continueRender]);
159
242
  const innerStyle = (0, react_1.useMemo)(() => {
160
243
  return {
161
244
  width,
162
245
  height,
246
+ ...style,
163
247
  };
164
- }, [width, height]);
165
- return (jsx_runtime_1.jsx(Sequence_js_1.Sequence, { durationInFrames: resolvedDuration, name: "<HtmlInCanvas>", controls: controls, ...sequenceProps, style: style, children: jsx_runtime_1.jsx("canvas", { ref: canvasRef, width: width, height: height, style: outerStyle, children: jsx_runtime_1.jsx("div", { ref: sceneRef, style: innerStyle, children: children }) }) }));
166
- };
248
+ }, [width, height, style]);
249
+ return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { durationInFrames: resolvedDuration, name: "<HtmlInCanvas>", _experimentalControls: controls, layout: "none", ...sequenceProps, children: (0, jsx_runtime_1.jsx)("canvas", { ref: setLayoutCanvasRef, width: width, height: height, children: (0, jsx_runtime_1.jsx)("div", { ref: divRef, style: innerStyle, children: children }) }) }));
250
+ });
251
+ HtmlInCanvasInner.displayName = 'HtmlInCanvas';
167
252
  const HtmlInCanvasWrapped = (0, wrap_in_schema_js_1.wrapInSchema)(HtmlInCanvasInner, htmlInCanvasSchema);
168
253
  exports.HtmlInCanvas = Object.assign(HtmlInCanvasWrapped, {
169
254
  isHtmlInCanvasSupported: exports.isHtmlInCanvasSupported,
package/dist/cjs/Img.js CHANGED
@@ -54,7 +54,7 @@ const imgSchema = {
54
54
  description: 'Opacity',
55
55
  },
56
56
  };
57
- const ImgInner = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, showInTimeline, name, stack, ref, controls, ...props }) => {
57
+ const ImgInner = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, showInTimeline, name, stack, ref, _experimentalControls: controls, ...props }) => {
58
58
  var _a, _b;
59
59
  const imageRef = (0, react_1.useRef)(null);
60
60
  const errors = (0, react_1.useRef)({});
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { LoopDisplay, SequenceControls } from './CompositionManager.js';
3
+ import type { EffectsProp } from './effects/effect-types.js';
4
+ import type { BasicMediaInTimelineReturnType } from './use-media-in-timeline.js';
3
5
  export type AbsoluteFillLayout = {
4
6
  layout?: 'absolute-fill';
5
7
  premountFor?: number;
@@ -19,7 +21,8 @@ export type SequencePropsWithoutDuration = {
19
21
  readonly from?: number;
20
22
  readonly name?: string;
21
23
  readonly showInTimeline?: boolean;
22
- readonly controls?: SequenceControls;
24
+ readonly _experimentalControls?: SequenceControls;
25
+ readonly _experimentalEffects?: EffectsProp;
23
26
  /**
24
27
  * @deprecated For internal use only.
25
28
  */
@@ -44,6 +47,13 @@ export type SequencePropsWithoutDuration = {
44
47
  * @deprecated For internal use only.
45
48
  */
46
49
  readonly _remotionInternalIsPostmounting?: boolean;
50
+ /**
51
+ * @deprecated For internal use only.
52
+ */
53
+ readonly _remotionInternalIsMedia?: {
54
+ type: 'video' | 'audio';
55
+ data: BasicMediaInTimelineReturnType;
56
+ };
47
57
  } & LayoutAndStyle;
48
58
  export type SequenceProps = {
49
59
  readonly durationInFrames?: number;
@@ -5,6 +5,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  /* eslint-disable @typescript-eslint/no-use-before-define */
6
6
  const react_1 = require("react");
7
7
  const AbsoluteFill_js_1 = require("./AbsoluteFill.js");
8
+ const effect_internals_js_1 = require("./effects/effect-internals.js");
9
+ const use_memoized_effects_js_1 = require("./effects/use-memoized-effects.js");
8
10
  const freeze_js_1 = require("./freeze.js");
9
11
  const nonce_js_1 = require("./nonce.js");
10
12
  const PremountContext_js_1 = require("./PremountContext.js");
@@ -15,7 +17,7 @@ const use_current_frame_1 = require("./use-current-frame");
15
17
  const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
16
18
  const use_video_config_js_1 = require("./use-video-config.js");
17
19
  const v5_flag_js_1 = require("./v5-flag.js");
18
- const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Infinity, children, name, height, width, showInTimeline = true, controls, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, ...other }, ref) => {
20
+ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Infinity, children, name, height, width, showInTimeline = true, _experimentalControls: controls, _experimentalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, ...other }, ref) => {
19
21
  var _a, _b;
20
22
  const { layout = 'absolute-fill' } = other;
21
23
  const [id] = (0, react_1.useState)(() => String(Math.random()));
@@ -95,17 +97,45 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
95
97
  }, [name]);
96
98
  const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
97
99
  const inheritedStack = (_a = other === null || other === void 0 ? void 0 : other.stack) !== null && _a !== void 0 ? _a : null;
100
+ const memoizedEffects = (0, use_memoized_effects_js_1.useMemoizedEffects)((0, effect_internals_js_1.flattenEffects)(_experimentalEffects !== null && _experimentalEffects !== void 0 ? _experimentalEffects : []));
98
101
  (0, react_1.useEffect)(() => {
99
- var _a;
102
+ var _a, _b;
100
103
  if (!env.isStudio) {
101
104
  return;
102
105
  }
106
+ if (isMedia) {
107
+ registerSequence({
108
+ type: isMedia.type,
109
+ controls: controls !== null && controls !== void 0 ? controls : null,
110
+ effects: memoizedEffects,
111
+ displayName: timelineClipName,
112
+ doesVolumeChange: isMedia.data.doesVolumeChange,
113
+ duration: actualDurationInFrames,
114
+ from,
115
+ id,
116
+ loopDisplay,
117
+ nonce: nonce.get(),
118
+ parent: (_a = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _a !== void 0 ? _a : null,
119
+ playbackRate: isMedia.data.playbackRate,
120
+ postmountDisplay: postmountDisplay !== null && postmountDisplay !== void 0 ? postmountDisplay : null,
121
+ premountDisplay: premountDisplay !== null && premountDisplay !== void 0 ? premountDisplay : null,
122
+ rootId,
123
+ showInTimeline,
124
+ src: isMedia.data.src,
125
+ stack: stack !== null && stack !== void 0 ? stack : inheritedStack,
126
+ startMediaFrom: isMedia.data.startMediaFrom,
127
+ volume: isMedia.data.volumes,
128
+ });
129
+ return () => {
130
+ unregisterSequence(id);
131
+ };
132
+ }
103
133
  registerSequence({
104
134
  from,
105
135
  duration: actualDurationInFrames,
106
136
  id,
107
137
  displayName: timelineClipName,
108
- parent: (_a = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _a !== void 0 ? _a : null,
138
+ parent: (_b = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _b !== void 0 ? _b : null,
109
139
  type: 'sequence',
110
140
  rootId,
111
141
  showInTimeline,
@@ -115,6 +145,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
115
145
  premountDisplay: premountDisplay !== null && premountDisplay !== void 0 ? premountDisplay : null,
116
146
  postmountDisplay: postmountDisplay !== null && postmountDisplay !== void 0 ? postmountDisplay : null,
117
147
  controls: controls !== null && controls !== void 0 ? controls : null,
148
+ effects: memoizedEffects,
118
149
  });
119
150
  return () => {
120
151
  unregisterSequence(id);
@@ -139,6 +170,8 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
139
170
  env.isStudio,
140
171
  inheritedStack,
141
172
  controls,
173
+ memoizedEffects,
174
+ isMedia,
142
175
  ]);
143
176
  // Ceil to support floats
144
177
  // https://github.com/remotion-dev/remotion/issues/2958
@@ -5,52 +5,52 @@ import type { RemotionMainAudioProps } from './props.js';
5
5
  * @see [Documentation](https://remotion.dev/docs/html5-audio)
6
6
  */
7
7
  export declare const Html5Audio: React.ForwardRefExoticComponent<Omit<import("./props.js").NativeAudioProps & {
8
- name?: string;
9
- volume?: import("../volume-prop.js").VolumeProp;
10
- playbackRate?: number;
11
- acceptableTimeShiftInSeconds?: number;
12
- allowAmplificationDuringRender?: boolean;
13
- _remotionInternalNeedsDurationCalculation?: boolean;
14
- _remotionInternalNativeLoopPassed?: boolean;
15
- toneFrequency?: number;
16
- useWebAudioApi?: boolean;
17
- pauseWhenBuffering?: boolean;
18
- showInTimeline?: boolean;
19
- delayRenderTimeoutInMilliseconds?: number;
20
- delayRenderRetries?: number;
21
- loopVolumeCurveBehavior?: import("./use-audio-frame.js").LoopVolumeCurveBehavior;
22
- onError?: (err: Error) => void;
23
- audioStreamIndex?: number;
8
+ name?: string | undefined;
9
+ volume?: import("../volume-prop.js").VolumeProp | undefined;
10
+ playbackRate?: number | undefined;
11
+ acceptableTimeShiftInSeconds?: number | undefined;
12
+ allowAmplificationDuringRender?: boolean | undefined;
13
+ _remotionInternalNeedsDurationCalculation?: boolean | undefined;
14
+ _remotionInternalNativeLoopPassed?: boolean | undefined;
15
+ toneFrequency?: number | undefined;
16
+ useWebAudioApi?: boolean | undefined;
17
+ pauseWhenBuffering?: boolean | undefined;
18
+ showInTimeline?: boolean | undefined;
19
+ delayRenderTimeoutInMilliseconds?: number | undefined;
20
+ delayRenderRetries?: number | undefined;
21
+ loopVolumeCurveBehavior?: import("./use-audio-frame.js").LoopVolumeCurveBehavior | undefined;
22
+ onError?: ((err: Error) => void) | undefined;
23
+ audioStreamIndex?: number | undefined;
24
24
  } & RemotionMainAudioProps & {
25
25
  /**
26
26
  * @deprecated For internal use only
27
27
  */
28
- readonly stack?: string;
28
+ readonly stack?: string | undefined;
29
29
  }, "ref"> & React.RefAttributes<HTMLAudioElement>>;
30
30
  /**
31
31
  * @deprecated This component has been renamed to `Html5Audio`.
32
32
  * @see [Documentation](https://remotion.dev/docs/mediabunny/new-video)
33
33
  */
34
34
  export declare const Audio: React.ForwardRefExoticComponent<Omit<import("./props.js").NativeAudioProps & {
35
- name?: string;
36
- volume?: import("../volume-prop.js").VolumeProp;
37
- playbackRate?: number;
38
- acceptableTimeShiftInSeconds?: number;
39
- allowAmplificationDuringRender?: boolean;
40
- _remotionInternalNeedsDurationCalculation?: boolean;
41
- _remotionInternalNativeLoopPassed?: boolean;
42
- toneFrequency?: number;
43
- useWebAudioApi?: boolean;
44
- pauseWhenBuffering?: boolean;
45
- showInTimeline?: boolean;
46
- delayRenderTimeoutInMilliseconds?: number;
47
- delayRenderRetries?: number;
48
- loopVolumeCurveBehavior?: import("./use-audio-frame.js").LoopVolumeCurveBehavior;
49
- onError?: (err: Error) => void;
50
- audioStreamIndex?: number;
35
+ name?: string | undefined;
36
+ volume?: import("../volume-prop.js").VolumeProp | undefined;
37
+ playbackRate?: number | undefined;
38
+ acceptableTimeShiftInSeconds?: number | undefined;
39
+ allowAmplificationDuringRender?: boolean | undefined;
40
+ _remotionInternalNeedsDurationCalculation?: boolean | undefined;
41
+ _remotionInternalNativeLoopPassed?: boolean | undefined;
42
+ toneFrequency?: number | undefined;
43
+ useWebAudioApi?: boolean | undefined;
44
+ pauseWhenBuffering?: boolean | undefined;
45
+ showInTimeline?: boolean | undefined;
46
+ delayRenderTimeoutInMilliseconds?: number | undefined;
47
+ delayRenderRetries?: number | undefined;
48
+ loopVolumeCurveBehavior?: import("./use-audio-frame.js").LoopVolumeCurveBehavior | undefined;
49
+ onError?: ((err: Error) => void) | undefined;
50
+ audioStreamIndex?: number | undefined;
51
51
  } & RemotionMainAudioProps & {
52
52
  /**
53
53
  * @deprecated For internal use only
54
54
  */
55
- readonly stack?: string;
55
+ readonly stack?: string | undefined;
56
56
  }, "ref"> & React.RefAttributes<HTMLAudioElement>>;