pmndrs / react-three-offscreen

📺 Offscreen worker canvas for react-three-fiber
https://offscreen.pmnd.rs
MIT License
463 stars 19 forks source link

Example with props #8

Open stripuramallu3 opened 1 year ago

stripuramallu3 commented 1 year ago

Could an example be provided where the Scene component has to receive props (for example for the mesh position)? How does the worker.jsx file to pass the props to the Scene?

// Scene.jsx (a self contained webgl app)
export default function App() {
  return (
    <mesh>
      <boxGeometry />
    </mesh>
  )
}
drcmda commented 1 year ago

dom and canvas run into two different threads, it's up to you how you bridge that. broadcasts maybe, but there's no conventional way.

stripuramallu3 commented 1 year ago

Thank you! Was hoping there was a better/conventional way

sshmaxime commented 1 year ago

It would be so beautiful to pass a ref to the worker canvas and manipulate it from the main thread.

drcmda commented 1 year ago

if you guys have any ideas go ahead, would love to have a standard interface of some sort. i have never used broadcasts before but it's gotta be something that works both in a worker and in a main thread.

mhmdjaw commented 10 months ago

Does that also mean that <Html> from drei doesn't work in offscreen canvas? I tried it and it doesn't show any HTML elements.

rob-myers commented 8 months ago

To get this working, we can patch @react-three/offscreen@0.0.8 as follows:

Show patches/@react-three+offscreen+0.0.8.patch ```diff diff --git a/node_modules/@react-three/offscreen/dist/Canvas.d.ts b/node_modules/@react-three/offscreen/dist/Canvas.d.ts index 7084e67..e79c825 100644 --- a/node_modules/@react-three/offscreen/dist/Canvas.d.ts +++ b/node_modules/@react-three/offscreen/dist/Canvas.d.ts @@ -13,5 +13,6 @@ export interface CanvasProps extends Omit, 'size' eventSource?: HTMLElement | React.MutableRefObject; /** The event prefix that is cast into canvas pointer x/y events, default: "offset" */ eventPrefix?: 'offset' | 'client' | 'page' | 'layer' | 'screen'; + sceneProps?: Record; } export declare function Canvas({ eventSource, worker, fallback, style, className, id, ...props }: CanvasProps): JSX.Element; diff --git a/node_modules/@react-three/offscreen/dist/index.mjs b/node_modules/@react-three/offscreen/dist/index.mjs index acf1918..9282957 100644 --- a/node_modules/@react-three/offscreen/dist/index.mjs +++ b/node_modules/@react-three/offscreen/dist/index.mjs @@ -86,6 +86,7 @@ function Canvas({ style, className, id, + sceneProps = {}, ...props }) { const [shouldFallback, setFallback] = React.useState(false); @@ -111,7 +112,7 @@ function Canvas({ worker.postMessage({ type: 'init', payload: { - props, + props: { sceneProps, ...props }, drawingSurface: offscreen, width: canvas.clientWidth, height: canvas.clientHeight, @@ -181,9 +182,9 @@ function Canvas({ if (!worker) return; worker.postMessage({ type: 'props', - payload: props + payload: { sceneProps, ...props } }); - }, [worker, props]); + }, [worker, props, sceneProps]); return shouldFallback ? /*#__PURE__*/React.createElement(Canvas$1, _extends({ id: id, className: className, @@ -203,7 +204,7 @@ function Canvas({ }); } -function render(children) { +function render(component) { extend(THREE); let root; let dpr = [1, 2]; @@ -218,6 +219,7 @@ function render(children) { const handleInit = payload => { const { props, + sceneProps, drawingSurface: canvas, width, top, @@ -281,7 +283,7 @@ function render(children) { }); // Render children once - root.render(children); + root.render(React.createElement(component, sceneProps)); } catch (e) { postMessage({ type: 'error', @@ -317,14 +319,15 @@ function render(children) { stopPropagation() {} }); }; - const handleProps = payload => { + const handleProps = ({ sceneProps, ...payload }) => { if (!root) return; if (payload.dpr) dpr = payload.dpr; root.configure({ size, dpr, - ...payload + ...payload, }); + root.render(React.createElement(component, sceneProps)); }; const handlerMap = { resize: handleResize, diff --git a/node_modules/@react-three/offscreen/dist/render.d.ts b/node_modules/@react-three/offscreen/dist/render.d.ts index 2be3f9c..0cceb2b 100644 --- a/node_modules/@react-three/offscreen/dist/render.d.ts +++ b/node_modules/@react-three/offscreen/dist/render.d.ts @@ -1,2 +1,2 @@ /// -export declare function render(children: React.ReactNode): void; +export declare function render

(component: React.FunctionComponent

| React.ComponentClass

): void; ```

Finally, restructure the project a bit:

// create-worker.js
// separate file fixes HMR
export const worker = new Worker(new URL('./worker.jsx', import.meta.url), { type: 'module' });
// App.jsx
import { worker } from "./create-worker";
// ...

  return (
      <Canvas
        fallback={<Scene testProp="hello, world! (fallback)" />}
        worker={worker}
        sceneProps={{ foo: "hello, world!" }}
      />
  );

// worker.jsx
import { render } from '@react-three/offscreen';
import Scene from "./Scene";

// Send component instead of ReactElement
render(Scene);
richi-coder commented 6 months ago

Does that also mean that <Html> from drei doesn't work in offscreen canvas? I tried it and it doesn't show any HTML elements.

How have you dealt with this so far? @mhmdjaw