xrblocks 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,7 @@ export declare class GeminiManager extends xb.Script<GeminiManagerEventMap> {
26
26
  currentInputText: string;
27
27
  currentOutputText: string;
28
28
  tools: xb.Tool[];
29
+ scheduleAheadTime: number;
29
30
  constructor();
30
31
  init(): void;
31
32
  startGeminiLive({ liveParams, model, }?: {
@@ -1,6 +1,7 @@
1
1
  import * as xb from 'xrblocks';
2
2
  import { AUDIO_CAPTURE_PROCESSOR_CODE } from './AudioCaptureProcessorCode.js';
3
3
 
4
+ const DEFAULT_SCHEDULE_AHEAD_TIME = 1.0;
4
5
  class GeminiManager extends xb.Script {
5
6
  constructor() {
6
7
  super();
@@ -19,6 +20,7 @@ class GeminiManager extends xb.Script {
19
20
  this.currentInputText = '';
20
21
  this.currentOutputText = '';
21
22
  this.tools = [];
23
+ this.scheduleAheadTime = DEFAULT_SCHEDULE_AHEAD_TIME;
22
24
  }
23
25
  init() {
24
26
  this.xrDeviceCamera = xb.core.deviceCamera;
@@ -191,10 +193,9 @@ class GeminiManager extends xb.Script {
191
193
  }
192
194
  }
193
195
  scheduleAudioBuffers() {
194
- const SCHEDULE_AHEAD_TIME = 0.2;
195
196
  while (this.audioQueue.length > 0 &&
196
197
  this.nextAudioStartTime <=
197
- this.audioContext.currentTime + SCHEDULE_AHEAD_TIME) {
198
+ this.audioContext.currentTime + this.scheduleAheadTime) {
198
199
  const audioBuffer = this.audioQueue.shift();
199
200
  const source = this.audioContext.createBufferSource();
200
201
  source.buffer = audioBuffer;
@@ -95,6 +95,7 @@ export declare class Options {
95
95
  * Whether to use post-processing effects.
96
96
  */
97
97
  usePostprocessing: boolean;
98
+ enableSimulator: boolean;
98
99
  /**
99
100
  * Configuration for the XR session button.
100
101
  */
@@ -104,10 +105,8 @@ export declare class Options {
104
105
  endText: string;
105
106
  invalidText: string;
106
107
  startSimulatorText: string;
107
- enableSimulator: boolean;
108
- showSimulatorButtonOnMobile: boolean;
109
- autostartSimulatorOnDesktop: boolean;
110
- autostartSimulator: boolean;
108
+ showEnterSimulatorButton: boolean;
109
+ alwaysAutostartSimulator: boolean;
111
110
  };
112
111
  /**
113
112
  * Constructs the Options object by merging default values with provided
@@ -34,6 +34,7 @@ export declare class WebXRSessionManager extends THREE.EventDispatcher<WebXRSess
34
34
  private sessionOptions?;
35
35
  private onSessionEndedBound;
36
36
  private xrModeSupported?;
37
+ private waitingForXRSession;
37
38
  constructor(renderer: THREE.WebGLRenderer, sessionInit: XRSessionInit, mode: XRSessionMode);
38
39
  /**
39
40
  * Checks for WebXR support and availability of the requested session mode.
@@ -9,7 +9,7 @@ export declare class XRButton {
9
9
  domElement: HTMLDivElement;
10
10
  simulatorButtonElement: HTMLButtonElement;
11
11
  xrButtonElement: HTMLButtonElement;
12
- constructor(sessionManager: WebXRSessionManager, startText?: string, endText?: string, invalidText?: string, startSimulatorText?: string, enableSimulator?: boolean, showSimulatorButtonOnMobile?: boolean, startSimulator?: () => void);
12
+ constructor(sessionManager: WebXRSessionManager, startText?: string, endText?: string, invalidText?: string, startSimulatorText?: string, showEnterSimulatorButton?: boolean, startSimulator?: () => void);
13
13
  private createSimulatorButton;
14
14
  private createXRButtonElement;
15
15
  private onSessionReady;
@@ -57,7 +57,7 @@ export declare class Depth {
57
57
  updateCPUDepthData(depthData: XRCPUDepthInformation, view_id?: number): void;
58
58
  updateGPUDepthData(depthData: XRWebGLDepthInformation, view_id?: number): void;
59
59
  getTexture(view_id: number): THREE.DataTexture | THREE.ExternalTexture | undefined;
60
- update(frame: XRFrame): void;
60
+ update(frame?: XRFrame): void;
61
61
  updateLocalDepth(frame: XRFrame): void;
62
62
  renderOcclusionPass(): void;
63
63
  debugLog(): void;
@@ -14,6 +14,7 @@ export declare class AudioPlayer extends Script {
14
14
  private categoryVolumes?;
15
15
  private volume;
16
16
  private category;
17
+ scheduleAheadTime: number;
17
18
  constructor(options?: AudioPlayerOptions);
18
19
  /**
19
20
  * Sets the CategoryVolumes instance for this player to respect
@@ -99,7 +99,6 @@ export * from './ui/layouts/SpatialPanel';
99
99
  export * from './ui/layouts/TextScrollerState';
100
100
  export * from './ui/layouts/VerticalPager';
101
101
  export * from './ui/UI';
102
- export * from './utils/BrowserUtils';
103
102
  export * from './utils/DependencyInjection';
104
103
  export * from './utils/HelperConstants';
105
104
  export * from './utils/Keycodes';
package/build/xrblocks.js CHANGED
@@ -14,9 +14,9 @@
14
14
  * limitations under the License.
15
15
  *
16
16
  * @file xrblocks.js
17
- * @version v0.3.0
18
- * @commitid c7b519d
19
- * @builddate 2025-11-04T00:07:30.989Z
17
+ * @version v0.4.0
18
+ * @commitid 385db96
19
+ * @builddate 2025-11-20T21:08:04.032Z
20
20
  * @description XR Blocks SDK, built from source with the above commit ID.
21
21
  * @agent When using with Gemini to create XR apps, use **Gemini Canvas** mode,
22
22
  * and follow rules below:
@@ -1890,10 +1890,6 @@ const xrDeviceCameraUserContinuousOptions = deepFreeze(new DeviceCameraOptions({
1890
1890
  willCaptureFrequently: true,
1891
1891
  }));
1892
1892
 
1893
- function onDesktopUserAgent() {
1894
- return !/Mobi|Android|iPhone/i.test(navigator.userAgent);
1895
- }
1896
-
1897
1893
  const DepthMeshTexturedShader = {
1898
1894
  vertexShader: /* glsl */ `
1899
1895
  varying vec3 vNormal;
@@ -3212,22 +3208,19 @@ class Depth {
3212
3208
  update(frame) {
3213
3209
  if (!this.options.enabled)
3214
3210
  return;
3215
- this.updateLocalDepth(frame);
3211
+ if (frame) {
3212
+ this.updateLocalDepth(frame);
3213
+ }
3216
3214
  if (this.options.occlusion.enabled) {
3217
3215
  this.renderOcclusionPass();
3218
3216
  }
3219
3217
  }
3220
3218
  updateLocalDepth(frame) {
3221
- if (onDesktopUserAgent()) {
3222
- return;
3223
- }
3224
3219
  const leftCamera = this.renderer.xr?.getCamera?.()?.cameras?.[0];
3225
3220
  if (leftCamera && this.depthMesh && this.depthMesh.parent != leftCamera) {
3226
3221
  leftCamera.add(this.depthMesh);
3227
3222
  this.scene.add(leftCamera);
3228
3223
  }
3229
- if (!frame)
3230
- return;
3231
3224
  const session = frame.session;
3232
3225
  const binding = this.renderer.xr.getBinding();
3233
3226
  // Enable or disable depth based on the number of clients.
@@ -4291,6 +4284,7 @@ class WebXRSessionManager extends THREE.EventDispatcher {
4291
4284
  this.sessionInit = sessionInit;
4292
4285
  this.mode = mode;
4293
4286
  this.onSessionEndedBound = this.onSessionEndedInternal.bind(this);
4287
+ this.waitingForXRSession = false;
4294
4288
  }
4295
4289
  /**
4296
4290
  * Checks for WebXR support and availability of the requested session mode.
@@ -4357,8 +4351,15 @@ class WebXRSessionManager extends THREE.EventDispatcher {
4357
4351
  else if (this.currentSession) {
4358
4352
  throw new Error('Session already started');
4359
4353
  }
4354
+ else if (this.waitingForXRSession) {
4355
+ throw new Error('Waiting for session to start');
4356
+ }
4357
+ this.waitingForXRSession = true;
4360
4358
  navigator
4361
4359
  .xr.requestSession(this.mode, this.sessionOptions)
4360
+ .finally(() => {
4361
+ this.waitingForXRSession = false;
4362
+ })
4362
4363
  .then(this.onSessionStartedInternal.bind(this));
4363
4364
  }
4364
4365
  /**
@@ -4401,7 +4402,7 @@ class WebXRSessionManager extends THREE.EventDispatcher {
4401
4402
  const XRBUTTON_WRAPPER_ID = 'XRButtonWrapper';
4402
4403
  const XRBUTTON_CLASS = 'XRButton';
4403
4404
  class XRButton {
4404
- constructor(sessionManager, startText = 'ENTER XR', endText = 'END XR', invalidText = 'XR NOT SUPPORTED', startSimulatorText = 'START SIMULATOR', enableSimulator = false, showSimulatorButtonOnMobile = false, startSimulator = () => { }) {
4405
+ constructor(sessionManager, startText = 'ENTER XR', endText = 'END XR', invalidText = 'XR NOT SUPPORTED', startSimulatorText = 'START SIMULATOR', showEnterSimulatorButton = false, startSimulator = () => { }) {
4405
4406
  this.sessionManager = sessionManager;
4406
4407
  this.startText = startText;
4407
4408
  this.endText = endText;
@@ -4413,8 +4414,7 @@ class XRButton {
4413
4414
  this.xrButtonElement = document.createElement('button');
4414
4415
  this.domElement.id = XRBUTTON_WRAPPER_ID;
4415
4416
  this.createXRButtonElement();
4416
- if (enableSimulator &&
4417
- (onDesktopUserAgent() || showSimulatorButtonOnMobile)) {
4417
+ if (showEnterSimulatorButton) {
4418
4418
  this.createSimulatorButton();
4419
4419
  }
4420
4420
  this.sessionManager.addEventListener(WebXRSessionEventType.UNSUPPORTED, this.showXRNotSupported.bind(this));
@@ -7422,6 +7422,7 @@ class Options {
7422
7422
  * Whether to use post-processing effects.
7423
7423
  */
7424
7424
  this.usePostprocessing = false;
7425
+ this.enableSimulator = true;
7425
7426
  /**
7426
7427
  * Configuration for the XR session button.
7427
7428
  */
@@ -7431,11 +7432,9 @@ class Options {
7431
7432
  endText: 'Exit XR',
7432
7433
  invalidText: 'XR Not Supported',
7433
7434
  startSimulatorText: 'Enter Simulator',
7434
- enableSimulator: true,
7435
- showSimulatorButtonOnMobile: false,
7436
- autostartSimulatorOnDesktop: true,
7437
- // Whether to always autostart the simulator.
7438
- autostartSimulator: false,
7435
+ showEnterSimulatorButton: false,
7436
+ // Whether to autostart the simulator even if WebXR is available.
7437
+ alwaysAutostartSimulator: false,
7439
7438
  };
7440
7439
  deepMerge(this, options);
7441
7440
  }
@@ -10269,6 +10268,7 @@ class AudioListener extends Script {
10269
10268
  }
10270
10269
  }
10271
10270
 
10271
+ const DEFAULT_SCHEDULE_AHEAD_TIME = 1.0;
10272
10272
  class AudioPlayer extends Script {
10273
10273
  constructor(options = {}) {
10274
10274
  super();
@@ -10277,6 +10277,7 @@ class AudioPlayer extends Script {
10277
10277
  this.nextStartTime = 0;
10278
10278
  this.volume = 1.0;
10279
10279
  this.category = 'speech';
10280
+ this.scheduleAheadTime = DEFAULT_SCHEDULE_AHEAD_TIME;
10280
10281
  this.options = { sampleRate: 24000, channelCount: 1, ...options };
10281
10282
  if (options.category) {
10282
10283
  this.category = options.category;
@@ -10341,9 +10342,9 @@ class AudioPlayer extends Script {
10341
10342
  this.scheduleAudioBuffers();
10342
10343
  }
10343
10344
  scheduleAudioBuffers() {
10344
- const SCHEDULE_AHEAD_TIME = 0.2;
10345
10345
  while (this.audioQueue.length > 0 &&
10346
- this.nextStartTime <= this.audioContext.currentTime + SCHEDULE_AHEAD_TIME) {
10346
+ this.nextStartTime <=
10347
+ this.audioContext.currentTime + this.scheduleAheadTime) {
10347
10348
  const audioBuffer = this.audioQueue.shift();
10348
10349
  const currentTime = this.audioContext.currentTime;
10349
10350
  const startTime = Math.max(this.nextStartTime, currentTime);
@@ -14597,14 +14598,17 @@ class Core {
14597
14598
  this.webXRSessionManager.addEventListener(WebXRSessionEventType.SESSION_START, (event) => this.onXRSessionStarted(event.session));
14598
14599
  this.webXRSessionManager.addEventListener(WebXRSessionEventType.SESSION_END, this.onXRSessionEnded.bind(this));
14599
14600
  // Sets up xrButton.
14600
- const shouldAutostartSimulator = this.options.xrButton.autostartSimulator ||
14601
- (this.options.xrButton.autostartSimulatorOnDesktop &&
14602
- this.options.xrButton.enableSimulator &&
14603
- onDesktopUserAgent());
14601
+ let shouldAutostartSimulator = this.options.xrButton.alwaysAutostartSimulator;
14604
14602
  if (!shouldAutostartSimulator && options.xrButton.enabled) {
14605
- this.xrButton = new XRButton(this.webXRSessionManager, options.xrButton?.startText, options.xrButton?.endText, options.xrButton?.invalidText, options.xrButton?.startSimulatorText, options.xrButton?.enableSimulator, options.xrButton?.showSimulatorButtonOnMobile, this.startSimulator.bind(this));
14603
+ this.xrButton = new XRButton(this.webXRSessionManager, options.xrButton?.startText, options.xrButton?.endText, options.xrButton?.invalidText, options.xrButton?.startSimulatorText, options.xrButton?.showEnterSimulatorButton, this.startSimulator.bind(this));
14606
14604
  document.body.appendChild(this.xrButton.domElement);
14607
14605
  }
14606
+ this.webXRSessionManager.addEventListener(WebXRSessionEventType.UNSUPPORTED, () => {
14607
+ if (this.options.enableSimulator) {
14608
+ this.xrButton?.domElement.remove();
14609
+ shouldAutostartSimulator = true;
14610
+ }
14611
+ });
14608
14612
  await this.webXRSessionManager.initialize();
14609
14613
  // Sets up postprocessing effects.
14610
14614
  if (options.usePostprocessing) {
@@ -14723,7 +14727,6 @@ class Core {
14723
14727
  * scripts.
14724
14728
  */
14725
14729
  onXRSessionEnded() {
14726
- this.startSimulator();
14727
14730
  this.scriptsManager.onXRSessionEnded();
14728
14731
  }
14729
14732
  /**
@@ -16825,5 +16828,5 @@ class VideoFileStream extends VideoStream {
16825
16828
  }
16826
16829
  }
16827
16830
 
16828
- export { AI, AIOptions, AVERAGE_IPD_METERS, ActiveControllers, Agent, AnimatableNumber, AudioListener, AudioPlayer, BACK, BackgroundMusic, CategoryVolumes, Col, Core, CoreSound, DEFAULT_DEVICE_CAMERA_HEIGHT, DEFAULT_DEVICE_CAMERA_WIDTH, DOWN, Depth, DepthMesh, DepthMeshOptions, DepthOptions, DepthTextures, DetectedObject, DetectedPlane, DeviceCameraOptions, DragManager, DragMode, ExitButton, FORWARD, FreestandingSlider, GazeController, Gemini, GeminiOptions, GenerateSkyboxTool, GestureRecognition, GestureRecognitionOptions, GetWeatherTool, Grid, HAND_BONE_IDX_CONNECTION_MAP, HAND_JOINT_COUNT, HAND_JOINT_IDX_CONNECTION_MAP, HAND_JOINT_NAMES, Handedness, Hands, HandsOptions, HorizontalPager, IconButton, IconView, ImageView, Input, InputOptions, Keycodes, LEFT, LEFT_VIEW_ONLY_LAYER, LabelView, Lighting, LightingOptions, LoadingSpinnerManager, MaterialSymbolsView, MeshScript, ModelLoader, ModelViewer, MouseController, NEXT_SIMULATOR_MODE, NUM_HANDS, OCCLUDABLE_ITEMS_LAYER, ObjectDetector, ObjectsOptions, OcclusionPass, OcclusionUtils, OpenAI, OpenAIOptions, Options, PageIndicator, Pager, PagerState, Panel, PanelMesh, Physics, PhysicsOptions, PinchOnButtonAction, PlaneDetector, PlanesOptions, RIGHT, RIGHT_VIEW_ONLY_LAYER, Registry, Reticle, ReticleOptions, RotationRaycastMesh, Row, SIMULATOR_HAND_POSE_NAMES, SIMULATOR_HAND_POSE_TO_JOINTS_LEFT, SIMULATOR_HAND_POSE_TO_JOINTS_RIGHT, SOUND_PRESETS, ScreenshotSynthesizer, Script, ScriptMixin, ScriptsManager, ScrollingTroikaTextView, SetSimulatorModeEvent, ShowHandsAction, Simulator, SimulatorCamera, SimulatorControlMode, SimulatorControllerState, SimulatorControls, SimulatorDepth, SimulatorDepthMaterial, SimulatorHandPose, SimulatorHandPoseChangeRequestEvent, SimulatorHands, SimulatorInterface, SimulatorMediaDeviceInfo, SimulatorMode, SimulatorOptions, SimulatorRenderMode, SimulatorScene, SimulatorUser, SimulatorUserAction, SketchPanel, SkyboxAgent, SoundOptions, SoundSynthesizer, SpatialAudio, SpatialPanel, SpeechRecognizer, SpeechRecognizerOptions, SpeechSynthesizer, SpeechSynthesizerOptions, SplatAnchor, StreamState, TextButton, TextScrollerState, TextView, Tool, UI, UI_OVERLAY_LAYER, UP, UX, User, VIEW_DEPTH_GAP, VerticalPager, VideoFileStream, VideoStream, VideoView, View, VolumeCategory, WaitFrame, WalkTowardsPanelAction, World, WorldOptions, XRButton, XRDeviceCamera, XREffects, XRPass, XRTransitionOptions, XR_BLOCKS_ASSETS_PATH, ZERO_VECTOR3, add, ai, aspectRatios, callInitWithDependencyInjection, clamp, clampRotationToAngle, core, cropImage, extractYaw, getColorHex, getDeltaTime, getUrlParamBool, getUrlParamFloat, getUrlParamInt, getUrlParameter, getVec4ByColorString, getXrCameraLeft, getXrCameraRight, init, initScript, lerp, loadStereoImageAsTextures, loadingSpinnerManager, lookAtRotation, objectIsDescendantOf, onDesktopUserAgent, parseBase64DataURL, placeObjectAtIntersectionFacingTarget, print, rgbToDepthParams, scene, showOnlyInLeftEye, showOnlyInRightEye, showReticleOnDepthMesh, transformRgbToDepthUv, transformRgbUvToWorld, traverseUtil, uninitScript, urlParams, user, world, xrDepthMeshOptions, xrDepthMeshPhysicsOptions, xrDepthMeshVisualizationOptions, xrDeviceCameraEnvironmentContinuousOptions, xrDeviceCameraEnvironmentOptions, xrDeviceCameraUserContinuousOptions, xrDeviceCameraUserOptions };
16831
+ export { AI, AIOptions, AVERAGE_IPD_METERS, ActiveControllers, Agent, AnimatableNumber, AudioListener, AudioPlayer, BACK, BackgroundMusic, CategoryVolumes, Col, Core, CoreSound, DEFAULT_DEVICE_CAMERA_HEIGHT, DEFAULT_DEVICE_CAMERA_WIDTH, DOWN, Depth, DepthMesh, DepthMeshOptions, DepthOptions, DepthTextures, DetectedObject, DetectedPlane, DeviceCameraOptions, DragManager, DragMode, ExitButton, FORWARD, FreestandingSlider, GazeController, Gemini, GeminiOptions, GenerateSkyboxTool, GestureRecognition, GestureRecognitionOptions, GetWeatherTool, Grid, HAND_BONE_IDX_CONNECTION_MAP, HAND_JOINT_COUNT, HAND_JOINT_IDX_CONNECTION_MAP, HAND_JOINT_NAMES, Handedness, Hands, HandsOptions, HorizontalPager, IconButton, IconView, ImageView, Input, InputOptions, Keycodes, LEFT, LEFT_VIEW_ONLY_LAYER, LabelView, Lighting, LightingOptions, LoadingSpinnerManager, MaterialSymbolsView, MeshScript, ModelLoader, ModelViewer, MouseController, NEXT_SIMULATOR_MODE, NUM_HANDS, OCCLUDABLE_ITEMS_LAYER, ObjectDetector, ObjectsOptions, OcclusionPass, OcclusionUtils, OpenAI, OpenAIOptions, Options, PageIndicator, Pager, PagerState, Panel, PanelMesh, Physics, PhysicsOptions, PinchOnButtonAction, PlaneDetector, PlanesOptions, RIGHT, RIGHT_VIEW_ONLY_LAYER, Registry, Reticle, ReticleOptions, RotationRaycastMesh, Row, SIMULATOR_HAND_POSE_NAMES, SIMULATOR_HAND_POSE_TO_JOINTS_LEFT, SIMULATOR_HAND_POSE_TO_JOINTS_RIGHT, SOUND_PRESETS, ScreenshotSynthesizer, Script, ScriptMixin, ScriptsManager, ScrollingTroikaTextView, SetSimulatorModeEvent, ShowHandsAction, Simulator, SimulatorCamera, SimulatorControlMode, SimulatorControllerState, SimulatorControls, SimulatorDepth, SimulatorDepthMaterial, SimulatorHandPose, SimulatorHandPoseChangeRequestEvent, SimulatorHands, SimulatorInterface, SimulatorMediaDeviceInfo, SimulatorMode, SimulatorOptions, SimulatorRenderMode, SimulatorScene, SimulatorUser, SimulatorUserAction, SketchPanel, SkyboxAgent, SoundOptions, SoundSynthesizer, SpatialAudio, SpatialPanel, SpeechRecognizer, SpeechRecognizerOptions, SpeechSynthesizer, SpeechSynthesizerOptions, SplatAnchor, StreamState, TextButton, TextScrollerState, TextView, Tool, UI, UI_OVERLAY_LAYER, UP, UX, User, VIEW_DEPTH_GAP, VerticalPager, VideoFileStream, VideoStream, VideoView, View, VolumeCategory, WaitFrame, WalkTowardsPanelAction, World, WorldOptions, XRButton, XRDeviceCamera, XREffects, XRPass, XRTransitionOptions, XR_BLOCKS_ASSETS_PATH, ZERO_VECTOR3, add, ai, aspectRatios, callInitWithDependencyInjection, clamp, clampRotationToAngle, core, cropImage, extractYaw, getColorHex, getDeltaTime, getUrlParamBool, getUrlParamFloat, getUrlParamInt, getUrlParameter, getVec4ByColorString, getXrCameraLeft, getXrCameraRight, init, initScript, lerp, loadStereoImageAsTextures, loadingSpinnerManager, lookAtRotation, objectIsDescendantOf, parseBase64DataURL, placeObjectAtIntersectionFacingTarget, print, rgbToDepthParams, scene, showOnlyInLeftEye, showOnlyInRightEye, showReticleOnDepthMesh, transformRgbToDepthUv, transformRgbUvToWorld, traverseUtil, uninitScript, urlParams, user, world, xrDepthMeshOptions, xrDepthMeshPhysicsOptions, xrDepthMeshVisualizationOptions, xrDeviceCameraEnvironmentContinuousOptions, xrDeviceCameraEnvironmentOptions, xrDeviceCameraUserContinuousOptions, xrDeviceCameraUserOptions };
16829
16832
  //# sourceMappingURL=xrblocks.js.map