Chapter 857: VR Basics / WebXR (Manual)
Core Idea
Turning a three.js app into a basic WebXR VR experience mainly means letting the VR system control camera orientation/fov/aspect and switching to renderer.setAnimationLoop() — the one critical rule to internalize is that in VR, one three.js unit equals one real-world meter.
Key Concepts
- VR system owns camera framing: field of view, aspect, and where the camera points are all supplied by the headset/browser, not set manually as in a normal app.
VRButton.createButton(renderer) + renderer.xr.enabled = true: the minimal addition to enable WebXR and give the user an entry point into VR mode.
renderer.setAnimationLoop() instead of requestAnimationFrame: required so three.js can drive the render loop correctly once an XR session is active.
- One unit = one meter: object sizes and positions must be authored in real-world scale, since VR maps the user's actual physical movement to scene units — a camera height of 1.6 or objects placed 2 units away are meant literally as 1.6m and 2m.
- HTTPS requirement for remote testing: viewing on a separate device (e.g. a phone) over your local network requires serving over HTTPS, since WebXR requires a secure context — most simple local servers, such as Servez, offer an HTTPS option for this.
- Input sophistication varies by device tier: from no controller at all (gaze/dwell-based selection only) up to two 6DOF controllers with hand-tracking-like interaction — UX decisions should match what the target device can actually provide.
Code Examples
renderer.xr.enabled = true;
document.body.appendChild(VRButton.createButton(renderer));
camera.position.set(0, 1.6, 0); // average standing eye height, in meters
renderer.setAnimationLoop(render); // replaces requestAnimationFrame(render)
- What it demonstrates: the minimal changes to enable WebXR — enabling XR on the renderer, adding the VR entry button, positioning the camera at a realistic standing height, and switching the render loop driver.
Key Takeaways
- Camera fov/aspect/orientation come from the VR system itself once in an XR session — don't fight it by setting them manually.
- Use
renderer.setAnimationLoop(), not a manual requestAnimationFrame loop, once WebXR is involved.
- Treat three.js units as real meters in VR — this affects camera height, object scale, and placement decisions directly.
- Testing on a separate device over the local network requires HTTPS, since WebXR needs a secure context.
- Match your input/UX design to the actual device tier you're targeting — gaze-only, single 3DOF controller, and dual 6DOF controllers each call for a different interaction model.
Connects To
- WebGLRenderer: exposes the
.xr namespace and setAnimationLoop used throughout this lesson.