WebXR Demos and Examples

Basic scene

This is a step-by-step guide on how to add XR features to a basic scene

Basic Scene with XR Support

Here we just add an environment, a sphere, and XR support

const xrHelper = await scene.createDefaultXRExperienceAsync();
Basic Scene With WebXR Support

Adding teleportation

To get teleportation enabled, we want to provide the experience helper with an array of floor meshes:

const xrHelper = await scene.createDefaultXRExperienceAsync({
// define floor meshes
floorMeshes: [environment.ground]
Basic Scene With Teleportation

Adding a color picker to the basic scene

Add a color picker (from our GUI library) and use it to change the sphere's color.

Notice that no changes were made in the XR code, and that the scene works perfectly well outside VR as well.

// GUI
var plane = BABYLON.Mesh.CreatePlane("plane", 1);
plane.position = new BABYLON.Vector3(1.4, 1.5, 0.4)
var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(plane);
var panel = new BABYLON.GUI.StackPanel();
var header = new BABYLON.GUI.TextBlock();
header.text = "Color GUI";
header.height = "100px";
header.color = "white";
header.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
header.fontSize = "120"
var picker = new BABYLON.GUI.ColorPicker();
picker.value = sphere.material.diffuseColor;
picker.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
picker.height = "350px";
picker.width = "350px";
picker.onValueChangedObservable.add(function(value) {
WebXR Color Picker

Other demos

Goalkeeper Training Legacy Physics Playground A cylinder object is child of a controller Simply grabbing objects by controllers

Babylon.js scenes with XR support

Mansion Hill Valley Espilit

WebXR with Vite

Step-by-step project setup using Vite and Babylon.js ES6 modules for WebXR development.

Install Vite

## Setup vite
npm create vite@latest
##> Project name: babylon-webxr-test
##> Select a framework: vanilla
##> Select a variant: vanilla-ts

Install @babylonjs ES6 packages

npm install @babylonjs/core@^5.0.0-beta.8
npm install @babylonjs/loaders@^5.0.0-beta.8

Enable HTTPS dev server

HTTPS is required by most VR devices. Create or modify vite.config.ts:

import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 3443,
https: true,
// Uncomment to allow access from network
// (or use `npm run dev -- -- host=`)
//host: '',

Set up a basic WebXR scene

Modify the main.ts file:

import './style.css'
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js'
import { Color3 } from '@babylonjs/core/Maths/math.color.js'
import { Engine } from '@babylonjs/core/Engines/engine.js'
import { EnvironmentHelper } from '@babylonjs/core/Helpers/environmentHelper.js'
import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight.js'
import { Mesh } from '@babylonjs/core/Meshes/mesh'
import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder.js'
import { Scene } from '@babylonjs/core/scene.js'
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial.js'
import { Vector3 } from '@babylonjs/core/Maths/math.vector.js'
import { WebXRDefaultExperience } from '@babylonjs/core/XR/webXRDefaultExperience.js'
// Required for EnvironmentHelper
import '@babylonjs/core/Materials/Textures/Loaders'
// Enable GLTF/GLB loader for loading controller models from WebXR Input registry
import '@babylonjs/loaders/glTF'
// Without this next import, an error message like this occurs loading controller models:
// Build of NodeMaterial failed" error when loading controller model
// Uncaught (in promise) Build of NodeMaterial failed: input rgba from block
// FragmentOutput[FragmentOutputBlock] is not connected and is not optional.
import '@babylonjs/core/Materials/Node/Blocks'
// Create a canvas element for rendering
const app = document.querySelector<HTMLDivElement>('#app')
const canvas = document.createElement('canvas')
// Create engine and a scene
const babylonEngine = new Engine(canvas, true)
const scene = new Scene(babylonEngine)
// Add a basic light
new HemisphericLight('light1', new Vector3(0, 2, 0), scene)
// Create a default environment (skybox, ground mesh, etc)
const envHelper = new EnvironmentHelper({
skyboxSize: 30,
groundColor: new Color3(0.5, 0.5, 0.5),
}, scene)
// Add a camera for the non-VR view in browser
const camera = new ArcRotateCamera("Camera", -(Math.PI / 4) * 3, Math.PI / 4, 10, new Vector3(0, 0, 0), scene);
// Add a sphere to have something to look at
const sphereD = 1.0
const sphere = MeshBuilder.CreateSphere('xSphere', { segments: 16, diameter: sphereD }, scene)
sphere.position.x = 0
sphere.position.y = sphereD * 2
sphere.position.z = 0
const rMat = new StandardMaterial("matR", scene)
rMat.diffuseColor = new Color3(1.0, 0, 0)
sphere.material = rMat
// Setup default WebXR experience
// Use the enviroment floor to enable teleportation
WebXRDefaultExperience.CreateAsync(scene, {
floorMeshes: [envHelper?.ground as Mesh],
optionalFeatures: true,
// Run render loop
babylonEngine.runRenderLoop(() => {

Corresponding git repo: kaliatech/babylon-docs-vite-webxr

Run server and verify

Start vite dev server and make it accessible from the network:

npm run dev -- --host

Browsing to https://<your-server-ip>:3443 on a desktop machine should show the basic scene. If the WebXR API Emulator is enabled, you should also see Babylon.js's default VR headset mode icon

If viewing from within a headset, the controller models should correspond to what is available in the global registry for your device.

To check TypeScript types and build:

npm run build

Using the setup above, vite reports a vendor.js size of ~2.4MB (520k gzipped) as of babylon-5.0.0-beta.8.