WebXR Bridge
Bring WebXR apps to glasses-free 3D displays. A browser page gets the same display geometry, rendering modes, and tracked eye poses a native app does — and falls back to standard WebXR when the extension isn't there.
WebXR, but display-aware
Chrome's built-in WebXR is display-agnostic — generic stereo, compromise-scaled framebuffers, no concept of a physical 3D display. The DisplayXR WebXR Bridge fills that gap: a browser page acquires session.displayXR and gets display geometry in meters, vendor rendering modes, tracked eye poses, window metadata, and a compositor HUD — reaching parity with a native handle app, but from JavaScript.
It's a stopgap, by design. The bridge gives web apps the DisplayXR surface today, until browsers support these extensions natively. Apps written against it stay standard WebXR: when the extension isn't installed, session.displayXR is undefined and the page runs as ordinary WebXR. One codebase, everywhere.
How it works
A Chrome extension
An MV3 extension wraps navigator.xr and adds a session.displayXR surface to every WebXR session — present only when the extension is installed.
A local bridge
displayxr-webxr-bridge.exe runs a headless OpenXR session against the DisplayXR service, reads XR_EXT_display_info, rendering-mode events, and eye poses, and relays them over a 127.0.0.1:9014 WebSocket.
Frames stay untouched
Chrome's WebXR still renders your frames through OpenXR. The bridge only carries metadata and control on a side channel — no extra copy in the render path.
The session.displayXR API
Feature-detect, await the bridge handshake, then read display info, rendering modes, and eye poses. Always keep the standard-WebXR fallback path.
// A bridge-aware WebXR app: full DisplayXR features when the extension
// is installed, standard WebXR everywhere else.
const session = await navigator.xr.requestSession("immersive-vr", {
optionalFeatures: ["local"],
});
let displayXR = session.displayXR; // undefined without the extension
if (displayXR?.ready) {
try {
await displayXR.ready; // bridge handshake (~10ms warm)
displayXR = session.displayXR; // re-read: now populated
const { displaySizeMeters } = displayXR.displayInfo;
displayXR.configureEyePoses("raw"); // stream tracked eye poses
// → off-axis (Kooima) projection, rendering-mode switching, HUD …
} catch {
// bridge unavailable → fall through to standard WebXR
}
}
// else: standard WebXR — Chrome's compromise-scaled stereo.Full surface, events, and the per-frame loop are in the developer guide; the wire protocol is in PROTOCOL.md.
Try it
The bridge needs the DisplayXR runtime running locally, so there's no zero-install web demo — but the extension and a full three.js reference sample ship in the runtime repo. Windows today.
- 1
Install DisplayXR (runtime + WebXR bridge) — see Download / Get Started. Start the service and
displayxr-webxr-bridge.exe. - 2
Load the extension (not on the Chrome Web Store yet): open
chrome://extensions, enable Developer mode, click Load unpacked, and selectwebxr-bridge/extension/. - 3
Open a sample — serve
webxr-bridge/sample/over localhost (python -m http.server 8080) and open it in Chrome. Full setup is in the README.
The WebXR Bridge ships in the webxr-bridge/ folder of the runtime repo — extension, samples, and docs.