8th Wall already gives you a WebGL canvas, a Three.js scene, a SLAM-tracked camera, and a render loop. React Three Fiber (R3F) expects the same things: a canvas, a renderer, and its own frameloop.

Wire them together carelessly and you end up with a second <Canvas>, a second WebGLRenderer, and two systems fighting over the same frame. Drawing, resizing, and picking all suffer.

This project is not about replacing 8th Wall with R3F. It is about running both together, with one canvas, one WebGLRenderer, and one clear owner of the runtime. I've open-sourced a small starter (plus an optional npm package) that does exactly this.

Links

The contract

XR8 drives the runtime. R3F owns the scene graph.

Everything in the starter follows from that one rule.

1. One canvas, one renderer

R3F reuses the gl, scene, and camera from XR8.Threejs.xrScene(). There is no nested <Canvas> and no second WebGLRenderer.

2. One draw path

XR8.Threejs renders both the camera feed and the scene. To make sure R3F doesn't also render, a small helper called StopR3FRender registers a useFrame callback with priority 1 and an empty body. Taking over R3F's default render step this way means it never calls gl.render.

3. XR8 drives the frame tick

R3F runs with frameloop: "never". On every XR8 onUpdate, the bridge calls advance() (using THREE.Timer), so your useFrame hooks still run, but on XR8's tick rather than a second competing loop.

4. Resize without fighting XR8

While R3F is configuring itself, setSize and setPixelRatio are muted, so XR8 (for example through FullWindowCanvas) keeps control of the drawing buffer. Then, on XR8's onCanvasSizeChange, the canvas CSS box size is passed into R3F. This keeps layout and picking much better aligned.

In short: hosts own the runtime, children own the scene.

What you write as an app author

Your code looks like normal R3F. You just put the scene under a host component:

import EighthWall from "./eighthwall/EighthWall"; import Experience from "./eighthwall/Experience"; export default function App() { return ( <EighthWall> <Experience /> </EighthWall> ); } 

Experience is an ordinary R3F tree: <mesh>, useFrame, and so on. For desktop or non-AR development, you can drop the same component into a plain R3F canvas:

import { Canvas } from "@react-three/fiber"; <Canvas> <Experience /> </Canvas> 

You still need two things in your index.html:

  1. The 8th Wall engine, XRExtras, and landing-page script tags
  2. A canvas with the class r3f-8thwall, which is what the host looks up:
<canvas class="r3f-8thwall"></canvas> 

How the pieces fit

Piece Role
EighthWall Boots XR8 and mounts your R3F children on the shared scene
StopR3FRender Prevents R3F from calling gl.render, since XR8 does the drawing
createR3FModule The bridge: shares XR8's gl, scene, and camera, sets frameloop: "never", calls advance() on each XR8 update, and guards resizing
initializeXR Sets up the standard 8th Wall pipeline modules, with the R3F bridge added last

Why bother?

With this, we can write our 8th Wall projects declaratively, in far fewer lines of code. Instead of fighting imperative Three.js setup (creating, adding, updating, and disposing objects by hand), we describe the scene as components and let React Three Fiber handle the rest. That frees us to focus on building quick, creative Three.js objects in the 8th Wall world.

We can also:

  • Write declarative scenes: meshes, lights, and groups are just JSX.
  • Write less code: setup, update, and disposal logic is handled by R3F.
  • Iterate faster: small ideas become working AR experiments quickly.
  • Use the pmndrs ecosystem: libraries built on React Three Fiber, like drei, work in your AR scene, so helpers like useGLTF and Text are ready to use.

Try the starter

git clone https://github.com/nagendra-dharmireddi/react-three-fiber-8thwall.git cd react-three-fiber-8thwall npm install npm run dev 

Open the HTTPS network URL on your phone, because camera access requires a secure context. The starter uses @vitejs/plugin-basic-ssl to provide local SSL.

If you'd rather use it as a package:

npm install react-three-fiber-8thwall three @react-three/fiber 
import { EighthWall } from "react-three-fiber-8thwall"; <EighthWall> <YourScene /> </EighthWall> 

With the package, you still add the 8th Wall CDN scripts and the r3f-8thwall canvas to your own HTML, plus the canvas CSS rule touch-action: none.

Common mistakes to avoid

  1. Nesting a second R3F <Canvas> inside the AR host
  2. Letting R3F also call gl.render, which fights XR8's draw (often a white screen)
  3. Missing or misnamed canvas class (it must be r3f-8thwall)
  4. Missing 8th Wall script tags
  5. Missing canvas CSS (touch-action: none)
  6. Letting R3F run setSize against XR8 during configure, which can desync the buffer and layout
  7. Overwriting camera.position every frame in AR (let XR8 own the SLAM pose)
  8. Testing over plain HTTP instead of HTTPS

Why this exists

Most R3F and 8th Wall glue code either forks too much or accidentally creates two renderers. This repo stays small on purpose: starter first, npm package second, MIT licensed.

If it's useful to you, try the demo on your phone, star the repo, and open an issue if anything is unclear.