### Handle Session Start and Setup Source: https://github.com/immersive-web/webxr/blob/main/explainer.md After a session starts, store the session, request a reference space, set up the WebGL layer, and begin the render loop by calling `xrSession.requestAnimationFrame`. ```javascript let xrSession = null; let xrReferenceSpace = null; function onSessionStarted(session) { // Store the session for use later. xrSession = session; xrSession.requestReferenceSpace('local') .then((referenceSpace) => { xrReferenceSpace = referenceSpace; }) .then(setupWebGLLayer) // Create a compatible XRWebGLLayer .then(() => { // Start the render loop xrSession.requestAnimationFrame(onDrawFrame); }); } ``` -------------------------------- ### WebVR Rendering Setup Source: https://github.com/immersive-web/webxr/blob/main/webvr-migration.md This code snippet demonstrates the setup for WebVR rendering, including requesting presentation, getting eye parameters, and setting the canvas dimensions based on these parameters. ```javascript let glCanvas = document.createElement('canvas'); let gl = document.getContext('webgl'); await vrDisplay.requestPresent([{ source: glCanvas }]); let leftEye = vrDisplay.getEyeParameters("left"); let rightEye = vrDisplay.getEyeParameters("right"); glCanvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2; glCanvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight); // Now presenting to the headset. ``` -------------------------------- ### XRInputSource Profiles Example Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md Example of `profiles` strings for identifying XR input devices. Applications should iterate through this list to find a known model. ```javascript ["samsung-odyssey", "microsoft-mixed-reality", "generic-trigger-squeeze-touchpad-thumbstick"] ``` -------------------------------- ### Visualize Bounded Geometry Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md This example demonstrates how to visualize the boundary geometry of a 'bounded-floor' reference space. It iterates through the provided points to create a mesh, useful for understanding the playable area. ```javascript // Demonstrated here using a fictional 3D library to simplify the example code. function createBoundsMesh() { boundsMesh.clear(); // Visualize the bounds geometry as 2 meter high quads let pointCount = xrReferenceSpace.boundsGeometry.length; for (let i = 0; i < pointCount - 1; ++i) { let pointA = xrReferenceSpace.boundsGeometry[i]; let pointB = xrReferenceSpace.boundsGeometry[i+1]; boundsMesh.addQuad( pointA.x, 0, pointA.z, // Quad Corner 1 pointB.x, 2.0, pointB.z) // Quad Corner 2 } // Close the loop let pointA = xrReferenceSpace.boundsGeometry[pointCount-1]; let pointB = xrReferenceSpace.boundsGeometry[0]; boundsMesh.addQuad( pointA.x, 0, pointA.z, // Quad Corner 1 pointB.x, 2.0, pointB.z) // Quad Corner 2 } } ``` -------------------------------- ### Generate Spec Document with Make Source: https://github.com/immersive-web/webxr/blob/main/README.md Use the 'make' command to generate the spec document from the Bikeshed source file. Ensure you have Bikeshed installed. ```sh make ``` -------------------------------- ### Handle XR Session Start and Reference Space Source: https://context7.com/immersive-web/webxr/llms.txt Callback function after an XR session starts. Checks for enabled features like 'local' tracking and requests the appropriate reference space. ```javascript function onSessionStarted(session) { xrSession = session; // Check if motion tracking is available if (session.enabledFeatures.includes('local')) { session.requestReferenceSpace('local') .then(onLocalReferenceSpaceCreated); } else { // Fallback to viewer space with click-drag controls session.requestReferenceSpace('viewer') .then(onViewerReferenceSpaceCreated); } } ``` -------------------------------- ### Handle WebXR Input Sources and Events Source: https://context7.com/immersive-web/webxr/llms.txt Set up event listeners for session start, input source changes, and selection events. Prioritizes input sources for interaction. ```javascript let xrInputSources = []; let preferredInputSource = null; function onSessionStarted(session) { xrSession = session; // Listen for input source changes xrSession.addEventListener('inputsourceschange', onInputSourcesChange); // Listen for selection events xrSession.addEventListener('select', onSelect); xrSession.addEventListener('selectstart', onSelectStart); xrSession.addEventListener('selectend', onSelectEnd); } function onInputSourcesChange(event) { xrInputSources = event.session.inputSources; // Log added/removed sources for (const added of event.added) { console.log("Input added:", added.targetRayMode, added.handedness); } for (const removed of event.removed) { console.log("Input removed:", removed.targetRayMode); } // Update preferred input source preferredInputSource = computePreferredInputSource(); } function computePreferredInputSource() { // Prioritize: screen > tracked-pointer > gaze for (const source of xrInputSources) { if (source.targetRayMode === 'screen') return source; } for (const source of xrInputSources) { if (source.targetRayMode === 'tracked-pointer') return source; } for (const source of xrInputSources) { if (source.targetRayMode === 'gaze') return source; } return null; } function onSelect(event) { const inputSource = event.inputSource; const frame = event.frame; // Get pose at selection time const pose = frame.getPose(inputSource.targetRaySpace, xrReferenceSpace); if (pose) { // Perform hit test and handle selection const hitResult = scene.hitTest(pose.transform); if (hitResult) { handleObjectSelection(hitResult.object); } } } function onSelectStart(event) { preferredInputSource = event.inputSource; startDragging(event); } function onSelectEnd(event) { stopDragging(event); } ``` -------------------------------- ### Setup XR-Compatible WebGL Layer Source: https://context7.com/immersive-web/webxr/llms.txt Ensures the WebGL context is XR-compatible and sets up the XRWebGLLayer for rendering. Configure antialiasing, depth, stencil, and alpha buffers as needed. Adjust framebufferScaleFactor for performance. ```javascript let glCanvas = document.createElement("canvas"); let gl = glCanvas.getContext("webgl", { xrCompatible: true }); function setupWebGLLayer() { // Ensure WebGL context is compatible with XR device return gl.makeXRCompatible().then(() => { // Create and set the WebGL layer const glLayer = new XRWebGLLayer(xrSession, gl, { antialias: true, depth: true, stencil: false, alpha: true, framebufferScaleFactor: 1.0 // 1.0 = default, can adjust for performance }); xrSession.updateRenderState({ baseLayer: glLayer, depthNear: 0.1, depthFar: 1000.0 }); }); } ``` -------------------------------- ### WebXR Session Request Fallback Logic Source: https://github.com/immersive-web/webxr/blob/main/designdocs/session-creation.md Demonstrates a fallback mechanism for requesting different WebXR session types, starting with immersive AR and progressively trying other modes if the initial request fails. This example requires a `xrDevice` object and assumes `supportsSession()` and `requestSession()` methods are available. ```javascript // Prefer immersive AR. let sessionRequirements = {immersive: true, worldIntegration: true}; let sessionConfig = { foveated: true, planes: true, pixelData: true }; xrDevice.supportsSession(sessionRequirements).then( function() { // Display Enter (immersive) AR button. } ).catch( function(error) { // The first fallback is "inline AR" (aka smartphone AR). sessionRequirements = {mode: 'inline', worldIntegration: true}; sessionConfig = { planes: true, pixelData: true }; xrDevice.supportsSession(sessionRequirements).then( function() { // Display Start (inline) AR button. } ); } ).catch( function(error) { // There is a limited VR fallback, so try immersive VR. sessionRequirements = {immersive: true, worldIntegration: false}; sessionConfig = { foveated: true }; xrDevice.supportsSession(sessionRequirements).then( function() { // Display Enter VR button. } ); } ).catch( function(error) { // Finally, try "magic window" VR. sessionRequirements = {mode: 'inline', worldIntegration: false}; sessionConfig = { }; xrDevice.supportsSession(sessionRequirements).then( function() { // Request VR "magic window" session, which does not // (generally) require user activation. // Note: The application could also choose to do this in all cases. startXrSession(); } ); } ).catch( function(error) { // Display "Your client is unsupported." ); function startXrSession() { xrDevice.requestSession(sessionRequirements, sessionConfig); } function onXRButtonClicked() { startXrSession(); } ``` -------------------------------- ### Setup Native Scale WebGL Layer Source: https://context7.com/immersive-web/webxr/llms.txt Configures the XRWebGLLayer to render at the native resolution of the XR device using the `getNativeFramebufferScaleFactor` method. ```javascript // For native resolution rendering function setupNativeScaleWebGLLayer() { return gl.makeXRCompatible().then(() => { const nativeScaleFactor = XRWebGLLayer.getNativeFramebufferScaleFactor(xrSession); const glLayer = new XRWebGLLayer(xrSession, gl, { framebufferScaleFactor: nativeScaleFactor }); xrSession.updateRenderState({ baseLayer: glLayer }); }); } ``` -------------------------------- ### Start an Inline XR Session Source: https://context7.com/immersive-web/webxr/llms.txt Initiates an inline XR session, rendering content within a 2D webpage. Requires no user gesture. Requests 'local' tracking if available. ```javascript function beginInlineSession() { // Inline sessions don't require user gesture navigator.xr.requestSession('inline', { optionalFeatures: ['local'] // Request tracking if available }) .then((session) => { const glLayer = new XRWebGLLayer(session, gl); session.updateRenderState({ baseLayer: glLayer, inlineVerticalFieldOfView: 0.5 * Math.PI // 90 degrees }); onSessionStarted(session); }) .catch((reason) => { console.log("Inline session failed:", reason); }); } ``` -------------------------------- ### Query Input Poses for Targeting and Rendering Source: https://context7.com/immersive-web/webxr/llms.txt Iterate through input sources to get targeting ray and grip poses. Updates cursor, pointing ray, highlights, and controller models. ```javascript function updateInputs(xrFrame) { for (const inputSource of xrInputSources) { // Get targeting ray pose (for pointing/aiming) const targetRayPose = xrFrame.getPose(inputSource.targetRaySpace, xrReferenceSpace); if (targetRayPose) { // Perform virtual hit test const hitResult = scene.virtualHitTest(targetRayPose.transform); // Update cursor position if (hitResult && inputSource.targetRayMode !== 'screen') { scene.cursor.visible = true; scene.cursor.setTransform(hitResult.transform); } else { scene.cursor.visible = false; } // Update pointing ray for tracked pointers if (inputSource.targetRayMode === 'tracked-pointer') { scene.pointingRay.visible = true; scene.pointingRay.setTransform(targetRayPose.transform); scene.pointingRay.length = hitResult ? distance(targetRayPose.transform, hitResult.transform) : DEFAULT_RAY_LENGTH; } // Update highlight on targeted objects if (hitResult && hitResult.objectHit) { scene.setHighlight(hitResult.objectHit); } else { scene.clearHighlight(); } } // Get grip pose (for rendering controller models) if (inputSource.gripSpace) { const gripPose = xrFrame.getPose(inputSource.gripSpace, xrReferenceSpace); if (gripPose && xrSession.environmentBlendMode === 'opaque') { // Render controller model at grip position const model = getControllerModel(inputSource); if (model) { model.setTransform(gripPose.transform); model.visible = true; } } } // Check for emulated position (tracking loss) if (targetRayPose && targetRayPose.emulatedPosition) { console.log("Controller position is estimated (tracking lost)"); } } } // Load appropriate controller model based on profiles function getControllerModel(inputSource) { // profiles array lists device identifiers in order of preference // e.g., ["samsung-odyssey", "microsoft-mixed-reality", "generic-trigger-squeeze-touchpad-thumbstick"] for (const profile of inputSource.profiles) { const model = loadModel(profile, inputSource.handedness); if (model) return model; } return loadGenericControllerModel(); } ``` -------------------------------- ### WebVR: Get Controller Pose and Hand Source: https://github.com/immersive-web/webxr/blob/main/webvr-migration.md Use navigator.getGamepads() to loop through controllers. Check for a non-null gamepad, displayId, and pose to access controller position, orientation, and hand. This is for the older WebVR API. ```javascript function onFrame (t) { // Queue a request for the next frame to keep the animation loop going. vrDisplay.requestAnimationFrame(onFrame); // Loop through all gamepads and identify the ones that are associated with // the vrDisplay. let gamepads = navigator.getGamepads(); for (let i = 0; i < gamepads.length; ++i) { let gamepad = gamepads[i]; // The array may contain undefined gamepads, so check for that as // well as a non-null pose. if (gamepad && gamepad.displayId && gamepad.pose) { scene.showControllerAtTransform(gamepad.pose.position, gamepad.pose.orientation, gamepad.hand); } } // Handle rendering as shown above... } ``` -------------------------------- ### Requesting XR Session with Required Features Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Initiates an immersive VR session and requires the 'unbounded' feature. If the 'unbounded' feature is not supported, the session request will be rejected, preventing the experience from starting without essential capabilities. This is suitable for experiences that critically depend on unbounded tracking. ```javascript let xrSession = null; let xrReferenceSpace = null; function beginXRSession() { navigator.xr.requestSession('immersive-vr', { requiredFeatures: ['unbounded'] }) .then(onSessionStarted) .catch(err => { // Display message to the user explaining that the experience could not // be started. }); } ``` -------------------------------- ### XRSessionInit Dictionary Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Configuration options for initializing an XR session. ```APIDOC ## XRSessionInit Dictionary ### Description Defines initialization parameters for an XR session. ### Fields - **requiredFeatures** (sequence) - An array of feature strings that must be supported. - **optionalFeatures** (sequence) - An array of feature strings that are optionally supported. ``` -------------------------------- ### Get active input sources Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md Access the `inputSources` attribute on an `XRSession` to get a list of all active `XRInputSource` objects. Properties of these objects are immutable. ```javascript let inputSources = xrSession.inputSources; ``` -------------------------------- ### XRWebGLLayerInit Dictionary Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Initialization options for an XRWebGLLayer. ```APIDOC ## XRWebGLLayerInit Dictionary ### Description Configuration options for creating an XRWebGLLayer. ### Fields - **antialias** (boolean) - Whether to use antialiasing (default: true). - **depth** (boolean) - Whether to enable depth buffer (default: true). - **stencil** (boolean) - Whether to enable stencil buffer (default: false). - **alpha** (boolean) - Whether the layer's color buffer has an alpha channel (default: true). - **ignoreDepthValues** (boolean) - Whether to ignore depth values (default: false). - **framebufferScaleFactor** (double) - Scale factor for the framebuffer size (default: 1.0). ``` -------------------------------- ### WebXR: Get Input Source Pose Source: https://github.com/immersive-web/webxr/blob/main/webvr-migration.md In WebXR, use xrSession.inputSources to get XRInputSource objects. Pass the targetRaySpace or gripSpace and a tracking space to xrFrame.getPose() to retrieve the XRPose. ```javascript function onFrame(t, frame) { ``` -------------------------------- ### Get Viewer Pose with XRFrame Source: https://github.com/immersive-web/webxr/blob/main/privacy-security-explainer.md Call `XRFrame.getViewerPose()` to retrieve `XRViewerPose` data. This method is used when `XRViewerPose` is needed instead of `XRPose`. ```javascript function onSessionRafCallback(XRFrame frame) { let viewerPose = frame.getViewerPose(xrReferenceSpace); } ``` -------------------------------- ### Handle XR Frame and Input Sources Source: https://github.com/immersive-web/webxr/blob/main/webvr-migration.md This snippet shows how to queue a request for the next XR frame and iterate through input sources to display controllers if they have a grip space. ```javascript xrSession.requestAnimationFrame(onXRFrame); // Loop through all input sources. for (let inputSource of xrSession.inputSources) { // Show the input source if it has a grip space if (inputSource.gripSpace) { let inputPose = frame.getPose(inputSource.gripSpace, xrReferenceSpace); scene.showControllerAtTransform(inputPose.position, inputPose.orientation, inputSource.handedness); } } ``` -------------------------------- ### XRSessionEventInit Dictionary Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Initialization options for XRSessionEvent. ```APIDOC ## XRSessionEventInit Dictionary ### Description Provides initialization parameters for `XRSessionEvent`. ### Fields - **session** (XRSession) - Required. The XR session associated with the event. ``` -------------------------------- ### XRReferenceSpace Interface Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Represents a reference coordinate system for XR. It provides methods to get an offset reference space and to handle reset events. ```webidl [SecureContext, Exposed=Window] interface XRReferenceSpace : XRSpace { XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset); attribute EventHandler onreset; }; ``` -------------------------------- ### Requesting WebXR Reference Spaces Source: https://context7.com/immersive-web/webxr/llms.txt Demonstrates how to request different reference spaces for various XR experience types. Use 'viewer' for inline previews, 'local' for seated experiences, 'local-floor' for standing experiences, 'bounded-floor' for room-scale with boundaries, and 'unbounded' for large-scale tracking. ```javascript // Viewer reference space - origin at viewer, no room tracking // Use for: inline previews, click-and-drag viewing xrSession.requestReferenceSpace('viewer').then((space) => { xrViewerSpace = space; }); // Local reference space - eye-level origin, seated experiences // Use for: video viewers, racing simulators, cockpit experiences xrSession.requestReferenceSpace('local').then((space) => { xrLocalSpace = space; }); // Local-floor reference space - floor-level origin, standing experiences // Use for: VR chat rooms, standing action games xrSession.requestReferenceSpace('local-floor').then((space) => { xrFloorSpace = space; }); // Bounded-floor reference space - room-scale with defined boundaries // Use for: VR painting, training simulators, dance games xrSession.requestReferenceSpace('bounded-floor').then((space) => { xrBoundedSpace = space; // Access play area boundaries const bounds = space.boundsGeometry; // Array of DOMPointReadOnly createBoundsMesh(bounds); }); // Unbounded reference space - large-scale tracking, world-scale AR // Use for: campus tours, renovation previews, location-based AR xrSession.requestReferenceSpace('unbounded').then((space) => { xrUnboundedSpace = space; }); // Progressive enhancement pattern xrSession.requestReferenceSpace('bounded-floor') .catch(() => xrSession.requestReferenceSpace('local-floor')) .catch(() => xrSession.requestReferenceSpace('local')) .then((referenceSpace) => { xrReferenceSpace = referenceSpace; console.log("Using reference space type:", referenceSpace); }); ``` -------------------------------- ### XRFrame Get Pose Method Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Adds the getPose method to the XRFrame interface. This method retrieves the XRPose for a given XRSpace relative to another XRSpace. ```webidl partial interface XRFrame { XRPose? getPose(XRSpace space, XRSpace relativeTo); }; ``` -------------------------------- ### Get targeting ray pose Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md Use `XRFrame.getPose()` with the `inputSource.targetRaySpace` and an `XRReferenceSpace` to determine the targeting ray's pose. Always verify the result as it can be null. ```javascript let inputSourcePose = xrFrame.getPose(inputSource.targetRaySpace, xrReferenceSpace); if (inputSourcePose) { // do something with the result } ``` -------------------------------- ### Request WebXR Session and Set Base Layer Source: https://github.com/immersive-web/webxr/blob/main/webvr-migration.md Request an immersive VR session and create an `XRWebGLLayer` using the session and the compatible WebGL context. Then, update the session's render state with this layer as the `baseLayer`. ```javascript let xrSession = await navigator.xr.requestSession('immersive-vr'); let xrLayer = new XRWebGLLayer(session, gl); session.updateRenderState({ baseLayer: xrLayer }); ``` -------------------------------- ### Calculating Distance from Viewer Pose Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md This snippet shows how to get the pose of an input source relative to the viewer reference space to calculate its distance from the user's head. ```javascript let pose = xrFrame.getPose(preferredInputSource.gripSpace, xrViewerReferenceSpace); if (pose) { // Calculate how far the motion controller is from the user's head } ``` -------------------------------- ### XRSession Creation Options Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Extends XRSessionCreationOptions to include a required reference space type. This must be specified when creating an XR session. ```webidl partial dictionary XRSessionCreationOptions { XRReferenceSpaceType requiredReferenceSpaceType; }; ``` -------------------------------- ### XRSessionCreationOptions Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Defines options for creating an XR session, including the required reference space type. ```APIDOC ## XRSessionCreationOptions ### Description Partial dictionary for `XRSessionCreationOptions` to specify the required reference space type when creating an XR session. ### Parameters #### Request Body - **requiredReferenceSpaceType** (XRReferenceSpaceType) - Required - The type of XR reference space that is required for the session. ``` -------------------------------- ### WebXR Session Method Signatures Source: https://github.com/immersive-web/webxr/blob/main/designdocs/session-creation.md Illustrates the parameter types for supportsSession() and requestSession(). supportsSession() takes required options, while requestSession() takes required options and requested configuration. ```javascript supportsSession(XRSessionRequiredOptions requiredOptions); requestSession(XRSessionRequiredOptions requiredOptions, XRSessionConfiguration requestedConfiguration); ``` -------------------------------- ### Load Renderable Input Models Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md Iterates through `XRInputSource` profiles to find and load a corresponding renderable 3D model. Falls back to a default model if no match is found. ```javascript function loadRenderableInputModels(xrInputSource) { for (let profile of xrInputSource.profiles) { // Retrieve a mesh to render based on the gamepad object's profile and handedness let renderableModel = getInputSourceRenderableModel(profile, xrInputSource.handedness); if (renderableModel) { // Add the model to the imaginary 3D engine's scene. scene.inputObjects.add(renderableModel, xrInputSource); return; } } // If the profiles list was empty or a corresponding model could not be found // for any entry in it the application could respond by not rendering the // device at all or rendering a generic device that is not intended to be a // visual match. This sample chooses the latter approach. scene.inputObjects.add(getDefaultInputSourceRenderableModel(), xrInputSource); } ``` -------------------------------- ### Update Preferred Input Source on Select Start Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md Update the preferred input source to the one the user most recently interacted with when a 'selectstart' event occurs. This helps in prioritizing user input. ```js // Keep track of the preferred input source var preferredInputSource = null; function onSelectStart(event) { // Update the preferred input source to be the last one the user interacted with preferredInputSource = event.inputSource; } ``` -------------------------------- ### XRRenderStateInit Dictionary Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Initialization options for the XR render state. ```APIDOC ## XRRenderStateInit Dictionary ### Description Defines parameters for initializing or updating the XR render state. ### Fields - **depthNear** (double) - The near clipping plane distance. - **depthFar** (double) - The far clipping plane distance. - **inlineVerticalFieldOfView** (double?) - The vertical field of view for inline sessions. - **baseLayer** (XRWebGLLayer?) - The base rendering layer. ``` -------------------------------- ### Requesting XR Session with Optional Features Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Initiates an immersive VR session and requests the 'bounded-floor' feature. Includes fallback logic to request a 'local' reference space if 'bounded-floor' is unavailable. This is useful for experiences that can adapt to different tracking capabilities. ```javascript let xrSession = null; let xrReferenceSpace = null; function onButtonClick() { navigator.xr.requestSession('immersive-vr', { optionalFeatures: ['bounded-floor'] }) .then(onSessionStarted) .catch(err => { window.requestAnimationFrame(onDrawFrame); }); } function onSessionStarted(session) { xrSession = session; // First request an bounded-floor frame of reference. xrSession.requestReferenceSpace('bounded-floor').then((referenceSpace) => { xrReferenceSpace = referenceSpace; }).catch(() => { // If a bounded-floor reference space isn't available, request a local // reference space as a fallback and adjust the experience as necessary. return xrSession.requestReferenceSpace('local').then((referenceSpace) => { xrReferenceSpace = referenceSpace; }); }) .then(setupWebGLLayer) .then(() => { xrSession.requestAnimationFrame(onDrawFrame); }); } ``` -------------------------------- ### Compute Preferred Input Source on Input Sources Change Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md When the available input sources change, re-compute the preferred input source. This function should implement logic to prioritize input sources, for example, by 'targetRayMode'. ```js function onInputSourcesChanged(event) { xrInputSources = event.session.inputSources; // Choose an appropriate default from available inputSources, such as // prioritizing based on the value of targetRayMode: 'screen' over // 'tracked-pointer' over 'gaze'. preferredInputSource = computePreferredInputSource(); } ``` -------------------------------- ### Apply Recommended Viewport Scale in WebXR Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Use `view.recommendedViewportScale` to apply the user agent's suggested viewport scale. This is useful for applying heuristics only when they exist. ```javascript view.requestViewportScale(view.recommendedViewportScale); ``` -------------------------------- ### Request Inline Session with Local Feature Source: https://github.com/immersive-web/webxr/blob/main/privacy-security-explainer.md Use this when creating an inline WebXR session to indicate the desire for 'local' viewer tracking. This must be added to `XRSessionInit.optionalFeatures`. ```javascript xr.requestSession('inline', { optionalFeatures: ['local'] } ) .then(onInlineSessionCreated); ``` -------------------------------- ### Getting Pose Relative to a Reference Space Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md This code demonstrates how to use `XRFrame.getPose()` to determine the spatial relationship (pose) between two `XRSpace` objects. The `baseSpace` parameter defines the coordinate system for the returned pose. ```javascript let pose = xrFrame.getPose(xrSpace, xrReferenceSpace); if (pose) { // Do a thing } ``` -------------------------------- ### Get XRPose Data Source: https://github.com/immersive-web/webxr/blob/main/privacy-security-explainer.md Retrieves pose data for a given input source within an XR frame. This is typically called within a requestAnimationFrame callback. Ensure user consent and document visibility before calling. ```javascript function onSessionRafCallback(XRFrame frame) { let motionControllerPose = frame.getPose(xrSession.inputSources[0], xrReferenceSpace); } ``` -------------------------------- ### Requesting 'local-floor' Reference Space in WebXR Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Initiates a WebXR session and requests the 'local-floor' reference space, ideal for experiences anchored to the floor. It proceeds to set up the WebGL layer and request animation frames. ```javascript let xrSession = null; let xrReferenceSpace = null; function onSessionStarted(session) { xrSession = session; xrSession.requestReferenceSpace('local-floor') .then((referenceSpace) => { xrReferenceSpace = referenceSpace; }) .then(setupWebGLLayer) .then(() => { xrSession.requestAnimationFrame(onDrawFrame); }); } ``` -------------------------------- ### Get View Matrix for WebGL Shaders Source: https://github.com/immersive-web/webxr/blob/main/explainer.md This snippet demonstrates how to obtain a view matrix and projection matrix suitable for direct use with WebGL shaders. It utilizes the `inverse` attribute of the `XRRigidTransform` for the view matrix. Ensure your shaders are set up to accept these matrices. ```javascript // Get a view matrix and projection matrix appropriate for passing directly to a WebGL shader. function drawScene(view) { viewMatrix = view.transform.inverse.matrix; projectionMatrix = view.projectionMatrix; // Set uniforms as appropriate for shaders being used // Draw Scene } ``` -------------------------------- ### Requesting 'local' Reference Space in WebXR Source: https://github.com/immersive-web/webxr/blob/main/spatial-tracking-explainer.md Initiates a WebXR session and requests the 'local' reference space, suitable for eye-level experiences. It then sets up the WebGL layer and requests animation frames. ```javascript let xrSession = null; let xrReferenceSpace = null; function onSessionStarted(session) { xrSession = session; xrSession.requestReferenceSpace('local') .then((referenceSpace) => { xrReferenceSpace = referenceSpace; }) .then(setupWebGLLayer) .then(() => { xrSession.requestAnimationFrame(onDrawFrame); }); } ``` -------------------------------- ### Request and Manage Immersive VR Session Source: https://context7.com/immersive-web/webxr/llms.txt Requests an immersive VR session with specified features and handles session lifecycle events. This function must be called from a user gesture. It sets up the WebGL layer and starts the render loop upon successful session initiation. ```javascript let xrSession = null; let xrReferenceSpace = null; let gl = null; function beginXRSession() { navigator.xr.requestSession('immersive-vr', { requiredFeatures: ['local-floor'], optionalFeatures: ['bounded-floor', 'hand-tracking'] }) .then(onSessionStarted) .catch(err => { console.error("Failed to start XR session:", err); window.requestAnimationFrame(onDrawFrame); }); } function onSessionStarted(session) { xrSession = session; xrSession.addEventListener('end', onSessionEnd); xrSession.addEventListener('visibilitychange', onVisibilityChange); xrSession.requestReferenceSpace('local-floor') .then((referenceSpace) => { xrReferenceSpace = referenceSpace; }) .then(setupWebGLLayer) .then(() => { xrSession.requestAnimationFrame(onDrawFrame); }); } function onVisibilityChange(event) { switch (event.session.visibilityState) { case 'visible': resumeMedia(); break; case 'visible-blurred': pauseMedia(); break; case 'hidden': pauseMedia(); break; } } function endXRSession() { if (xrSession) { xrSession.end().then(onSessionEnd); } } function onSessionEnd() { gl.bindFramebuffer(gl.FRAMEBUFFER, null); xrSession = null; window.requestAnimationFrame(onDrawFrame); } ``` -------------------------------- ### Positional Audio Sample in WebXR Samples Source: https://github.com/immersive-web/webxr/blob/main/accessibility-considerations-explainer.md This sample demonstrates one method of integrating WebXR positional data with WebAudio for spatial audio. It is located in the WebXR Samples repository. ```html Positional Audio Sample ``` -------------------------------- ### Update Scene with XR Frame Data Source: https://github.com/immersive-web/webxr/blob/main/input-explainer.md This function updates the scene by getting the pose of the input source's target ray space and performing a virtual hit test. It then updates the cursor, highlight, renderable models, and pointing ray based on the results. Use this within your XR session's animation loop. ```javascript function updateScene(timestamp, xrFrame) { // Scene update logic ... // Use the previously determined preferredInputSource to hit test with let inputSourcePose = xrFrame.getPose(preferredInputSource.targetRaySpace, xrReferenceSpace); if (inputSourcePose) { // Invoke the example 3D engine to compute a virtual hit test var virtualHitTestResult = scene.virtualHitTest(inputSourcePose.transform); } updateCursor(virtualHitTestResult); updateHighlight(virtualHitTestResult); updateRenderableInputModels(xrFrame); updatePointingRay(inputSourcePose, virtualHitTestResult); // Other scene update logic ... } ``` -------------------------------- ### Request Inline Session with Bounded Floor Source: https://github.com/immersive-web/webxr/blob/main/privacy-security-explainer.md Use this to request an inline WebXR session that supports bounded floor tracking. This is useful for experiences that do not require full immersion but benefit from spatial awareness. ```javascript xr.requestSession('inline', { optionalFeatures: ['bounded-floor'] } ) .then(onInlineSessionCreated); } ``` -------------------------------- ### WebGLRenderingContextBase Interface Extension Source: https://github.com/immersive-web/webxr/blob/main/explainer.md Extension to WebGLRenderingContextBase for making a context XR compatible. ```APIDOC ## WebGLRenderingContextBase Interface Extension ### Description Provides a method to make an existing WebGL context compatible with XR. ### Interface WebGLRenderingContextBase ### Methods - **makeXRCompatible()**: Promise - Makes the WebGL context compatible with XR. ```