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:
// 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
<graphty-element view-mode="vr"></graphty-element>Via JavaScript
// 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
<graphty-element view-mode="ar"></graphty-element>Via JavaScript
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:
graph.setXRConfig({
referenceSpace: "local-floor",
sessionMode: "immersive-vr",
});Reference Space Options
| Value | Description |
|---|---|
local | Small-scale, seated experience |
local-floor | Standing experience with floor tracking |
bounded-floor | Room-scale with boundaries |
unbounded | Large-scale, free movement |
Session Mode Options
| Value | Description |
|---|---|
immersive-vr | Full VR headset experience |
immersive-ar | AR with environment pass-through |
inline | Non-immersive (in-page preview) |
Exiting XR
Return to normal 3D view:
await graph.exitXR();
// Or set view mode explicitly
graph.setViewMode("3d");VR/AR Button
Create a button to enter XR:
<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
| Browser | Status |
|---|---|
| Chrome (desktop) | ✅ Full support |
| Chrome (Android) | ✅ Full support |
| Edge | ✅ Full support |
| Firefox | ⚠️ Partial support |
| Safari | ❌ Not supported |
AR Support
| Browser | Status |
|---|---|
| Chrome (Android) | ✅ Full support with ARCore |
| Edge | ⚠️ Limited support |
| Safari (iOS) | ❌ Not supported (use Quick Look) |
Headsets
| Device | VR | AR |
|---|---|---|
| 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:
- Reduce node count: Keep under 1000 nodes
- Simplify shapes: Use spheres instead of complex shapes
- Limit labels: Disable or reduce label rendering
- Pre-compute layouts: Use fixed layouts instead of live physics
// 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:
// 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:
- Scale: Graph may need scaling to fit physical space
- Placement: Consider how the graph anchors in real world
- Lighting: AR lighting affects node visibility
- 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:
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:
- Chrome: DevTools > More tools > Sensors > WebXR
- Firefox: Install WebXR Emulator extension
Or use mobile AR without a headset:
// Check mobile AR support
if (arSupported && /Android/.test(navigator.userAgent)) {
// Mobile AR available
button.textContent = "View in AR";
}