Skip to content

VR/AR ​

Guide to VR and AR immersive experiences.

Overview ​

Graphty supports WebXR for immersive graph exploration. View your graphs in virtual reality (VR) or augmented reality (AR) using compatible headsets and browsers.

Checking Support ​

Before enabling XR modes, check browser and device support:

typescript
// Check VR support
const vrSupported = await graph.isVRSupported();
console.log("VR supported:", vrSupported);

// Check AR support
const arSupported = await graph.isARSupported();
console.log("AR supported:", arSupported);

Entering VR Mode ​

Via HTML Attribute ​

html
<graphty-element view-mode="vr"></graphty-element>

Via JavaScript ​

typescript
// Check support first
const vrSupported = await graph.isVRSupported();

if (vrSupported) {
    graph.setViewMode("vr");
} else {
    console.log("VR is not supported on this device");
}

Entering AR Mode ​

Via HTML Attribute ​

html
<graphty-element view-mode="ar"></graphty-element>

Via JavaScript ​

typescript
const arSupported = await graph.isARSupported();

if (arSupported) {
    graph.setViewMode("ar");
} else {
    console.log("AR is not supported on this device");
}

XR Configuration ​

Configure WebXR session options:

typescript
graph.setXRConfig({
    referenceSpace: "local-floor",
    sessionMode: "immersive-vr",
});

Reference Space Options ​

ValueDescription
localSmall-scale, seated experience
local-floorStanding experience with floor tracking
bounded-floorRoom-scale with boundaries
unboundedLarge-scale, free movement

Session Mode Options ​

ValueDescription
immersive-vrFull VR headset experience
immersive-arAR with environment pass-through
inlineNon-immersive (in-page preview)

Exiting XR ​

Return to normal 3D view:

typescript
await graph.exitXR();

// Or set view mode explicitly
graph.setViewMode("3d");

VR/AR Button ​

Create a button to enter XR:

html
<button id="vr-button" disabled>Enter VR</button>
<graphty-element></graphty-element>

<script type="module">
    import "@graphty/graphty-element";

    const button = document.getElementById("vr-button");
    const element = document.querySelector("graphty-element");

    // Wait for element to be ready
    await customElements.whenDefined("graphty-element");
    const graph = element.graph;

    // Check VR support
    const vrSupported = await graph.isVRSupported();

    if (vrSupported) {
        button.disabled = false;
        button.onclick = () => {
            graph.setViewMode("vr");
        };
    } else {
        button.textContent = "VR Not Supported";
    }
</script>

Browser Compatibility ​

VR Support ​

BrowserStatus
Chrome (desktop)✅ Full support
Chrome (Android)✅ Full support
Edge✅ Full support
Firefox⚠️ Partial support
Safari❌ Not supported

AR Support ​

BrowserStatus
Chrome (Android)✅ Full support with ARCore
Edge⚠️ Limited support
Safari (iOS)❌ Not supported (use Quick Look)

Headsets ​

DeviceVRAR
Meta Quest 2/3✅✅
HTC Vive✅❌
Valve Index✅❌
Windows Mixed Reality✅⚠️
Pico✅✅

Controller Interaction ​

In VR/AR mode, controllers can interact with the graph:

  • Point: Highlight nodes
  • Trigger: Select nodes
  • Grip: Drag nodes (if enabled)
  • Thumbstick: Navigate through the graph

Controller bindings depend on the specific headset and browser.

Performance in XR ​

XR requires high frame rates (72-120 fps). Tips for smooth performance:

  1. Reduce node count: Keep under 1000 nodes
  2. Simplify shapes: Use spheres instead of complex shapes
  3. Limit labels: Disable or reduce label rendering
  4. Pre-compute layouts: Use fixed layouts instead of live physics
typescript
// Optimize for XR
graph.setLayout("fixed");

// Simplify styles
await element.session.styles.add({
    name: "XR - simple nodes",
    target: "node",
    selector: { match: "everything" },
    set: { "node.shape": "sphere" },
});

A label is drawn because a layer wrote one. The way not to draw labels in XR is not to add that layer -- or, when one is already in the stack, to take it out by its id.

VR-Specific Styling ​

Adjust styles for VR visibility:

typescript
// Larger nodes and high contrast, on top of whatever is already in the stack
await element.session.styles.add({
    name: "VR - readable at arm's length",
    target: "node",
    selector: { match: "everything" },
    set: { "node.size": 2, "node.color": "#00FF00" },
});

// Thicker lines, visible in VR
await element.session.styles.add({
    name: "VR - thicker edges",
    target: "edge",
    selector: { match: "everything" },
    set: { "edge.width": 1.5 },
});

A layer added later paints over the layers under it, which is what "on top" means here: there is no priority number, only position in the stack.

AR Considerations ​

For AR experiences:

  1. Scale: Graph may need scaling to fit physical space
  2. Placement: Consider how the graph anchors in real world
  3. Lighting: AR lighting affects node visibility
  4. Occlusion: Real objects can occlude the graph

Not yet published

Placing and scaling the graph in the room is not something the element publishes an API for. The graph.setScale() and graph.setPosition() calls this page used to teach have never existed in any version, and a reader who copied them got a TypeError. Recorded in design/element-api/capability-losses.md.

What IS published for AR and VR today is the mode switch and the XR configuration: set element.viewMode to "ar" or "vr", and use element.xrConfig for the session options. The reader's own headset places the scene.

Event Handling in XR ​

XR has specific events:

typescript
graph.on("xr-session-started", () => {
    console.log("Entered XR mode");
});

graph.on("xr-session-ended", () => {
    console.log("Exited XR mode");
});

graph.on("xr-controller-connected", ({ controller }) => {
    console.log("Controller connected:", controller);
});

Testing Without Headset ​

Use browser developer tools:

  1. Chrome: DevTools > More tools > Sensors > WebXR
  2. Firefox: Install WebXR Emulator extension

Or use mobile AR without a headset:

typescript
// Check mobile AR support
if (arSupported && /Android/.test(navigator.userAgent)) {
    // Mobile AR available
    button.textContent = "View in AR";
}

Interactive Examples ​