WebXR is a W3C standard API that enables web applications to render immersive experiences on VR headsets and AR-capable devices. It replaces the older WebVR API and works with devices from Meta Quest to mobile AR via ARCore and ARKit.
Key Concepts
- XRSession — represents an active immersive session (inline, immersive-vr, or immersive-ar)
- XRFrame — snapshot of tracking state at a given moment; provided each render loop tick
- XRReferenceSpace — a coordinate system: local, local-floor, bounded-floor, or unbounded
- XRInputSource — a tracked controller or hand
- WebGL/WebGPU — the actual rendering layer; WebXR provides pose data, not rendering
Requesting a VR Session
webxr-session.jsjavascript
// Check for support
if (!navigator.xr) {
console.log('WebXR not supported');
} else {
const supported = await navigator.xr.isSessionSupported('immersive-vr');
if (supported) {
startButton.addEventListener('click', async () => {
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['local-floor'],
});
onSessionStarted(session);
});
}
}
function onSessionStarted(session) {
session.addEventListener('end', onSessionEnded);
// Attach session to your WebGL renderer
renderer.xr.setSession(session); // Three.js example
}Three.js XR Render Loop
three-xr.jsjavascript
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
// Add VR button
import { VRButton } from 'three/addons/webxr/VRButton.js';
document.body.appendChild(VRButton.createButton(renderer));
// The render loop runs at headset refresh rate (72-120 Hz)
renderer.setAnimationLoop((timestamp, frame) => {
// frame is an XRFrame when in XR, null otherwise
renderer.render(scene, camera);
});