The CloudXR.js Session API provides comprehensive management of streaming sessions with the CloudXR Runtime. This guide covers the core session lifecycle, configuration, and key operations.
CloudXR.js is a JavaScript Client SDK that enables WebXR streaming from the CloudXR Runtime. It requires compatible server applications such as Isaac Lab, or any OpenXR-compatible application running with the CloudXR Runtime.
The CloudXR session follows a well-defined lifecycle with distinct states and transitions:
Initialized → Connecting → Connected → Disconnecting → Disconnected
Full API reference: createSession
import { createSession } from '@nvidia/cloudxr';
const session = createSession({
serverAddress: 'your-server',
serverPort: 49100,
useSecureConnection: false,
gl: webglContext,
perEyeWidth: 2048,
perEyeHeight: 1792,
referenceSpace: xrReferenceSpace,
// Additional configuration options
});
Note: The perEyeWidth and perEyeHeight parameters specify the resolution for each eye. The actual stream resolution will be calculated automatically:
perEyeWidth * 2perEyeHeight * 9 / 4See SessionOptions for all available configuration options.
Full API reference: Session
// Connect throws an error if connection cannot be initiated
try {
session.connect();
console.log('Session connection initiated');
// Connection state changes will be reported via delegates
} catch (error) {
console.error('Failed to initiate connection:', error.message);
}
// Disconnect from the server
session.disconnect();
The session will transition to SessionState.Disconnecting state immediately. Then to SessionState.Disconnected state when the disconnection is complete.
Note: CloudXR.js does not currently support pause/resume functionality. To temporarily stop streaming, disconnect the session and reconnect when needed.
// Send viewer pose and input tracking to server
const success = session.sendTrackingStateToServer(timestamp, xrFrame);
if (!success) {
console.warn('Failed to send tracking state');
}
// Render a frame from CloudXR Runtime
session.render(timestamp, xrFrame, xrWebGLLayer);
// Send custom message to server
try {
session.sendServerMessage(messageObject);
console.log('Message sent successfully');
} catch (error) {
console.error('Failed to send server message:', error.message);
}
CloudXR uses a delegate-based event system. Pass delegates when creating the session:
const sessionDelegates = {
onStreamStarted: () => {
console.log('Streaming started');
},
onStreamStopped: (error) => {
if (error) {
console.log('Streaming stopped due to error:', error);
} else {
console.log('Streaming stopped normally');
}
},
onWebGLStateChangeBegin: () => {
// Called before session changes WebGL state
console.log('WebGL state change beginning');
},
onWebGLStateChangeEnd: () => {
// Called after session changes WebGL state
console.log('WebGL state change complete');
}
};
const session = createSession(sessionOptions, sessionDelegates);
See SessionDelegates for more details.
// Check current session state
console.log('Current state:', session.state);
// Request WebXR session
const xrSession = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['local-floor']
});
// Get WebGL context and reference space
const gl = xrSession.renderState.baseLayer.context;
const referenceSpace = await xrSession.requestReferenceSpace('local-floor');
// Create CloudXR session
const sessionOptions = {
serverAddress: 'your-server',
serverPort: 49100,
useSecureConnection: false,
gl: gl,
perEyeWidth: 2048,
perEyeHeight: 1792,
referenceSpace: referenceSpace,
deviceFrameRate: 90,
maxStreamingBitrateKbps: 150000
};
const sessionDelegates = {
onStreamStarted: () => console.log('CloudXR streaming started'),
onStreamStopped: (error) => console.log('CloudXR streaming stopped', error)
};
const cloudxrSession = createSession(sessionOptions, sessionDelegates);
// Connect to CloudXR Runtime
try {
cloudxrSession.connect();
console.log('CloudXR connection initiated');
} catch (error) {
console.error('Failed to initiate CloudXR connection:', error.message);
}
// Begin rendering loop
function renderFrame(time, frame) {
// Send tracking state to server
cloudxrSession.sendTrackingStateToServer(time, frame);
// Render CloudXR frame
cloudxrSession.render(time, frame, xrSession.renderState.baseLayer);
// Continue rendering
xrSession.requestAnimationFrame(renderFrame);
}
xrSession.requestAnimationFrame(renderFrame);
CloudXR automatically handles controller input and hand tracking through the WebXR session. The tracking data is sent to the server via sendTrackingStateToServer():
// Controllers and hand tracking are automatically handled
// when you call sendTrackingStateToServer with the XR frame
function renderFrame(time, frame) {
// This automatically includes controller and hand tracking data
cloudxrSession.sendTrackingStateToServer(time, frame);
// Render the frame
cloudxrSession.render(time, frame, xrWebGLLayer);
}
The server will receive all input data including:
const sessionDelegates = {
onStreamStarted: () => {
console.log('Streaming started successfully');
},
onStreamStopped: (error) => {
if (error) {
console.error('Streaming stopped due to error:', error);
// Handle specific error types
if (error.message.includes('connection')) {
console.error('Connection error - check network and server');
}
} else {
console.log('Streaming stopped normally');
}
}
};
// Connect throws an error if connection cannot be initiated
try {
session.connect();
} catch (error) {
console.error('Failed to initiate connection:', error.message);
}
// Send tracking state returns false if not connected
if (!session.sendTrackingStateToServer(timestamp, frame)) {
console.warn('Cannot send tracking state - session not connected');
}
// Send server message throws an error if not connected or invalid message
try {
session.sendServerMessage(message);
} catch (error) {
console.error('Failed to send server message:', error.message);
}
For comprehensive WebXR performance monitoring and debugging tools, refer to the Meta Horizon WebXR Performance Tools documentation.
CloudXR.js requires a compatible server running:
The server must be accessible via WebSocket connection and properly configured for CloudXR streaming.
See our Getting Started Guide for more details.