WebXR Games: VR and AR Games You Can Play in a Browser

A WebXR game is a VR or AR game that runs directly in a browser via the WebXR API, with no app store and no install, and in Three.js it's built the same way as any other Three.js game (a scene, a render loop, physics and input) plus an immersive-vr or immersive-ar XR session that hands you head and controller tracking instead of mouse/keyboard input.

Last updated . Verified against three.js r181.

Read the FAQJump to code

What makes a WebXR game different from a regular Three.js game

The rendering and game-logic layer is identical to any other Three.js game: scene graph, physics, collision, a render loop. What changes is the input and camera model: instead of a fixed camera driven by mouse/keyboard, WebXR hands you real-time head pose and (where supported) hand or controller pose every frame, and the renderer draws a stereo pair of frames instead of one.

Three.js's renderer.xr module handles most of the plumbing: requesting an XR session, getting controller objects with their own position/orientation, and running the render loop at the headset's native refresh rate via renderer.setAnimationLoop() rather than requestAnimationFrame.

Device and browser reality for WebXR games

Before designing a WebXR game, know the actual reachable audience. See the full breakdown in the WebXR guide:

  • Meta Quest Browser is the strongest target: full immersive-vr support, hand tracking, controllers. Most browser VR games are realistically built for Quest first.
  • Android Chrome supports immersive-ar, including hit-testing for placing objects on real surfaces: the largest reachable AR-in-browser audience.
  • Safari on iPhone/iPad has no WebXR support at all. A WebXR game will not reach iOS users through the WebXR path. Plan a non-immersive fallback (a "play without VR" mode using the model in a regular 3D viewer) if iOS reach matters to your project.

Designing for "everyone" means the non-immersive mode is the actual product for most visitors, with the immersive session as a bonus for the minority who can enter it.

Building a WebXR game in Three.js

The core additions on top of a normal Three.js game loop:

  1. Add an XR "Enter VR" button (Three.js ships a ready-made VRButton helper) that requests the XR session.
  2. Read controller objects via renderer.xr.getController(0)/getController(1) and add visual representations (a simple cone or a loaded controller model) as children of the scene.
  3. Handle selectstart/selectend events on each controller for the trigger button. This is your primary interaction input, replacing mouse click.
  4. Switch renderer.setAnimationLoop() instead of requestAnimationFrame. This is required for XR, since the headset drives the frame timing, not the browser tab.

Tools and libraries

See it in production

Browse the full showcase →

Code

Minimal WebXR game loop (r181)
1import * as THREE from 'three'
2import { VRButton } from 'three/examples/jsm/webxr/VRButton.js'
3
4const renderer = new THREE.WebGLRenderer({ antialias: true })
5renderer.xr.enabled = true
6document.body.appendChild(VRButton.createButton(renderer))
7
8const controller = renderer.xr.getController(0)
9controller.addEventListener('selectstart', () => {
10 // trigger pressed: fire, grab, teleport
11})
12scene.add(controller)
13
14renderer.setAnimationLoop(() => {
15 // game logic here: this replaces requestAnimationFrame while in an XR session
16 renderer.render(scene, camera)
17})
Controller-driven interaction with TSL materials
1// TSL materials work unchanged inside a WebXR session. The XR layer only
2// affects the camera/input model, not materials or shading.
3import { color, uniform } from 'three/tsl'
4
5const grabbed = uniform(0) // toggled by controller selectstart/selectend
6const material = new THREE.MeshStandardNodeMaterial()
7material.emissiveNode = color(0x22c55e).mul(grabbed)
8
9controller.addEventListener('selectstart', () => grabbed.value = 1)
10controller.addEventListener('selectend', () => grabbed.value = 0)

Learn this properly

Learn Practical TSL

Your First Node Material

Build the material and scene fundamentals before adding a WebXR session on top.

Start the lesson (6 minutes)

Frequently asked questions

Can I play WebXR games without a VR headset?

Some WebXR games offer a non-immersive fallback mode viewable on a normal screen, but the core experience requires a supported device: a headset for immersive-vr, or an ARCore-capable Android phone for immersive-ar. WebXR is not supported on iPhone/iPad at all.

What devices support WebXR games?

Meta Quest Browser has the most complete WebXR support. Android Chrome supports AR sessions on ARCore-capable phones. Support on Safari (iOS) is entirely absent, and Firefox's WebXR support has been removed. See the WebXR guide for the full breakdown.

How do I build a WebXR game with Three.js?

Enable renderer.xr, add an "Enter VR" button (Three.js ships a VRButton helper), read controller input via renderer.xr.getController(), and switch your render loop to renderer.setAnimationLoop(). Everything else (scene, physics, game logic) is the same as a regular Three.js game.

Keep reading