@remotion/transitions 4.0.495 → 4.0.497

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.
@@ -7,7 +7,7 @@ import {
7
7
  Internals,
8
8
  useDelayRender
9
9
  } from "remotion";
10
- import { jsx } from "react/jsx-runtime";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
11
  var HtmlInCanvasPresentation = ({
12
12
  children,
13
13
  onElementImage,
@@ -23,6 +23,7 @@ var HtmlInCanvasPresentation = ({
23
23
  throw new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE);
24
24
  }
25
25
  const canvasRef = useRef(null);
26
+ const outputCanvasRef = useRef(null);
26
27
  const canvasSubtreeStyle = useMemo(() => {
27
28
  return {
28
29
  width: "100%",
@@ -34,7 +35,21 @@ var HtmlInCanvasPresentation = ({
34
35
  bottom: 0
35
36
  };
36
37
  }, []);
37
- const [offscreenCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
+ const outputCanvasStyle = useMemo(() => {
39
+ return {
40
+ width: "100%",
41
+ height: "100%",
42
+ position: "absolute",
43
+ top: 0,
44
+ left: 0,
45
+ right: 0,
46
+ bottom: 0,
47
+ pointerEvents: "none"
48
+ };
49
+ }, []);
50
+ const captureCanvasRef = useRef(null);
51
+ const captureContextRef = useRef(null);
52
+ const [shaderCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
53
  const passedPropsRef = useRef(passedProps);
39
54
  passedPropsRef.current = passedProps;
40
55
  const memoizedEffects = Internals.useMemoizedEffects({
@@ -43,33 +58,58 @@ var HtmlInCanvasPresentation = ({
43
58
  });
44
59
  const effectsRef = useRef(memoizedEffects);
45
60
  effectsRef.current = memoizedEffects;
46
- const [instance] = useState(() => shader(offscreenCanvas));
61
+ const [instance] = useState(() => shader(shaderCanvas));
47
62
  useLayoutEffect(() => {
63
+ const canvas = canvasRef.current;
64
+ if (!canvas) {
65
+ return () => {
66
+ instance.cleanup();
67
+ };
68
+ }
69
+ const captureCanvas = canvas.transferControlToOffscreen();
70
+ const captureContext = captureCanvas.getContext("2d");
71
+ if (!captureContext) {
72
+ throw new Error("Failed to create capture canvas context");
73
+ }
74
+ captureCanvasRef.current = captureCanvas;
75
+ captureContextRef.current = captureContext;
48
76
  return () => {
49
77
  instance.cleanup();
78
+ captureCanvasRef.current = null;
79
+ captureContextRef.current = null;
50
80
  };
51
- }, [offscreenCanvas, instance]);
81
+ }, [instance]);
52
82
  const chainState = Internals.useEffectChainState();
53
83
  const { delayRender, continueRender } = useDelayRender();
54
84
  const draw = useCallback(async (prevImage, nextImage, progress) => {
55
- if (!canvasRef.current) {
85
+ const outputCanvas = outputCanvasRef.current;
86
+ if (!outputCanvas) {
56
87
  throw new Error("Canvas not found");
57
88
  }
58
89
  const handle = delayRender("onPaint");
90
+ const clearOutput = () => {
91
+ const context = outputCanvas.getContext("2d");
92
+ if (!context) {
93
+ throw new Error("Failed to create output canvas context");
94
+ }
95
+ context.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
96
+ };
59
97
  if (!prevImage && !nextImage) {
60
- continueRender(handle);
61
98
  instance.clear();
99
+ clearOutput();
100
+ continueRender(handle);
62
101
  return;
63
102
  }
64
103
  const width = prevImage?.width ?? nextImage?.width ?? 0;
65
104
  const height = prevImage?.height ?? nextImage?.height ?? 0;
66
105
  if (width === 0 || height === 0) {
67
- continueRender(handle);
68
106
  instance.clear();
107
+ clearOutput();
108
+ continueRender(handle);
69
109
  return;
70
110
  }
71
- offscreenCanvas.width = width;
72
- offscreenCanvas.height = height;
111
+ shaderCanvas.width = width;
112
+ shaderCanvas.height = height;
73
113
  instance.draw({
74
114
  prevImage,
75
115
  nextImage,
@@ -80,14 +120,14 @@ var HtmlInCanvasPresentation = ({
80
120
  });
81
121
  await Internals.runEffectChain({
82
122
  state: chainState.get(width, height),
83
- source: offscreenCanvas,
123
+ source: shaderCanvas,
84
124
  effects: effectsRef.current ?? [],
85
125
  width,
86
126
  height,
87
- output: canvasRef.current
127
+ output: outputCanvas
88
128
  });
89
129
  continueRender(handle);
90
- }, [chainState, instance, offscreenCanvas, continueRender, delayRender]);
130
+ }, [chainState, continueRender, delayRender, instance, shaderCanvas]);
91
131
  const passThrough = bothEnteringAndExiting && presentationDirection === "exiting";
92
132
  useLayoutEffect(() => {
93
133
  if (passThrough) {
@@ -100,11 +140,19 @@ var HtmlInCanvasPresentation = ({
100
140
  canvas.layoutSubtree = true;
101
141
  const onPaint = () => {
102
142
  const firstChild = canvas.firstChild;
103
- if (!firstChild) {
143
+ const captureCanvas = captureCanvasRef.current;
144
+ const captureContext = captureContextRef.current;
145
+ if (!firstChild || !captureCanvas || !captureContext) {
104
146
  return;
105
147
  }
106
148
  const elementImage = canvas.captureElementImage(firstChild);
107
- onElementImage(elementImage, draw);
149
+ try {
150
+ captureContext.reset();
151
+ captureContext.drawElementImage(elementImage, 0, 0);
152
+ } finally {
153
+ elementImage.close();
154
+ }
155
+ onElementImage(captureCanvas, draw);
108
156
  };
109
157
  canvas.addEventListener("paint", onPaint);
110
158
  return () => {
@@ -138,20 +186,39 @@ var HtmlInCanvasPresentation = ({
138
186
  return;
139
187
  }
140
188
  const observer = new ResizeObserver(([entry]) => {
141
- canvas.width = entry.devicePixelContentBoxSize[0].inlineSize;
142
- canvas.height = entry.devicePixelContentBoxSize[0].blockSize;
189
+ const outputCanvas = outputCanvasRef.current;
190
+ const captureCanvas = captureCanvasRef.current;
191
+ if (!outputCanvas || !captureCanvas) {
192
+ return;
193
+ }
194
+ const width = entry.devicePixelContentBoxSize[0].inlineSize;
195
+ const height = entry.devicePixelContentBoxSize[0].blockSize;
196
+ captureCanvas.width = width;
197
+ captureCanvas.height = height;
198
+ outputCanvas.width = width;
199
+ outputCanvas.height = height;
200
+ canvas.requestPaint?.();
143
201
  });
144
202
  observer.observe(canvas, { box: "device-pixel-content-box" });
203
+ return () => {
204
+ observer.disconnect();
205
+ };
145
206
  }, [passThrough]);
146
207
  if (passThrough) {
147
208
  return children;
148
209
  }
149
- return /* @__PURE__ */ jsx(AbsoluteFill, {
150
- children: /* @__PURE__ */ jsx("canvas", {
151
- ref: canvasRef,
152
- style: canvasSubtreeStyle,
153
- children
154
- })
210
+ return /* @__PURE__ */ jsxs(AbsoluteFill, {
211
+ children: [
212
+ /* @__PURE__ */ jsx("canvas", {
213
+ ref: canvasRef,
214
+ style: canvasSubtreeStyle,
215
+ children
216
+ }),
217
+ /* @__PURE__ */ jsx("canvas", {
218
+ ref: outputCanvasRef,
219
+ style: outputCanvasStyle
220
+ })
221
+ ]
155
222
  });
156
223
  };
157
224
  var makeHtmlInCanvasPresentation = (shader) => {
@@ -173,6 +240,11 @@ var makeHtmlInCanvasPresentation = (shader) => {
173
240
  };
174
241
  };
175
242
 
243
+ // src/presentations/upload-element-image.ts
244
+ var uploadElementImage = (gl, elementImage) => {
245
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elementImage);
246
+ };
247
+
176
248
  // src/presentations/dissolve.tsx
177
249
  var DEFAULT_LINE_WIDTH = 0.1;
178
250
  var DEFAULT_SPREAD_COLOR = "#ff0000";
@@ -345,13 +417,13 @@ var dissolveShader = (canvas) => {
345
417
  gl.activeTexture(gl.TEXTURE0);
346
418
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
347
419
  if (prevImage) {
348
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
420
+ uploadElementImage(gl, prevImage);
349
421
  }
350
422
  gl.uniform1i(uPrev, 0);
351
423
  gl.activeTexture(gl.TEXTURE1);
352
424
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
353
425
  if (nextImage) {
354
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
426
+ uploadElementImage(gl, nextImage);
355
427
  }
356
428
  gl.uniform1i(uNext, 1);
357
429
  const spread = parseHexColor(spreadColor);
@@ -7,7 +7,7 @@ import {
7
7
  Internals,
8
8
  useDelayRender
9
9
  } from "remotion";
10
- import { jsx } from "react/jsx-runtime";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
11
  var HtmlInCanvasPresentation = ({
12
12
  children,
13
13
  onElementImage,
@@ -23,6 +23,7 @@ var HtmlInCanvasPresentation = ({
23
23
  throw new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE);
24
24
  }
25
25
  const canvasRef = useRef(null);
26
+ const outputCanvasRef = useRef(null);
26
27
  const canvasSubtreeStyle = useMemo(() => {
27
28
  return {
28
29
  width: "100%",
@@ -34,7 +35,21 @@ var HtmlInCanvasPresentation = ({
34
35
  bottom: 0
35
36
  };
36
37
  }, []);
37
- const [offscreenCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
+ const outputCanvasStyle = useMemo(() => {
39
+ return {
40
+ width: "100%",
41
+ height: "100%",
42
+ position: "absolute",
43
+ top: 0,
44
+ left: 0,
45
+ right: 0,
46
+ bottom: 0,
47
+ pointerEvents: "none"
48
+ };
49
+ }, []);
50
+ const captureCanvasRef = useRef(null);
51
+ const captureContextRef = useRef(null);
52
+ const [shaderCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
53
  const passedPropsRef = useRef(passedProps);
39
54
  passedPropsRef.current = passedProps;
40
55
  const memoizedEffects = Internals.useMemoizedEffects({
@@ -43,33 +58,58 @@ var HtmlInCanvasPresentation = ({
43
58
  });
44
59
  const effectsRef = useRef(memoizedEffects);
45
60
  effectsRef.current = memoizedEffects;
46
- const [instance] = useState(() => shader(offscreenCanvas));
61
+ const [instance] = useState(() => shader(shaderCanvas));
47
62
  useLayoutEffect(() => {
63
+ const canvas = canvasRef.current;
64
+ if (!canvas) {
65
+ return () => {
66
+ instance.cleanup();
67
+ };
68
+ }
69
+ const captureCanvas = canvas.transferControlToOffscreen();
70
+ const captureContext = captureCanvas.getContext("2d");
71
+ if (!captureContext) {
72
+ throw new Error("Failed to create capture canvas context");
73
+ }
74
+ captureCanvasRef.current = captureCanvas;
75
+ captureContextRef.current = captureContext;
48
76
  return () => {
49
77
  instance.cleanup();
78
+ captureCanvasRef.current = null;
79
+ captureContextRef.current = null;
50
80
  };
51
- }, [offscreenCanvas, instance]);
81
+ }, [instance]);
52
82
  const chainState = Internals.useEffectChainState();
53
83
  const { delayRender, continueRender } = useDelayRender();
54
84
  const draw = useCallback(async (prevImage, nextImage, progress) => {
55
- if (!canvasRef.current) {
85
+ const outputCanvas = outputCanvasRef.current;
86
+ if (!outputCanvas) {
56
87
  throw new Error("Canvas not found");
57
88
  }
58
89
  const handle = delayRender("onPaint");
90
+ const clearOutput = () => {
91
+ const context = outputCanvas.getContext("2d");
92
+ if (!context) {
93
+ throw new Error("Failed to create output canvas context");
94
+ }
95
+ context.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
96
+ };
59
97
  if (!prevImage && !nextImage) {
60
- continueRender(handle);
61
98
  instance.clear();
99
+ clearOutput();
100
+ continueRender(handle);
62
101
  return;
63
102
  }
64
103
  const width = prevImage?.width ?? nextImage?.width ?? 0;
65
104
  const height = prevImage?.height ?? nextImage?.height ?? 0;
66
105
  if (width === 0 || height === 0) {
67
- continueRender(handle);
68
106
  instance.clear();
107
+ clearOutput();
108
+ continueRender(handle);
69
109
  return;
70
110
  }
71
- offscreenCanvas.width = width;
72
- offscreenCanvas.height = height;
111
+ shaderCanvas.width = width;
112
+ shaderCanvas.height = height;
73
113
  instance.draw({
74
114
  prevImage,
75
115
  nextImage,
@@ -80,14 +120,14 @@ var HtmlInCanvasPresentation = ({
80
120
  });
81
121
  await Internals.runEffectChain({
82
122
  state: chainState.get(width, height),
83
- source: offscreenCanvas,
123
+ source: shaderCanvas,
84
124
  effects: effectsRef.current ?? [],
85
125
  width,
86
126
  height,
87
- output: canvasRef.current
127
+ output: outputCanvas
88
128
  });
89
129
  continueRender(handle);
90
- }, [chainState, instance, offscreenCanvas, continueRender, delayRender]);
130
+ }, [chainState, continueRender, delayRender, instance, shaderCanvas]);
91
131
  const passThrough = bothEnteringAndExiting && presentationDirection === "exiting";
92
132
  useLayoutEffect(() => {
93
133
  if (passThrough) {
@@ -100,11 +140,19 @@ var HtmlInCanvasPresentation = ({
100
140
  canvas.layoutSubtree = true;
101
141
  const onPaint = () => {
102
142
  const firstChild = canvas.firstChild;
103
- if (!firstChild) {
143
+ const captureCanvas = captureCanvasRef.current;
144
+ const captureContext = captureContextRef.current;
145
+ if (!firstChild || !captureCanvas || !captureContext) {
104
146
  return;
105
147
  }
106
148
  const elementImage = canvas.captureElementImage(firstChild);
107
- onElementImage(elementImage, draw);
149
+ try {
150
+ captureContext.reset();
151
+ captureContext.drawElementImage(elementImage, 0, 0);
152
+ } finally {
153
+ elementImage.close();
154
+ }
155
+ onElementImage(captureCanvas, draw);
108
156
  };
109
157
  canvas.addEventListener("paint", onPaint);
110
158
  return () => {
@@ -138,20 +186,39 @@ var HtmlInCanvasPresentation = ({
138
186
  return;
139
187
  }
140
188
  const observer = new ResizeObserver(([entry]) => {
141
- canvas.width = entry.devicePixelContentBoxSize[0].inlineSize;
142
- canvas.height = entry.devicePixelContentBoxSize[0].blockSize;
189
+ const outputCanvas = outputCanvasRef.current;
190
+ const captureCanvas = captureCanvasRef.current;
191
+ if (!outputCanvas || !captureCanvas) {
192
+ return;
193
+ }
194
+ const width = entry.devicePixelContentBoxSize[0].inlineSize;
195
+ const height = entry.devicePixelContentBoxSize[0].blockSize;
196
+ captureCanvas.width = width;
197
+ captureCanvas.height = height;
198
+ outputCanvas.width = width;
199
+ outputCanvas.height = height;
200
+ canvas.requestPaint?.();
143
201
  });
144
202
  observer.observe(canvas, { box: "device-pixel-content-box" });
203
+ return () => {
204
+ observer.disconnect();
205
+ };
145
206
  }, [passThrough]);
146
207
  if (passThrough) {
147
208
  return children;
148
209
  }
149
- return /* @__PURE__ */ jsx(AbsoluteFill, {
150
- children: /* @__PURE__ */ jsx("canvas", {
151
- ref: canvasRef,
152
- style: canvasSubtreeStyle,
153
- children
154
- })
210
+ return /* @__PURE__ */ jsxs(AbsoluteFill, {
211
+ children: [
212
+ /* @__PURE__ */ jsx("canvas", {
213
+ ref: canvasRef,
214
+ style: canvasSubtreeStyle,
215
+ children
216
+ }),
217
+ /* @__PURE__ */ jsx("canvas", {
218
+ ref: outputCanvasRef,
219
+ style: outputCanvasStyle
220
+ })
221
+ ]
155
222
  });
156
223
  };
157
224
  var makeHtmlInCanvasPresentation = (shader) => {
@@ -173,6 +240,11 @@ var makeHtmlInCanvasPresentation = (shader) => {
173
240
  };
174
241
  };
175
242
 
243
+ // src/presentations/upload-element-image.ts
244
+ var uploadElementImage = (gl, elementImage) => {
245
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elementImage);
246
+ };
247
+
176
248
  // src/presentations/dreamy-zoom.tsx
177
249
  var DEFAULT_ROTATION = 6;
178
250
  var DEFAULT_SCALE = 1.2;
@@ -320,13 +392,13 @@ var dreamyZoomShader = (canvas) => {
320
392
  gl.activeTexture(gl.TEXTURE0);
321
393
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
322
394
  if (prevImage) {
323
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
395
+ uploadElementImage(gl, prevImage);
324
396
  }
325
397
  gl.uniform1i(uPrev, 0);
326
398
  gl.activeTexture(gl.TEXTURE1);
327
399
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
328
400
  if (nextImage) {
329
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
401
+ uploadElementImage(gl, nextImage);
330
402
  }
331
403
  gl.uniform1i(uNext, 1);
332
404
  gl.uniform1f(uTime, effectiveTime);
@@ -7,7 +7,7 @@ import {
7
7
  Internals,
8
8
  useDelayRender
9
9
  } from "remotion";
10
- import { jsx } from "react/jsx-runtime";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
11
  var HtmlInCanvasPresentation = ({
12
12
  children,
13
13
  onElementImage,
@@ -23,6 +23,7 @@ var HtmlInCanvasPresentation = ({
23
23
  throw new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE);
24
24
  }
25
25
  const canvasRef = useRef(null);
26
+ const outputCanvasRef = useRef(null);
26
27
  const canvasSubtreeStyle = useMemo(() => {
27
28
  return {
28
29
  width: "100%",
@@ -34,7 +35,21 @@ var HtmlInCanvasPresentation = ({
34
35
  bottom: 0
35
36
  };
36
37
  }, []);
37
- const [offscreenCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
+ const outputCanvasStyle = useMemo(() => {
39
+ return {
40
+ width: "100%",
41
+ height: "100%",
42
+ position: "absolute",
43
+ top: 0,
44
+ left: 0,
45
+ right: 0,
46
+ bottom: 0,
47
+ pointerEvents: "none"
48
+ };
49
+ }, []);
50
+ const captureCanvasRef = useRef(null);
51
+ const captureContextRef = useRef(null);
52
+ const [shaderCanvas] = useState(() => new OffscreenCanvas(1, 1));
38
53
  const passedPropsRef = useRef(passedProps);
39
54
  passedPropsRef.current = passedProps;
40
55
  const memoizedEffects = Internals.useMemoizedEffects({
@@ -43,33 +58,58 @@ var HtmlInCanvasPresentation = ({
43
58
  });
44
59
  const effectsRef = useRef(memoizedEffects);
45
60
  effectsRef.current = memoizedEffects;
46
- const [instance] = useState(() => shader(offscreenCanvas));
61
+ const [instance] = useState(() => shader(shaderCanvas));
47
62
  useLayoutEffect(() => {
63
+ const canvas = canvasRef.current;
64
+ if (!canvas) {
65
+ return () => {
66
+ instance.cleanup();
67
+ };
68
+ }
69
+ const captureCanvas = canvas.transferControlToOffscreen();
70
+ const captureContext = captureCanvas.getContext("2d");
71
+ if (!captureContext) {
72
+ throw new Error("Failed to create capture canvas context");
73
+ }
74
+ captureCanvasRef.current = captureCanvas;
75
+ captureContextRef.current = captureContext;
48
76
  return () => {
49
77
  instance.cleanup();
78
+ captureCanvasRef.current = null;
79
+ captureContextRef.current = null;
50
80
  };
51
- }, [offscreenCanvas, instance]);
81
+ }, [instance]);
52
82
  const chainState = Internals.useEffectChainState();
53
83
  const { delayRender, continueRender } = useDelayRender();
54
84
  const draw = useCallback(async (prevImage, nextImage, progress) => {
55
- if (!canvasRef.current) {
85
+ const outputCanvas = outputCanvasRef.current;
86
+ if (!outputCanvas) {
56
87
  throw new Error("Canvas not found");
57
88
  }
58
89
  const handle = delayRender("onPaint");
90
+ const clearOutput = () => {
91
+ const context = outputCanvas.getContext("2d");
92
+ if (!context) {
93
+ throw new Error("Failed to create output canvas context");
94
+ }
95
+ context.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
96
+ };
59
97
  if (!prevImage && !nextImage) {
60
- continueRender(handle);
61
98
  instance.clear();
99
+ clearOutput();
100
+ continueRender(handle);
62
101
  return;
63
102
  }
64
103
  const width = prevImage?.width ?? nextImage?.width ?? 0;
65
104
  const height = prevImage?.height ?? nextImage?.height ?? 0;
66
105
  if (width === 0 || height === 0) {
67
- continueRender(handle);
68
106
  instance.clear();
107
+ clearOutput();
108
+ continueRender(handle);
69
109
  return;
70
110
  }
71
- offscreenCanvas.width = width;
72
- offscreenCanvas.height = height;
111
+ shaderCanvas.width = width;
112
+ shaderCanvas.height = height;
73
113
  instance.draw({
74
114
  prevImage,
75
115
  nextImage,
@@ -80,14 +120,14 @@ var HtmlInCanvasPresentation = ({
80
120
  });
81
121
  await Internals.runEffectChain({
82
122
  state: chainState.get(width, height),
83
- source: offscreenCanvas,
123
+ source: shaderCanvas,
84
124
  effects: effectsRef.current ?? [],
85
125
  width,
86
126
  height,
87
- output: canvasRef.current
127
+ output: outputCanvas
88
128
  });
89
129
  continueRender(handle);
90
- }, [chainState, instance, offscreenCanvas, continueRender, delayRender]);
130
+ }, [chainState, continueRender, delayRender, instance, shaderCanvas]);
91
131
  const passThrough = bothEnteringAndExiting && presentationDirection === "exiting";
92
132
  useLayoutEffect(() => {
93
133
  if (passThrough) {
@@ -100,11 +140,19 @@ var HtmlInCanvasPresentation = ({
100
140
  canvas.layoutSubtree = true;
101
141
  const onPaint = () => {
102
142
  const firstChild = canvas.firstChild;
103
- if (!firstChild) {
143
+ const captureCanvas = captureCanvasRef.current;
144
+ const captureContext = captureContextRef.current;
145
+ if (!firstChild || !captureCanvas || !captureContext) {
104
146
  return;
105
147
  }
106
148
  const elementImage = canvas.captureElementImage(firstChild);
107
- onElementImage(elementImage, draw);
149
+ try {
150
+ captureContext.reset();
151
+ captureContext.drawElementImage(elementImage, 0, 0);
152
+ } finally {
153
+ elementImage.close();
154
+ }
155
+ onElementImage(captureCanvas, draw);
108
156
  };
109
157
  canvas.addEventListener("paint", onPaint);
110
158
  return () => {
@@ -138,20 +186,39 @@ var HtmlInCanvasPresentation = ({
138
186
  return;
139
187
  }
140
188
  const observer = new ResizeObserver(([entry]) => {
141
- canvas.width = entry.devicePixelContentBoxSize[0].inlineSize;
142
- canvas.height = entry.devicePixelContentBoxSize[0].blockSize;
189
+ const outputCanvas = outputCanvasRef.current;
190
+ const captureCanvas = captureCanvasRef.current;
191
+ if (!outputCanvas || !captureCanvas) {
192
+ return;
193
+ }
194
+ const width = entry.devicePixelContentBoxSize[0].inlineSize;
195
+ const height = entry.devicePixelContentBoxSize[0].blockSize;
196
+ captureCanvas.width = width;
197
+ captureCanvas.height = height;
198
+ outputCanvas.width = width;
199
+ outputCanvas.height = height;
200
+ canvas.requestPaint?.();
143
201
  });
144
202
  observer.observe(canvas, { box: "device-pixel-content-box" });
203
+ return () => {
204
+ observer.disconnect();
205
+ };
145
206
  }, [passThrough]);
146
207
  if (passThrough) {
147
208
  return children;
148
209
  }
149
- return /* @__PURE__ */ jsx(AbsoluteFill, {
150
- children: /* @__PURE__ */ jsx("canvas", {
151
- ref: canvasRef,
152
- style: canvasSubtreeStyle,
153
- children
154
- })
210
+ return /* @__PURE__ */ jsxs(AbsoluteFill, {
211
+ children: [
212
+ /* @__PURE__ */ jsx("canvas", {
213
+ ref: canvasRef,
214
+ style: canvasSubtreeStyle,
215
+ children
216
+ }),
217
+ /* @__PURE__ */ jsx("canvas", {
218
+ ref: outputCanvasRef,
219
+ style: outputCanvasStyle
220
+ })
221
+ ]
155
222
  });
156
223
  };
157
224
  var makeHtmlInCanvasPresentation = (shader) => {
@@ -173,6 +240,11 @@ var makeHtmlInCanvasPresentation = (shader) => {
173
240
  };
174
241
  };
175
242
 
243
+ // src/presentations/upload-element-image.ts
244
+ var uploadElementImage = (gl, elementImage) => {
245
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elementImage);
246
+ };
247
+
176
248
  // src/presentations/film-burn.tsx
177
249
  var DEFAULT_SEED = 2.31;
178
250
  var VERTEX_SHADER = `#version 300 es
@@ -417,13 +489,13 @@ var filmBurnShader = (canvas) => {
417
489
  gl.activeTexture(gl.TEXTURE0);
418
490
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
419
491
  if (prevImage) {
420
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
492
+ uploadElementImage(gl, prevImage);
421
493
  }
422
494
  gl.uniform1i(uPrev, 0);
423
495
  gl.activeTexture(gl.TEXTURE1);
424
496
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
425
497
  if (nextImage) {
426
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
498
+ uploadElementImage(gl, nextImage);
427
499
  }
428
500
  gl.uniform1i(uNext, 1);
429
501
  gl.uniform1f(uTime, effectiveTime);