Skip to content

Commit ec09321

Browse files
authored
fix(💄): remove ReactNativeCanvas wrapper (#389)
1 parent 52efc1f commit ec09321

10 files changed

Lines changed: 49 additions & 137 deletions

File tree

‎apps/docs/content/docs/integrations/react-three-fiber.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: React Three Fiber
33
description: Integrations demo - declarative 3D with @react-three/fiber.
44
---
55

6-
Builds on [Three.js](/docs/integrations/three-js): same `WebGPURenderer`, canvas adapter, and **`present()`** hook - but scenes are JSX reconciled by React Three Fiber.
6+
Builds on [Three.js](/docs/integrations/three-js): same `WebGPURenderer` and **`present()`** hook - but scenes are JSX reconciled by React Three Fiber.
77

88
<WebGPUPlayground demo="three-js" height={280} />
99

@@ -38,7 +38,7 @@ export const FiberCanvas = ({ children, style, scene, camera }) => {
3838
const context = canvasRef.current!.getContext("webgpu")!;
3939
const renderer = makeWebGPURenderer(context);
4040

41-
const canvas = new ReactNativeCanvas(context.canvas) as HTMLCanvasElement;
41+
const canvas = context.canvas as HTMLCanvasElement;
4242
canvas.width = canvas.clientWidth * PixelRatio.get();
4343
canvas.height = canvas.clientHeight * PixelRatio.get();
4444

‎apps/docs/content/docs/integrations/three-js.mdx‎

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,47 +33,17 @@ if (moduleName.startsWith("three/addons/")) {
3333

3434
Import from `three/webgpu`, not `three` (which would pull the WebGL build).
3535

36-
## 2. Canvas adapter
36+
## 2. Create the renderer
3737

38-
`WebGPURenderer` expects an object with `width`, `height`, `clientWidth`, and `clientHeight`. Wrap the native canvas from `getContext("webgpu")`:
39-
40-
```tsx twoslash
41-
import type { NativeCanvas } from "react-native-webgpu";
42-
// ---cut---
43-
export class ReactNativeCanvas {
44-
constructor(private canvas: NativeCanvas) {}
45-
46-
get width() { return this.canvas.width; }
47-
set width(v: number) { this.canvas.width = v; }
48-
get height() { return this.canvas.height; }
49-
set height(v: number) { this.canvas.height = v; }
50-
get clientWidth() { return this.canvas.clientWidth; }
51-
get clientHeight() { return this.canvas.clientHeight; }
52-
53-
// Three.js may call these - no-ops are fine on RN
54-
addEventListener() {}
55-
removeEventListener() {}
56-
dispatchEvent() { return false; }
57-
setPointerCapture() {}
58-
releasePointerCapture() {}
59-
}
60-
```
61-
62-
## 3. Create the renderer
63-
64-
Pass the adapter and the **same** `GPUCanvasContext` you got from React Native WebGPU:
38+
`WebGPURenderer` expects a DOM-like canvas with `width`, `height`, `clientWidth`, and `clientHeight`, plus a few event methods. The native canvas from `getContext("webgpu")` already satisfies this interface, so pass it directly along with the **same** `GPUCanvasContext`:
6539

6640
```tsx twoslash
6741
import * as THREE from "three/webgpu";
68-
import type { NativeCanvas } from "react-native-webgpu";
69-
declare const ReactNativeCanvas: new (canvas: NativeCanvas) => unknown;
7042
// ---cut---
7143
export function makeWebGPURenderer(context: GPUCanvasContext) {
7244
return new THREE.WebGPURenderer({
7345
antialias: true,
74-
canvas: new ReactNativeCanvas(
75-
context.canvas as unknown as NativeCanvas,
76-
) as unknown as HTMLCanvasElement,
46+
canvas: context.canvas,
7747
context,
7848
});
7949
}
@@ -83,7 +53,7 @@ export function makeWebGPURenderer(context: GPUCanvasContext) {
8353
`WebGPURenderer.init()` is **async**. Do not call `render()` until it resolves - unlike raw WebGPU where pipeline creation is synchronous after `requestDevice`.
8454
</Callout>
8555

86-
## 4. Render loop + present
56+
## 3. Render loop + present
8757

8858
Configure the context once ([Canvas](/docs/getting-started/canvas)), then animate:
8959

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,9 @@
1-
import type { NativeCanvas } from "react-native-webgpu";
21
import * as THREE from "three/webgpu";
32

4-
export class ReactNativeCanvas {
5-
constructor(private canvas: NativeCanvas) {}
6-
7-
get width() {
8-
return this.canvas.width;
9-
}
10-
set width(v: number) {
11-
this.canvas.width = v;
12-
}
13-
get height() {
14-
return this.canvas.height;
15-
}
16-
set height(v: number) {
17-
this.canvas.height = v;
18-
}
19-
get clientWidth() {
20-
return this.canvas.clientWidth;
21-
}
22-
get clientHeight() {
23-
return this.canvas.clientHeight;
24-
}
25-
26-
addEventListener() {}
27-
removeEventListener() {}
28-
dispatchEvent() {
29-
return false;
30-
}
31-
setPointerCapture() {}
32-
releasePointerCapture() {}
33-
}
34-
353
export function makeWebGPURenderer(context: GPUCanvasContext) {
364
return new THREE.WebGPURenderer({
375
antialias: true,
38-
canvas: new ReactNativeCanvas(
39-
context.canvas as unknown as NativeCanvas,
40-
) as unknown as HTMLCanvasElement,
6+
canvas: context.canvas,
417
context,
428
});
439
}

‎apps/docs/tsconfig.tsbuildinfo‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎apps/example/src/ThreeJS/components/FiberCanvas.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { PixelRatio } from "react-native";
1212
import type { CanvasRef } from "react-native-webgpu";
1313
import { Canvas } from "react-native-webgpu";
1414

15-
import { makeWebGPURenderer, ReactNativeCanvas } from "./makeWebGPURenderer";
15+
import { makeWebGPURenderer } from "./makeWebGPURenderer";
1616

1717
//global.THREE = global.THREE || THREE;
1818

@@ -38,9 +38,7 @@ export const FiberCanvas = ({
3838
const context = canvasRef.current!.getContext("webgpu")!;
3939
const renderer = makeWebGPURenderer(context);
4040

41-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
42-
// @ts-expect-error
43-
const canvas = new ReactNativeCanvas(context.canvas) as HTMLCanvasElement;
41+
const canvas = context.canvas as unknown as HTMLCanvasElement;
4442
canvas.width = canvas.clientWidth * PixelRatio.get();
4543
canvas.height = canvas.clientHeight * PixelRatio.get();
4644
const size = {
Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,11 @@
1-
import type { NativeCanvas } from "react-native-webgpu";
21
import * as THREE from "three";
32

4-
// Here we need to wrap the Canvas into a non-host object for now
5-
export class ReactNativeCanvas {
6-
constructor(private canvas: NativeCanvas) {}
7-
8-
get width() {
9-
return this.canvas.width;
10-
}
11-
12-
get height() {
13-
return this.canvas.height;
14-
}
15-
16-
set width(width: number) {
17-
this.canvas.width = width;
18-
}
19-
20-
set height(height: number) {
21-
this.canvas.height = height;
22-
}
23-
24-
get clientWidth() {
25-
return this.canvas.width;
26-
}
27-
28-
get clientHeight() {
29-
return this.canvas.height;
30-
}
31-
32-
set clientWidth(width: number) {
33-
this.canvas.width = width;
34-
}
35-
36-
set clientHeight(height: number) {
37-
this.canvas.height = height;
38-
}
39-
40-
addEventListener(_type: string, _listener: EventListener) {
41-
// TODO
42-
}
43-
44-
removeEventListener(_type: string, _listener: EventListener) {
45-
// TODO
46-
}
47-
48-
dispatchEvent(_event: Event) {
49-
// TODO
50-
}
51-
52-
setPointerCapture() {
53-
// TODO
54-
}
55-
56-
releasePointerCapture() {
57-
// TODO
58-
}
59-
}
60-
613
export const makeWebGPURenderer = (
624
context: GPUCanvasContext,
635
{ antialias = true }: { antialias?: boolean } = {},
646
) =>
657
new THREE.WebGPURenderer({
668
antialias,
67-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
68-
// @ts-expect-error
69-
canvas: new ReactNativeCanvas(context.canvas),
9+
canvas: context.canvas,
7010
context,
7111
});

‎packages/webgpu/cpp/rnwgpu/api/Canvas.h‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ class Canvas : public NativeObject<Canvas> {
3636

3737
void *getSurface() { return _surface; }
3838

39+
// No-op DOM-compatibility stubs so that web renderers (Three.js,
40+
// react-three-fiber) can treat the canvas like an HTMLCanvasElement without
41+
// needing a JS wrapper. Extra JS arguments are ignored.
42+
void addEventListener() {}
43+
void removeEventListener() {}
44+
void dispatchEvent() {}
45+
void setPointerCapture() {}
46+
void releasePointerCapture() {}
47+
3948
static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
4049
installGetter(runtime, prototype, "surface", &Canvas::getSurface);
4150
installGetterSetter(runtime, prototype, "width", &Canvas::getWidth,
@@ -44,6 +53,15 @@ class Canvas : public NativeObject<Canvas> {
4453
&Canvas::setHeight);
4554
installGetter(runtime, prototype, "clientWidth", &Canvas::getClientWidth);
4655
installGetter(runtime, prototype, "clientHeight", &Canvas::getClientHeight);
56+
installMethod(runtime, prototype, "addEventListener",
57+
&Canvas::addEventListener);
58+
installMethod(runtime, prototype, "removeEventListener",
59+
&Canvas::removeEventListener);
60+
installMethod(runtime, prototype, "dispatchEvent", &Canvas::dispatchEvent);
61+
installMethod(runtime, prototype, "setPointerCapture",
62+
&Canvas::setPointerCapture);
63+
installMethod(runtime, prototype, "releasePointerCapture",
64+
&Canvas::releasePointerCapture);
4765
}
4866

4967
private:

‎packages/webgpu/src/Canvas.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ export interface NativeCanvas {
1717
height: number;
1818
clientWidth: number;
1919
clientHeight: number;
20+
// No-op DOM-compatibility stubs so web renderers (Three.js,
21+
// react-three-fiber) can treat the canvas like an HTMLCanvasElement.
22+
addEventListener(type: string, listener: EventListener): void;
23+
removeEventListener(type: string, listener: EventListener): void;
24+
dispatchEvent(event: Event): void;
25+
setPointerCapture(pointerId: number): void;
26+
releasePointerCapture(pointerId: number): void;
2027
}
2128

2229
export type RNCanvasContext = GPUCanvasContext & {

‎packages/webgpu/src/WebPolyfillGPUModule.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ function getNativeSurface(contextId: number) {
1515
width,
1616
clientHeight: height,
1717
clientWidth: width,
18+
// On web the real DOM canvas handles events; delegate to it.
19+
addEventListener: canvas.addEventListener.bind(canvas),
20+
removeEventListener: canvas.removeEventListener.bind(canvas),
21+
dispatchEvent: canvas.dispatchEvent.bind(canvas),
22+
setPointerCapture: canvas.setPointerCapture.bind(canvas),
23+
releasePointerCapture: canvas.releasePointerCapture.bind(canvas),
1824
};
1925
}
2026

‎packages/webgpu/src/types.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ export interface NativeCanvas {
66
height: number;
77
clientWidth: number;
88
clientHeight: number;
9+
// No-op DOM-compatibility stubs so web renderers (Three.js,
10+
// react-three-fiber) can treat the canvas like an HTMLCanvasElement.
11+
addEventListener(type: string, listener: EventListener): void;
12+
removeEventListener(type: string, listener: EventListener): void;
13+
dispatchEvent(event: Event): void;
14+
setPointerCapture(pointerId: number): void;
15+
releasePointerCapture(pointerId: number): void;
916
}
1017

1118
export type RNCanvasContext = GPUCanvasContext & {

0 commit comments

Comments
 (0)