The WebXR Device API

The WebXR Device API provides access to input (pose information from headset and controllers) and output (hardware display) capabilities commonly associated with Virtual Reality (VR) and Augmented Reality (AR) devices. It allows you develop and host VR and AR experiences on the web.

You can read more about the goals of this standardisation effort by reading the WebXR Explainer.

What does this mean...

For phones:

Enable VR by providing pose information and allowing the WebGL scene to be rendered side by side to be placed in a headset like the Cardboard

Enable AR by using the platforms AR capabilities such as ARCore to render the WebGL scene onto the users environment like a magic window.

For Desktops:

Desktop computers can make use of tethered VR hardware such as the Oculus Rift or HTC Vive to display the VR scene

For standalone AR Headsets:

Enable AR by using the platforms AR capabilities to render the WebGL scene immersively onto the users environment.

For standalone VR Headsets:

Enable VR by rendering the scene using the platforms VR capabilities.

Try out some Demos

A demo of VR and AR with the WebXR Device API, embedded with an iframe, for iframes allow="xr" is requred.

These are samples from the WebXR Samples from the Immersive Web Working Group They use a very minimal libary to show how one can make use of the WebXR Device API directly.

This sample demonstrates use of an 'inline' XRSession to present content on the page prior to entering XR presentation with an immersive session.
This sample demonstrates basic tracking and rendering of XRInputSources. It does not respond to button presses or other controller interactions.
This sample demonstrates teleporting the viewer by updating the XRSession reference space.

Benefits of doing XR on the Web

WebXR in the Real World

Hello WebXR

Mozilla Mixed Reality

The demo is designed as a playground where you can try different experiences and interactions in VR, and introduce newcomers to the VR world and its special language in a smooth, easy and nice way.

XR Dinosaurs

Brandon Jones

Welcome to the web's virtual Dinosaur Park!

We've used the magic of your browser to bring back a friendly pack of prehistoric pals.

Our dinosaurs can be viewed with a variety of Virtual Reality headsets, Augmented Reality headsets and phones, or directly in your browser.

What You Don't Know

Jono & Mr. Doob

Dive into the creative process of avant-pop artist Matthew Dear from his new single of the same name. Floating above you is a magic eight-ball reciting lyrics. In the distance planetary objects orbit around you to the beat. And directly ahead is an elastic donut which bounces, bulges, and twists to the complex melodies.

Getting started building a WebXR Website

These are brief guides to building a site which uses and AR and VR.

The WebXR device API relies on graphics APIs like WebGL & WebGL2 to work, these graphics libraries and frameworks come with WebXR support built in.

AR and VR

A-Frame, is a JS library to use HTML to create VR and AR experiences in the Web.

A-Frame is based on THREE.js and has a large community, as well as lots of community made custom elements and components.

<html>
  <head>
    <script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

Babylon.js is an easy to use real-time 3D game engine built using TypeScript. It has full WebXR support out of the box, including gaze and teleportation support, AR experimental features and more. To simplify WebXR development Babylon.js offers the WebXR Experience Helper, which is the one-stop-shop for all XR-related functionalities.

To get started use the Babylon.js playground, or try these demos:

  • https://playground.babylonjs.com/#PPM311
  • https://playground.babylonjs.com/#JA1ND3#164

To start on your own use this simple template:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
        <title>Babylon - Getting Started</title>
        <!--- Link to the last version of BabylonJS --->
        <script src="https://preview.babylonjs.com/babylon.js"></script>
        <style>
            html,
            body {
                overflow: hidden;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
            }

            #renderCanvas {
                width: 100%;
                height: 100%;
                touch-action: none;
            }
        </style>
    </head>

    <body>
        <canvas id="renderCanvas"></canvas>
        <script>
            window.addEventListener('DOMContentLoaded', async function () {
                // get the canvas DOM element
                var canvas = document.getElementById('renderCanvas');
                // load the 3D engine
                var engine = new BABYLON.Engine(canvas, true);
                // createScene function that creates and return the scene
                var createScene = async function () {
                    // create a basic BJS Scene object
                    var scene = new BABYLON.Scene(engine);
                    // create a FreeCamera, and set its position to (x:0, y:5, z:-10)
                    var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);
                    // target the camera to scene origin
                    camera.setTarget(BABYLON.Vector3.Zero());
                    // attach the camera to the canvas
                    camera.attachControl(canvas, false);
                    // create a basic light, aiming 0,1,0 - meaning, to the sky
                    var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);
                    // create a built-in "sphere" shape; its constructor takes 6 params: name, segment, diameter, scene, updatable, sideOrientation 
                    var sphere = BABYLON.Mesh.CreateSphere('sphere1', 16, 2, scene);
                    // move the sphere upward 1/2 of its height
                    sphere.position.y = 1;
                    // create a built-in "ground" shape;
                    var ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene);

                    // Add XR support
                    var xr = await scene.createDefaultXRExperienceAsync({/* configuration options, as needed */})
                    // return the created scene
                    return scene;
                }

                // call the createScene function
                var scene = await createScene();

                // run the render loop
                engine.runRenderLoop(function () {
                    scene.render();
                });

                // the canvas/window resize event handler
                window.addEventListener('resize', function () {
                    engine.resize();
                });
            });
        </script>
    </body>
</html>

For advanced examples and documentation see the Babylon.js WebXR documentation page

Model viewer is a custom HTML element for displaying 3D models and vieweing them in AR

AR

<!-- Import the component -->
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.js"></script>
<script nomodule src="https://unpkg.com/@google/model-viewer/dist/model-viewer-legacy.js"></script>

<!-- Use it like any other HTML element -->
<model-viewer src="examples/assets/Astronaut.glb" ar alt="A 3D model of an astronaut" auto-rotate camera-controls background-color="#455A64"></model-viewer>

PlayCanvas is an open-source game engine. It uses HTML5 and WebGL to run games and other interactive 3D content in any mobile or desktop browser.

Full documentation available on the PlayCanvas Developer site including API reference. Also check out XR tutorials with sources using online Editor as well as engine-only examples and their source code.

Below is basic example of setting up PlayCanvas application, simple scene with light and some cubes aranged in grid. And Immersive VR session on click/touch if WebXR is supported:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>PlayCanvas Basic VR</title>
    <meta charset="utf-8">
    <script src="https://unpkg.com/playcanvas"></script>
    <style type="text/css">
        body {
            margin: 0;
            overflow: hidden;
        }
        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        let canvas = document.getElementById('canvas');

        // create application
        let app = new pc.Application(canvas, {
            mouse: new pc.Mouse(canvas),
            touch: new pc.TouchDevice(canvas)
        });

        // set resizing rules
        app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
        app.setCanvasResolution(pc.RESOLUTION_AUTO);
        // handle window resize
        window.addEventListener("resize", function () {
            app.resizeCanvas(canvas.width, canvas.height);
        });

        // use device pixel ratio
        app.graphicsDevice.maxPixelRatio = window.devicePixelRatio;

        // start an application
        app.start();


        // create camera
        let cameraEntity = new pc.Entity();
        cameraEntity.addComponent("camera", {
            clearColor: new pc.Color(0.3, 0.3, 0.3)
        });
        app.root.addChild(cameraEntity);

        // create light
        let light = new pc.Entity();
        light.addComponent("light", {
            type: "spot",
            range: 30
        });
        light.translate(0,10,0);
        app.root.addChild(light);

        let SIZE = 8;

        // create floor plane
        let plane = new pc.Entity();
        plane.addComponent("model", {
            type: "plane"
        });
        plane.setLocalScale(SIZE * 2, 1, SIZE * 2);
        app.root.addChild(plane);

        // create a grid of cubes
        for (let x = 0; x < SIZE; x++) {
            for (let z = 0; z < SIZE; z++) {
                let cube = new pc.Entity();
                cube.addComponent("model", {
                    type: "box"
                });
                cube.setPosition(2 * x - SIZE + 1, 0.5, 2 * z - SIZE + 1);
                app.root.addChild(cube);
            }
        }


        // if XR is supported
        if (app.xr.supported) {
            // handle mouse / touch events
            let onTap = function (evt) {
                // if immersive VR supported
                if (app.xr.isAvailable(pc.XRTYPE_VR)) {
                    // start immersive VR session
                    cameraEntity.camera.startXr(pc.XRTYPE_VR, pc.XRSPACE_LOCALFLOOR);
                }
                evt.event.preventDefault();
                evt.event.stopPropagation();
            };
            // attach mouse / touch events
            app.mouse.on("mousedown", onTap);
            app.touch.on("touchend", onTap);
        }
    </script>
</body>
</html>

React 360 is a framework for the creation of 3D and VR user interfaces.

Three.js is a cross-browser JavaScript library used to create and display animated 3D computer graphics in a web browser. It has a large community, good docs, and many examples.

Using VR is largely the same as regular Three.js applications. Setup the scene, camera, and renderer. The major difference is setting the vr.enabled flag to true on the renderer. There is an optional VRButton class to make a button that will enter and exit VR for you.

For more info, see this guide to VR in Three.js and the WebXR examples.

Here is a full example that sets up a scene with a rotating red cube.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        body {
            margin: 0;
            background-color: #000;
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <script type="module">
        // Import three
        import * as THREE from 'https://unpkg.com/three/build/three.module.js';
        // Import the default VRButton
        import { VRButton } from 'https://unpkg.com/three/examples/jsm/webxr/VRButton.js';

        // Make a new scene
        let scene = new THREE.Scene();
        // Set background color of the scene to gray
        scene.background = new THREE.Color(0x505050);

        // Make a camera. note that far is set to 100, which is better for realworld sized environments
        let camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(0, 1.6, 3);
        scene.add(camera);

        // Add some lights
        var light = new THREE.DirectionalLight(0xffffff,0.5);
        light.position.set(1, 1, 1).normalize();
        scene.add(light);
        scene.add(new THREE.AmbientLight(0xffffff,0.5))

        // Make a red cube
        let cube = new THREE.Mesh(
            new THREE.BoxBufferGeometry(1,1,1),
            new THREE.MeshLambertMaterial({color:'red'})
        );
        cube.position.set(0, 1.5, -10);
        scene.add(cube);

        // Make a renderer that fills the screen
        let renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        // Turn on VR support
        renderer.vr.enabled = true;
        // Set animation loop
        renderer.setAnimationLoop(render);
        // Add canvas to the page
        document.body.appendChild(renderer.domElement);

        // Add a button to enter/exit vr to the page
        document.body.appendChild(VRButton.createButton(renderer));

        // For AR instead, import ARButton at the top
        //    import { ARButton } from 'https://unpkg.com/three/examples/jsm/webxr/ARButton.js';
        // then create the button
        //  document.body.appendChild(ARButton.createButton(renderer));

        // Handle browser resize
        window.addEventListener('resize', onWindowResize, false);

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function render(time) {
            // Rotate the cube
            cube.rotation.y = time / 1000;
            // Draw everything
            renderer.render(scene, camera);
        }
    </script>
</body>
</html>

Here is a full example of an immersive-ar demo made using three.js

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js ar - cones</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>

		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> ar - cones<br/>
		</div>

		<script type="module">

            		import * as THREE from 'https://unpkg.com/three/build/three.module.js';
			import { ARButton } from 'https://unpkg.com/three/examples/jsm/webxr/ARButton.js';

			var container;
			var camera, scene, renderer;
			var controller;

			init();
			animate();

			function init() {

				container = document.createElement( 'div' );
				document.body.appendChild( container );

				scene = new THREE.Scene();

				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 20 );

				var light = new THREE.HemisphereLight( 0xffffff, 0xbbbbff, 1 );
				light.position.set( 0.5, 1, 0.25 );
				scene.add( light );

				//

				renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.xr.enabled = true;
				container.appendChild( renderer.domElement );

				//

				document.body.appendChild( ARButton.createButton( renderer ) );

				//

				var geometry = new THREE.CylinderBufferGeometry( 0, 0.05, 0.2, 32 ).rotateX( Math.PI / 2 );

				function onSelect() {

					var material = new THREE.MeshPhongMaterial( { color: 0xffffff * Math.random() } );
					var mesh = new THREE.Mesh( geometry, material );
					mesh.position.set( 0, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
					mesh.quaternion.setFromRotationMatrix( controller.matrixWorld );
					scene.add( mesh );

				}

				controller = renderer.xr.getController( 0 );
				controller.addEventListener( 'select', onSelect );
				scene.add( controller );

				//

				window.addEventListener( 'resize', onWindowResize, false );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			//

			function animate() {

				renderer.setAnimationLoop( render );

			}

			function render() {

				renderer.render( scene, camera );

			}

		</script>
	</body>
</html>

Unity is a GUI based game engine

Click on a tab to begin.

Tooling

WebXR API Emulator

Mozilla Mixed Reality

WebXR Emulator extension, for Chrome and Firefox enables users and developers to run and test WebXR content in desktop browsers without using a real XR device. The extension will emulate the WebXR API on browsers that don’t support it yet and also provide a list of XR devices with their controllers to emulate.

WebXR Input Profiles

W3C Immersive Web Working Group

This repo provides a javascript library for managing known motion controller profiles, loading the most ideal known profile for a supplied input source, and creating a MotionController object that binds them together. Developers can use this library to interact with the conceptual components of an input source, rather than each individual button or axis.

Support Table for the WebXR Device API

Note: this table is incomplete.

Feature Name Standardisation Polyfill Chrome Firefox Reality Servo WebXR Viewer Magic Leap Helio Samsung Internet Oculus Browser
WebXR Core Explainer
Spec
Supported, will make use of WebVR if available and WebXR is not. Chrome 79 Android standalones. PC coming soon Hololens2 iOS Magic Leap Helio 0.98 Samsung Internet 11.2 (Q2 2020) 7.0, December 2019
WebXR AR Module Explainer
Spec
Not Supported Chrome for Android, 81 Hololens2 iOS Magic Leap Helio 0.98 Samsung Internet 12.1 Not Supported
WebXR Gamepads Module Explainer
Spec
Supported Chrome 79 Partially supported on Magic Leap Helio 0.98 7.1, December 2019
Hit Test Explainer
Spec
Chrome for Android, 81 Samsung Internet 12.1
DOM Overlays Explainer
Spec
Chrome for Android, 83
Layers Explainer
Spec
Prototyped for Hololens2 behind a pref 10.0,
June 2020
behind a pref
Hand input Explainer
Additional Details Hardware Support Details Final release announcement 2.0 announcement