@remotion/transitions 4.0.496 → 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/ripple.tsx
177
249
  var DEFAULT_AMPLITUDE = 100;
178
250
  var DEFAULT_SPEED = 50;
@@ -315,13 +387,13 @@ var rippleShader = (canvas) => {
315
387
  gl.activeTexture(gl.TEXTURE0);
316
388
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
317
389
  if (prevImage) {
318
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
390
+ uploadElementImage(gl, prevImage);
319
391
  }
320
392
  gl.uniform1i(uPrev, 0);
321
393
  gl.activeTexture(gl.TEXTURE1);
322
394
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
323
395
  if (nextImage) {
324
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
396
+ uploadElementImage(gl, nextImage);
325
397
  }
326
398
  gl.uniform1i(uNext, 1);
327
399
  gl.uniform1f(uTime, effectiveTime);
package/dist/esm/swap.mjs CHANGED
@@ -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/swap.tsx
177
249
  var DEFAULT_REFLECTION = 0.4;
178
250
  var DEFAULT_PERSPECTIVE = 0.2;
@@ -366,13 +438,13 @@ var swapShader = (canvas) => {
366
438
  gl.activeTexture(gl.TEXTURE0);
367
439
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
368
440
  if (prevImage) {
369
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
441
+ uploadElementImage(gl, prevImage);
370
442
  }
371
443
  gl.uniform1i(uPrev, 0);
372
444
  gl.activeTexture(gl.TEXTURE1);
373
445
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
374
446
  if (nextImage) {
375
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
447
+ uploadElementImage(gl, nextImage);
376
448
  }
377
449
  gl.uniform1i(uNext, 1);
378
450
  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/zoom-blur.tsx
177
249
  var VERTEX_SHADER = `#version 300 es
178
250
  in vec2 a_pos;
@@ -338,13 +410,13 @@ var zoomBlurShader = (canvas) => {
338
410
  gl.activeTexture(gl.TEXTURE0);
339
411
  gl.bindTexture(gl.TEXTURE_2D, prevTex);
340
412
  if (prevImage) {
341
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, prevImage);
413
+ uploadElementImage(gl, prevImage);
342
414
  }
343
415
  gl.uniform1i(uPrev, 0);
344
416
  gl.activeTexture(gl.TEXTURE1);
345
417
  gl.bindTexture(gl.TEXTURE_2D, nextTex);
346
418
  if (nextImage) {
347
- gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, nextImage);
419
+ uploadElementImage(gl, nextImage);
348
420
  }
349
421
  gl.uniform1i(uNext, 1);
350
422
  gl.uniform1f(uTime, effectiveTime);