Getting Started
XR Blocks is a lightweight, cross-platform library for rapidly prototyping advanced XR and AI experiences. Built upon three.js, it targets Chrome v136+ with WebXR support on Android XR. XR Blocks supports XR and desktop platforms, emphasizing a user-centric, developer-friendly SDK.
Installation & Import Options
XR Blocks can be imported directly into a webpage using an import map, or installed via npm and bundled.
Option A: Using an Import Map (No Build Step)
This is the fastest way to get started. You can use an import map to load XR Blocks and three.js directly from a CDN.
For a starter template, see templates/0_basic/index.html (note that while templates in the repository use relative paths for local development, your project should use the CDN URLs below).
To use an import map, add the following script tag to your index.html page.
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/",
"xrblocks": "https://cdn.jsdelivr.net/gh/google/xrblocks@build/xrblocks.js",
"xrblocks/addons/": "https://cdn.jsdelivr.net/gh/google/xrblocks@build/addons/"
}
}
</script>
Using xrblocks@build loads the latest development version of XR Blocks every time your web app loads.
To pin a build of XR Blocks, replace build with an SHA from the build branch or load a version from the xrblocks npm package using a URL such as https://cdn.jsdelivr.net/npm/xrblocks@0.1.0/build/xrblocks.js.
Checking versions...
Option B: Using npm & a Bundler
You can install XR Blocks and its peer dependency three.js via npm:
npm install xrblocks three
For a pre-configured template using TypeScript and Vite, check out templates/typescript/src/main.ts (and its associated templates/typescript/package.json and templates/typescript/tsconfig.json).
Handling Optional Dependencies
XR Blocks is designed to be highly modular. Features like GenAI, physics, hand tracking, and advanced UI blocks are kept external so you only bundle what you actually use.
If you want to install all optional dependencies at once (for example, to simplify TypeScript compilation or enable all features), run:
npm install @dimforge/rapier3d @google/genai openai lit @pmndrs/uikit @preact/signals-core @mediapipe/tasks-vision @mediapipe/tasks-audio troika-three-text @sparkjsdev/spark three-mesh-bvh
Otherwise, manage dependencies based on your tooling:
-
TypeScript: Because
xrblocksdeclaration files import types from optional dependencies (like@google/genaiorlit), the TypeScript compiler will complain about missing types. You can handle this in two ways:- Set
"skipLibCheck": true(Recommended): Adding"skipLibCheck": trueto thecompilerOptionssection of yourtsconfig.jsontells the compiler to skip type checking of declaration files (.d.tsfiles) insidenode_modules/. This is the easiest way to usexrblockswithout installing any unused optional dependencies. - Install Dev Dependencies: Alternatively, you can install the types/packages for the specific features you are using, or install all of them as devDependencies.
- Set
-
Bundler Configuration (Rollup, Vite, Webpack): If you are not using certain features and do not want to install their corresponding optional dependencies, you should configure your bundler to mark them as
externalso it skips trying to resolve them:// rollup.config.js / vite.config.jsexport default {external: ['@google/genai','@mediapipe/tasks-vision','@pmndrs/uikit','rapier3d',// Add other unused optional dependencies here],};
List of Optional Dependencies
- AI Integration:
@google/genai(Gemini),openai(OpenAI) - Physics:
@dimforge/rapier3d - UI Systems:
lit(Simulator UI overlay),@pmndrs/uikit(Rich UI blocks),@preact/signals-core(State management) - Gaussian Splatting:
@sparkjsdev/spark - Text Rendering:
troika-three-text - Vision & Audio (MediaPipe):
@mediapipe/tasks-vision(Hands/Face/Objects),@mediapipe/tasks-audio(Audio classification) - Performance & Utilities:
three-mesh-bvh(Accelerated raycasting)
Creating an Interactive Scene
XR Blocks uses a singleton engine driven by a script lifecycle. Rather than managing the renderer and canvas yourself, you write your app as one or more xb.Script subclasses and register them.
Upon importing, XR Blocks automatically creates the core singleton which manages the lifecycle, camera, and renderer.
Here is a complete, interactive example of a script-based scene:
import * as THREE from 'three';
import * as xb from 'xrblocks';
class InteractiveScene extends xb.Script {
init() {
// Runs once after registration; can be asynchronous.
// Add lighting to the scene
this.add(new THREE.HemisphereLight(0xffffff, 0x666666, 3));
// Create an interactive cube
this.cube = new THREE.Mesh(
new THREE.BoxGeometry(0.3, 0.3, 0.3),
new THREE.MeshStandardMaterial({color: 0x4285f4})
);
// Place the cube in front of the user (using user-physical context)
this.cube.position.set(0, xb.user.height - 0.3, -xb.user.objectDistance);
this.add(this.cube);
}
update(time, frame) {
// Runs on every animation frame.
this.cube.rotation.y += xb.getDeltaTime();
}
onSelectEnd() {
// Fired on a desktop click or a WebXR controller pinch/trigger release.
// Randomize the cube's color when selected.
this.cube.material.color.set(Math.random() * 0xffffff);
}
dispose() {
// Clean up three.js resources to prevent GPU memory leaks
this.cube.geometry.dispose();
this.cube.material.dispose();
}
}
// Bootstrap the application when the DOM is ready
document.addEventListener('DOMContentLoaded', () => {
xb.add(new InteractiveScene());
xb.init(new xb.Options());
});
init(): Sets up your lights, cameras, models, and UI. This is where you construct your 3D objects.update(): Updates positions, rotations, animations, and runs any per-frame logic.onSelectEnd(): Handles user clicks (desktop) and pinch/select releases (WebXR).dispose(): Disposes of geometries, materials, and textures to prevent memory leaks on the GPU when the script is removed from the scene.