@iwsdk/core 0.5.3 → 1.0.0-rc.1

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.
Files changed (233) hide show
  1. package/README.md +22 -1
  2. package/dist/asset/asset-manager.d.ts.map +1 -1
  3. package/dist/asset/asset-manager.js +3 -2
  4. package/dist/asset/asset-manager.js.map +1 -1
  5. package/dist/asset/cache-manager.js.map +1 -1
  6. package/dist/asset/loaders/audio-loader.js.map +1 -1
  7. package/dist/asset/loaders/cached-asset-load.js.map +1 -1
  8. package/dist/asset/loaders/gltf-loader.js.map +1 -1
  9. package/dist/asset/loaders/hdr-texture-loader.js.map +1 -1
  10. package/dist/asset/loaders/texture-loader.js.map +1 -1
  11. package/dist/asset/loaders/uikitml-loader.js.map +1 -1
  12. package/dist/audio/audio-pool.js.map +1 -1
  13. package/dist/audio/audio-system.js.map +1 -1
  14. package/dist/audio/audio-utils.js.map +1 -1
  15. package/dist/audio/audio.js.map +1 -1
  16. package/dist/camera/camera-source.js.map +1 -1
  17. package/dist/camera/camera-system.d.ts +7 -3
  18. package/dist/camera/camera-system.d.ts.map +1 -1
  19. package/dist/camera/camera-system.js +81 -50
  20. package/dist/camera/camera-system.js.map +1 -1
  21. package/dist/camera/camera-utils.d.ts +5 -0
  22. package/dist/camera/camera-utils.d.ts.map +1 -1
  23. package/dist/camera/camera-utils.js +8 -1
  24. package/dist/camera/camera-utils.js.map +1 -1
  25. package/dist/camera/types.js.map +1 -1
  26. package/dist/depth/depth-occludable.js.map +1 -1
  27. package/dist/depth/depth-sensing-system.d.ts +3 -0
  28. package/dist/depth/depth-sensing-system.d.ts.map +1 -1
  29. package/dist/depth/depth-sensing-system.js +55 -1
  30. package/dist/depth/depth-sensing-system.js.map +1 -1
  31. package/dist/depth/depth-textures.js.map +1 -1
  32. package/dist/depth/occlusion/preprocessing-pass.js.map +1 -1
  33. package/dist/depth/occlusion/preprocessing-shader.glsl.js.map +1 -1
  34. package/dist/ecs/builtin-components.js.map +1 -1
  35. package/dist/ecs/component-editor-metadata.js.map +1 -1
  36. package/dist/ecs/component-manifest.js.map +1 -1
  37. package/dist/ecs/entity.js.map +1 -1
  38. package/dist/ecs/system.js.map +1 -1
  39. package/dist/ecs/world.d.ts +2 -0
  40. package/dist/ecs/world.d.ts.map +1 -1
  41. package/dist/ecs/world.js +4 -0
  42. package/dist/ecs/world.js.map +1 -1
  43. package/dist/environment/dome-gradient.js.map +1 -1
  44. package/dist/environment/dome-texture.js.map +1 -1
  45. package/dist/environment/environment-system.js.map +1 -1
  46. package/dist/environment/gradient-environment.js.map +1 -1
  47. package/dist/environment/ibl-gradient.js.map +1 -1
  48. package/dist/environment/ibl-texture.js.map +1 -1
  49. package/dist/environment/scene-ar-environment.js.map +1 -1
  50. package/dist/environment-raycast/environment-raycast.js.map +1 -1
  51. package/dist/environment-raycast/raycast-target.js.map +1 -1
  52. package/dist/grab/distance-grabbable.d.ts +5 -0
  53. package/dist/grab/distance-grabbable.d.ts.map +1 -1
  54. package/dist/grab/distance-grabbable.js +5 -0
  55. package/dist/grab/distance-grabbable.js.map +1 -1
  56. package/dist/grab/grab-helpers.js.map +1 -1
  57. package/dist/grab/grab-system.js.map +1 -1
  58. package/dist/grab/grab-warnings.js.map +1 -1
  59. package/dist/grab/grabbed.js.map +1 -1
  60. package/dist/grab/handles.d.ts +6 -0
  61. package/dist/grab/handles.d.ts.map +1 -1
  62. package/dist/grab/handles.js +46 -12
  63. package/dist/grab/handles.js.map +1 -1
  64. package/dist/grab/index.js.map +1 -1
  65. package/dist/grab/one-hand-grabbable.d.ts +5 -0
  66. package/dist/grab/one-hand-grabbable.d.ts.map +1 -1
  67. package/dist/grab/one-hand-grabbable.js +5 -0
  68. package/dist/grab/one-hand-grabbable.js.map +1 -1
  69. package/dist/grab/pointer-events-patch.js.map +1 -1
  70. package/dist/grab/two-hands-grabbable.d.ts +5 -0
  71. package/dist/grab/two-hands-grabbable.d.ts.map +1 -1
  72. package/dist/grab/two-hands-grabbable.js +5 -0
  73. package/dist/grab/two-hands-grabbable.js.map +1 -1
  74. package/dist/index.js +4 -3
  75. package/dist/index.js.map +1 -1
  76. package/dist/init/browser-camera.js.map +1 -1
  77. package/dist/init/index.d.ts +2 -2
  78. package/dist/init/index.d.ts.map +1 -1
  79. package/dist/init/player-camera.js.map +1 -1
  80. package/dist/init/session-grant.d.ts +34 -0
  81. package/dist/init/session-grant.d.ts.map +1 -0
  82. package/dist/init/session-grant.js +89 -0
  83. package/dist/init/session-grant.js.map +1 -0
  84. package/dist/init/world-initializer.d.ts +87 -4
  85. package/dist/init/world-initializer.d.ts.map +1 -1
  86. package/dist/init/world-initializer.js +45 -41
  87. package/dist/init/world-initializer.js.map +1 -1
  88. package/dist/init/xr.d.ts +19 -0
  89. package/dist/init/xr.d.ts.map +1 -1
  90. package/dist/init/xr.js +136 -41
  91. package/dist/init/xr.js.map +1 -1
  92. package/dist/input/canvas-pointer-system.d.ts +2 -0
  93. package/dist/input/canvas-pointer-system.d.ts.map +1 -1
  94. package/dist/input/canvas-pointer-system.js +33 -13
  95. package/dist/input/canvas-pointer-system.js.map +1 -1
  96. package/dist/input/input-actions.js.map +1 -1
  97. package/dist/input/input-manager.js.map +1 -1
  98. package/dist/input/input-system.d.ts.map +1 -1
  99. package/dist/input/input-system.js +5 -2
  100. package/dist/input/input-system.js.map +1 -1
  101. package/dist/input/state-tags.js.map +1 -1
  102. package/dist/input/stateful-browser-gamepad.js.map +1 -1
  103. package/dist/input/stateful-keyboard.js.map +1 -1
  104. package/dist/layers/xr-cylinder-layer.d.ts +2 -1
  105. package/dist/layers/xr-cylinder-layer.d.ts.map +1 -1
  106. package/dist/layers/xr-cylinder-layer.js +2 -1
  107. package/dist/layers/xr-cylinder-layer.js.map +1 -1
  108. package/dist/layers/xr-layer-init.d.ts +19 -0
  109. package/dist/layers/xr-layer-init.d.ts.map +1 -0
  110. package/dist/layers/xr-layer-init.js +20 -0
  111. package/dist/layers/xr-layer-init.js.map +1 -0
  112. package/dist/layers/xr-layer-state.js.map +1 -1
  113. package/dist/layers/xr-layer-system.d.ts +41 -1
  114. package/dist/layers/xr-layer-system.d.ts.map +1 -1
  115. package/dist/layers/xr-layer-system.js +506 -132
  116. package/dist/layers/xr-layer-system.js.map +1 -1
  117. package/dist/layers/xr-layer-transform.d.ts +18 -0
  118. package/dist/layers/xr-layer-transform.d.ts.map +1 -0
  119. package/dist/layers/xr-layer-transform.js +115 -0
  120. package/dist/layers/xr-layer-transform.js.map +1 -0
  121. package/dist/layers/xr-quad-layer.d.ts +2 -1
  122. package/dist/layers/xr-quad-layer.d.ts.map +1 -1
  123. package/dist/layers/xr-quad-layer.js +2 -1
  124. package/dist/layers/xr-quad-layer.js.map +1 -1
  125. package/dist/level/level-component-applier.d.ts +2 -0
  126. package/dist/level/level-component-applier.d.ts.map +1 -1
  127. package/dist/level/level-component-applier.js +24 -5
  128. package/dist/level/level-component-applier.js.map +1 -1
  129. package/dist/level/level-player-rig.js.map +1 -1
  130. package/dist/level/level-root.js.map +1 -1
  131. package/dist/level/level-scene-environment.js.map +1 -1
  132. package/dist/level/level-scene-json-importer.js.map +1 -1
  133. package/dist/level/level-scene-material.js.map +1 -1
  134. package/dist/level/level-scene-object.js.map +1 -1
  135. package/dist/level/level-scene-primitive.js.map +1 -1
  136. package/dist/level/level-system.js.map +1 -1
  137. package/dist/level/level-tag.js.map +1 -1
  138. package/dist/lighting/light-binding.js.map +1 -1
  139. package/dist/lighting/light-components.js.map +1 -1
  140. package/dist/lighting/light-system.js.map +1 -1
  141. package/dist/locomotion/geometries/beveled-cylinder.js.map +1 -1
  142. package/dist/locomotion/locomotion-environment.js.map +1 -1
  143. package/dist/locomotion/locomotion-input-provider.js.map +1 -1
  144. package/dist/locomotion/locomotion.js.map +1 -1
  145. package/dist/locomotion/materials/line.js.map +1 -1
  146. package/dist/locomotion/slide.js.map +1 -1
  147. package/dist/locomotion/teleport.js.map +1 -1
  148. package/dist/locomotion/turn.js.map +1 -1
  149. package/dist/mcp/ecs-debug-tools.d.ts +4 -1
  150. package/dist/mcp/ecs-debug-tools.d.ts.map +1 -1
  151. package/dist/mcp/ecs-debug-tools.js +113 -10
  152. package/dist/mcp/ecs-debug-tools.js.map +1 -1
  153. package/dist/mcp/index.d.ts +1 -0
  154. package/dist/mcp/index.d.ts.map +1 -1
  155. package/dist/mcp/mcp-runtime.d.ts +2 -0
  156. package/dist/mcp/mcp-runtime.d.ts.map +1 -1
  157. package/dist/mcp/mcp-runtime.js +41 -0
  158. package/dist/mcp/mcp-runtime.js.map +1 -1
  159. package/dist/mcp/scene-tools.js.map +1 -1
  160. package/dist/mcp/ui-debug-tools.d.ts +56 -0
  161. package/dist/mcp/ui-debug-tools.d.ts.map +1 -0
  162. package/dist/mcp/ui-debug-tools.js +412 -0
  163. package/dist/mcp/ui-debug-tools.js.map +1 -0
  164. package/dist/physics/index.js +1 -1
  165. package/dist/physics/physics-runtime.d.ts +22 -0
  166. package/dist/physics/physics-runtime.d.ts.map +1 -0
  167. package/dist/physics/physics-runtime.js +423 -0
  168. package/dist/physics/physics-runtime.js.map +1 -0
  169. package/dist/physics/physics-system.d.ts +84 -108
  170. package/dist/physics/physics-system.d.ts.map +1 -1
  171. package/dist/physics/physics-system.js +686 -555
  172. package/dist/physics/physics-system.js.map +1 -1
  173. package/dist/physics/physics-transport.d.ts +20 -0
  174. package/dist/physics/physics-transport.d.ts.map +1 -0
  175. package/dist/physics/physics-transport.js +111 -0
  176. package/dist/physics/physics-transport.js.map +1 -0
  177. package/dist/physics/physics-worker-protocol.d.ts +144 -0
  178. package/dist/physics/physics-worker-protocol.d.ts.map +1 -0
  179. package/dist/physics/physics-worker-protocol.js +41 -0
  180. package/dist/physics/physics-worker-protocol.js.map +1 -0
  181. package/dist/physics/physics-worker-utils.d.ts +8 -0
  182. package/dist/physics/physics-worker-utils.d.ts.map +1 -0
  183. package/dist/physics/physics-worker-utils.js +12 -0
  184. package/dist/physics/physics-worker-utils.js.map +1 -0
  185. package/dist/physics/physics-worker.d.ts +8 -0
  186. package/dist/physics/physics-worker.d.ts.map +1 -0
  187. package/dist/physics/physics-worker.js +66 -0
  188. package/dist/physics/physics-worker.js.map +1 -0
  189. package/dist/physics/physicsBody.js.map +1 -1
  190. package/dist/physics/physicsManipulation.js.map +1 -1
  191. package/dist/physics/physicsShape.js.map +1 -1
  192. package/dist/physics/utils.js.map +1 -1
  193. package/dist/project/normalize.js +7 -1
  194. package/dist/project/normalize.js.map +1 -1
  195. package/dist/project/paths.js.map +1 -1
  196. package/dist/project/types.d.ts +7 -1
  197. package/dist/project/types.d.ts.map +1 -1
  198. package/dist/project/types.js.map +1 -1
  199. package/dist/project/validation.js +36 -2
  200. package/dist/project/validation.js.map +1 -1
  201. package/dist/runtime/three.js.map +1 -1
  202. package/dist/scene-understanding/anchor.js.map +1 -1
  203. package/dist/scene-understanding/mesh.js.map +1 -1
  204. package/dist/scene-understanding/plane.js.map +1 -1
  205. package/dist/scene-understanding/scene-understanding-system.d.ts +42 -6
  206. package/dist/scene-understanding/scene-understanding-system.d.ts.map +1 -1
  207. package/dist/scene-understanding/scene-understanding-system.js +391 -106
  208. package/dist/scene-understanding/scene-understanding-system.js.map +1 -1
  209. package/dist/schemas/iwsdk-project.v1.schema.json +20 -1
  210. package/dist/transform/synced-euler.js.map +1 -1
  211. package/dist/transform/synced-quaternion.js.map +1 -1
  212. package/dist/transform/synced-vector3.js.map +1 -1
  213. package/dist/transform/transform-component.js.map +1 -1
  214. package/dist/transform/transform-utils.js.map +1 -1
  215. package/dist/transform/transform.js.map +1 -1
  216. package/dist/ui/document.js.map +1 -1
  217. package/dist/ui/follow-component.js.map +1 -1
  218. package/dist/ui/follow.d.ts.map +1 -1
  219. package/dist/ui/follow.js +0 -1
  220. package/dist/ui/follow.js.map +1 -1
  221. package/dist/ui/panel-components.js.map +1 -1
  222. package/dist/ui/screenspace-component.js.map +1 -1
  223. package/dist/ui/screenspace.js.map +1 -1
  224. package/dist/ui/ui.js.map +1 -1
  225. package/dist/ui/uikitml-asset.js.map +1 -1
  226. package/dist/ui/uikitml.js.map +1 -1
  227. package/dist/version.d.ts +1 -1
  228. package/dist/version.d.ts.map +1 -1
  229. package/dist/version.js +1 -1
  230. package/dist/version.js.map +1 -1
  231. package/dist/visibility/visibility-component.js.map +1 -1
  232. package/dist/visibility/visibility.js.map +1 -1
  233. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"audio-utils.js","sources":["../../src/audio/audio-utils.ts"],"sourcesContent":[null],"names":["AudioComponent"],"mappings":"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"}
1
+ {"version":3,"file":"audio-utils.js","sources":["../../src/audio/audio-utils.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { Entity } from '../ecs/entity.js';\nimport type { World } from '../ecs/world.js';\nimport { AudioSource as AudioComponent } from './audio.js';\n\n/** Utility helpers to control {@link AudioSource} without touching Three audio.\n * @category Audio\n */\nexport class AudioUtils {\n /**\n * Play audio on an entity\n * @param entity - Entity with Audio component\n * @param fadeIn - Fade in duration in seconds\n */\n static play(entity: Entity, fadeIn = 0): void {\n const index = entity.index;\n // Check if entity has audio by checking if data exists\n if (AudioComponent.data.src[index] === undefined) {\n console.warn('Entity does not have Audio component');\n return;\n }\n\n AudioComponent.data._playRequested[index] = 1;\n AudioComponent.data._fadeIn[index] = fadeIn;\n }\n\n /**\n * Pause audio on an entity\n * @param entity - Entity with Audio component\n * @param fadeOut - Fade out duration in seconds\n */\n static pause(entity: Entity, fadeOut = 0): void {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n console.warn('Entity does not have Audio component');\n return;\n }\n\n AudioComponent.data._pauseRequested[index] = 1;\n AudioComponent.data._fadeOut[index] = fadeOut;\n }\n\n /**\n * Stop audio on an entity\n * @param entity - Entity with Audio component\n */\n static stop(entity: Entity): void {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n console.warn('Entity does not have Audio component');\n return;\n }\n\n AudioComponent.data._stopRequested[index] = 1;\n }\n\n /**\n * Check if audio is playing on an entity\n * @param entity - Entity with Audio component\n * @returns True if audio is playing\n */\n static isPlaying(entity: Entity): boolean {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n return false;\n }\n\n return AudioComponent.data._isPlaying[index] === 1;\n }\n\n /**\n * Set volume on an entity's audio\n * @param entity - Entity with Audio component\n * @param volume - Volume level (0.0 to 1.0)\n */\n static setVolume(entity: Entity, volume: number): void {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n console.warn('Entity does not have Audio component');\n return;\n }\n\n AudioComponent.data.volume[index] = Math.max(0, Math.min(1, volume));\n }\n\n /**\n * Get volume from an entity's audio\n * @param entity - Entity with Audio component\n * @returns Current volume level\n */\n static getVolume(entity: Entity): number {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n return 0;\n }\n\n return AudioComponent.data.volume[index];\n }\n\n /**\n * Preload audio for an entity\n * @param entity - Entity with Audio component\n * @returns Promise that resolves when audio is loaded\n */\n static async preload(entity: Entity): Promise<void> {\n const index = entity.index;\n if (AudioComponent.data.src[index] === undefined) {\n throw new Error('Entity does not have Audio component');\n }\n\n // Wait for loading to complete\n return new Promise<void>((resolve) => {\n const checkLoaded = () => {\n if (AudioComponent.data._loaded[index]) {\n resolve();\n } else if (\n !AudioComponent.data._loading[index] &&\n !AudioComponent.data._loaded[index]\n ) {\n // Not loading and not loaded, might need to wait for system update\n setTimeout(checkLoaded, 16);\n } else {\n // Currently loading\n setTimeout(checkLoaded, 16);\n }\n };\n\n checkLoaded();\n });\n }\n\n /**\n * Create a one-shot audio entity that auto-removes after playing\n * @param world - World instance\n * @param src - Audio source path\n * @param options - Additional audio options\n * @returns Created entity\n */\n static createOneShot(\n world: World,\n src: string,\n options: {\n volume?: number;\n positional?: boolean;\n position?: { x: number; y: number; z: number };\n } = {},\n ): Entity {\n const entity = world.createEntity();\n\n entity.addComponent(AudioComponent, {\n src,\n volume: options.volume ?? 1.0,\n positional: options.positional ?? false,\n autoplay: true,\n loop: false,\n });\n\n if (options.positional && options.position) {\n // Would need Transform component\n // entity.addComponent(Transform, { position: options.position });\n }\n\n // Auto-remove entity when sound ends\n // This would be handled by the AudioSystem when detecting ended non-looping sounds\n\n return entity;\n }\n}\n"],"names":["AudioComponent"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"audio.js","sources":["../../src/audio/audio.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audio.js","sources":["../../src/audio/audio.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// See audio-system.ts for rationale — import from the subfile, not the\n// `../ecs/index.js` barrel, to keep this module free of the world.js cycle.\nimport { Types, createComponent } from '../ecs/component.js';\n\n/**\n * Playback behavior when a new play is requested.\n *\n * @category Audio\n */\nexport const PlaybackMode = {\n Restart: 'restart',\n Overlap: 'overlap',\n Ignore: 'ignore',\n FadeRestart: 'fade-restart',\n} as const;\n\n/**\n * Policy used when the instance pool is full and a new play is requested.\n *\n * @category Audio\n */\nexport const InstanceStealPolicy = {\n Oldest: 'oldest',\n Quietest: 'quietest',\n Furthest: 'furthest',\n} as const;\n\n/**\n * Distance attenuation model for positional audio.\n *\n * @category Audio\n */\nexport const DistanceModel = {\n Linear: 'linear',\n Inverse: 'inverse',\n Exponential: 'exponential',\n} as const;\n\n/**\n * Configurable audio playback component for positional and ambient sounds.\n *\n * @remarks\n * - The {@link AudioSystem} loads sources via {@link AssetManager} and manages\n * instance pooling, crossfades, and XR session lifecycle.\n * - For positional audio, attach the component to an entity with a valid\n * Object3D; non-positional audio plays from the listener.\n * - Use `_playRequested/_pauseRequested/_stopRequested` to trigger actions\n * without directly reaching into Three.js audio objects.\n *\n * @category Audio\n */\nexport const AudioSource = createComponent(\n 'AudioSource',\n {\n // Core properties PathByFilePickerAttribute\n src: {\n type: Types.FilePath,\n default: '',\n fileTypes: '.mp3,.wav,.ogg,.m4a,.aac',\n subfolder: 'audio',\n }, // URL or cache key for an audio buffer\n volume: { type: Types.Float32, default: 1.0 }, // Linear gain [0..1]\n loop: { type: Types.Boolean, default: false }, // When true, newly created instances loop\n autoplay: { type: Types.Boolean, default: false }, // Trigger a single play on first update after load\n\n // Spatial properties\n positional: { type: Types.Boolean, default: true }, // true: PositionalAudio; false: ambient Audio\n refDistance: { type: Types.Float32, default: 1 }, // Distance at which volume is 1.0\n rolloffFactor: { type: Types.Float32, default: 1 }, // Rolloff curve steepness\n maxDistance: { type: Types.Float32, default: 10000 }, // Distance after which volume is 0\n distanceModel: {\n type: Types.Enum,\n enum: DistanceModel,\n default: DistanceModel.Inverse,\n },\n coneInnerAngle: { type: Types.Float32, default: 360 }, // Degrees of full-volume cone\n coneOuterAngle: { type: Types.Float32, default: 360 }, // Degrees until falloff reaches outer gain\n coneOuterGain: { type: Types.Float32, default: 0 }, // Gain at the edge/outside of the cone\n\n // Playback behavior control\n playbackMode: {\n type: Types.Enum,\n enum: PlaybackMode,\n default: PlaybackMode.Restart,\n }, // Behavior when play is triggered while another instance is active\n maxInstances: { type: Types.Int8, default: 1 }, // Max simultaneous instances in pool\n crossfadeDuration: { type: Types.Float32, default: 0.1 }, // Seconds used for FadeRestart\n instanceStealPolicy: {\n type: Types.Enum,\n enum: InstanceStealPolicy,\n default: InstanceStealPolicy.Oldest,\n }, // Which instance to replace when pool is full\n\n // Playback control flags (internal)\n _playRequested: { type: Types.Boolean, default: false }, // Set true to request play on next update\n _pauseRequested: { type: Types.Boolean, default: false }, // Set true to request pause (optional fade)\n _stopRequested: { type: Types.Boolean, default: false }, // Set true to stop and clear instances\n _fadeIn: { type: Types.Float32, default: 0 }, // Seconds to fade in on next play\n _fadeOut: { type: Types.Float32, default: 0 }, // Seconds to fade out on pause\n\n // Runtime state (managed by AudioSystem)\n _pool: { type: Types.Object, default: undefined }, // Assigned AudioPool for this entity\n _instances: { type: Types.Object, default: undefined }, // Active instance list (internal)\n _isPlaying: { type: Types.Boolean, default: false }, // True if any instance is currently playing\n _buffer: { type: Types.Object, default: undefined }, // Loaded AudioBuffer\n _loaded: { type: Types.Boolean, default: false }, // True once buffer is loaded\n _loading: { type: Types.Boolean, default: false }, // True while buffer is loading\n },\n 'AudioSource playback component for positional and non-positional sounds',\n);\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAEH;AACA;AAGA;;;;AAIG;AACI,MAAM,YAAY,GAAG;AAC1B,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,WAAW,EAAE,cAAc;;AAG7B;;;;AAIG;AACI,MAAM,mBAAmB,GAAG;AACjC,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,QAAQ,EAAE,UAAU;AACpB,IAAA,QAAQ,EAAE,UAAU;;AAGtB;;;;AAIG;AACI,MAAM,aAAa,GAAG;AAC3B,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,WAAW,EAAE,aAAa;;AAG5B;;;;;;;;;;;;AAYG;AACI,MAAM,WAAW,GAAG,eAAe,CACxC,aAAa,EACb;;AAEE,IAAA,GAAG,EAAE;QACH,IAAI,EAAE,KAAK,CAAC,QAAQ;AACpB,QAAA,OAAO,EAAE,EAAE;AACX,QAAA,SAAS,EAAE,0BAA0B;AACrC,QAAA,SAAS,EAAE,OAAO;AACnB,KAAA;AACD,IAAA,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;AAC7C,IAAA,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AAC7C,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;;AAGjD,IAAA,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;AAClD,IAAA,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAChD,IAAA,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAClD,IAAA,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AACpD,IAAA,aAAa,EAAE;QACb,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,aAAa,CAAC,OAAO;AAC/B,KAAA;AACD,IAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;AACrD,IAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;AACrD,IAAA,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;;AAGlD,IAAA,YAAY,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,YAAY,CAAC,OAAO;AAC9B,KAAA;AACD,IAAA,YAAY,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;AAC9C,IAAA,iBAAiB,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;AACxD,IAAA,mBAAmB,EAAE;QACnB,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,mBAAmB,CAAC,MAAM;AACpC,KAAA;;AAGD,IAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AACvD,IAAA,eAAe,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AACxD,IAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AACvD,IAAA,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAC5C,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;;AAG7C,IAAA,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;AACjD,IAAA,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;AACtD,IAAA,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AACnD,IAAA,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;AACnD,IAAA,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AAChD,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;CAClD,EACD,yEAAyE;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"camera-source.js","sources":["../../src/camera/camera-source.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAAA;;;;;AAKG;AAKH;;;AAGG;AACI,MAAM,YAAY,GAAG,eAAe,CACzC,cAAc,EACd;;AAEE,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;AAC7C,IAAA,MAAM,EAAE;QACN,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,YAAY,CAAC,OAAO;AAC9B,KAAA;IACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;IAC5C,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;;AAG7C,IAAA,KAAK,EAAE;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,WAAW,CAAC,QAAQ;AAC9B,KAAA;AACD,IAAA,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AAC9C,IAAA,YAAY,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AACnD,IAAA,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;CAC9C,EACD,yCAAyC;;;;"}
1
+ {"version":3,"file":"camera-source.js","sources":["../../src/camera/camera-source.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { Types, createComponent } from '../ecs/component.js';\nimport { CameraFacing, CameraState } from './types.js';\n\n/**\n * CameraSource - Component for accessing device cameras\n * Provides VideoTexture for rendering and HTMLVideoElement for advanced use\n */\nexport const CameraSource = createComponent(\n 'CameraSource',\n {\n // Input (set by user)\n deviceId: { type: Types.String, default: '' }, // Empty = auto-select based on facing\n facing: {\n type: Types.Enum,\n enum: CameraFacing,\n default: CameraFacing.Unknown,\n }, // 'front' | 'back' | 'unknown' - used for auto-selection (unknown = any camera)\n width: { type: Types.Int16, default: 1920 },\n height: { type: Types.Int16, default: 1080 },\n frameRate: { type: Types.Int16, default: 30 },\n\n // Output (managed by system, read-only for users)\n state: {\n type: Types.Enum,\n enum: CameraState,\n default: CameraState.Inactive,\n }, // 'inactive' | 'starting' | 'active' | 'error'\n texture: { type: Types.Object, default: null }, // VideoTexture\n videoElement: { type: Types.Object, default: null }, // HTMLVideoElement (for advanced use)\n stream: { type: Types.Object, default: null }, // MediaStream (internal)\n },\n 'Camera video source with texture output',\n);\n"],"names":[],"mappings":";;;AAAA;;;;;AAKG;AAKH;;;AAGG;AACI,MAAM,YAAY,GAAG,eAAe,CACzC,cAAc,EACd;;AAEE,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;AAC7C,IAAA,MAAM,EAAE;QACN,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,YAAY,CAAC,OAAO;AAC9B,KAAA;IACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;IAC5C,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;;AAG7C,IAAA,KAAK,EAAE;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,WAAW,CAAC,QAAQ;AAC9B,KAAA;AACD,IAAA,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AAC9C,IAAA,YAAY,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AACnD,IAAA,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;CAC9C,EACD,yCAAyC;;;;"}
@@ -113,10 +113,9 @@ declare const CameraSystem_base: import("elics").SystemConstructor<import("elics
113
113
  * CameraSystem - Manages camera stream lifecycle for CameraSource components
114
114
  * Automatically starts streams when the world is visible, including browser
115
115
  * non-immersive mode and immersive XR sessions.
116
- *
117
- * System is stateless - all state is stored in CameraSource components
118
116
  */
119
117
  export declare class CameraSystem extends CameraSystem_base {
118
+ private readonly operationIds;
120
119
  init(): void;
121
120
  update(): void;
122
121
  /**
@@ -124,13 +123,18 @@ export declare class CameraSystem extends CameraSystem_base {
124
123
  * Async operation - sets state to Starting, then Active when complete
125
124
  * Users should check state or null-check texture/videoElement before using
126
125
  *
127
- * Checks state after each async operation to abort if stopCamera was called
126
+ * Checks an operation generation after each async operation so a restarted
127
+ * camera cannot be overwritten by an older request that resolves later.
128
128
  */
129
129
  private startCamera;
130
130
  /**
131
131
  * Stop camera stream for an entity
132
132
  */
133
133
  private stopCamera;
134
+ private releaseCameraResources;
135
+ private stopAllCameras;
136
+ private beginOperation;
137
+ private isCurrentStart;
134
138
  /**
135
139
  * Clean up camera resources (stream, video element, texture)
136
140
  */
@@ -1 +1 @@
1
- {"version":3,"file":"camera-system.d.ts","sourceRoot":"","sources":["../../src/camera/camera-system.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeH;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,iBAEhC;IACA,IAAI;IAeJ,MAAM;IAgBN;;;;;;OAMG;YACW,WAAW;IAqKzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAuBlB;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAgB/B"}
1
+ {"version":3,"file":"camera-system.d.ts","sourceRoot":"","sources":["../../src/camera/camera-system.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeH;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,iBAEhC;IACA,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAE9D,IAAI;IAkCJ,MAAM;IAqBN;;;;;;;OAOG;YACW,WAAW;IA0IzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAgB/B"}
@@ -16,33 +16,49 @@ import { VideoTexture, LinearFilter } from 'three';
16
16
  * CameraSystem - Manages camera stream lifecycle for CameraSource components
17
17
  * Automatically starts streams when the world is visible, including browser
18
18
  * non-immersive mode and immersive XR sessions.
19
- *
20
- * System is stateless - all state is stored in CameraSource components
21
19
  */
22
20
  class CameraSystem extends createSystem({
23
21
  cameras: { required: [CameraSource] },
24
22
  }) {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.operationIds = new WeakMap();
26
+ }
25
27
  init() {
26
- // Stop all cameras only when the page/session is hidden. Register the
27
- // unsubscribe so the callback (and its closure over `this`) is released on
28
- // system teardown rather than leaking.
28
+ const stopIfDocumentHidden = () => {
29
+ if (document.visibilityState === 'hidden') {
30
+ this.stopAllCameras();
31
+ }
32
+ };
33
+ const hasDocumentVisibility = typeof document !== 'undefined' &&
34
+ typeof document.addEventListener === 'function';
35
+ if (hasDocumentVisibility) {
36
+ document.addEventListener('visibilitychange', stopIfDocumentHidden);
37
+ }
29
38
  this.cleanupFuncs.push(this.world.visibilityState.subscribe((state) => {
30
39
  if (state === VisibilityState.Hidden) {
31
- for (const entity of this.queries.cameras.entities) {
32
- this.stopCamera(entity);
33
- }
40
+ this.stopAllCameras();
41
+ }
42
+ }), this.queries.cameras.subscribe('disqualify', (entity) => {
43
+ this.stopCamera(entity);
44
+ }), () => {
45
+ if (hasDocumentVisibility) {
46
+ document.removeEventListener('visibilitychange', stopIfDocumentHidden);
34
47
  }
35
- }));
48
+ this.stopAllCameras();
49
+ });
36
50
  }
37
51
  update() {
38
52
  // CameraSource uses browser media APIs and works outside immersive XR.
39
- if (this.world.visibilityState.value === VisibilityState.Hidden) {
53
+ const documentHidden = typeof document !== 'undefined' && document.visibilityState === 'hidden';
54
+ if (documentHidden ||
55
+ this.world.visibilityState.value === VisibilityState.Hidden) {
40
56
  return;
41
57
  }
42
58
  for (const entity of this.queries.cameras.entities) {
43
59
  const state = entity.getValue(CameraSource, 'state');
44
- // Start camera if inactive (not started or errored)
45
- if (state === CameraState.Inactive || state === CameraState.Error) {
60
+ // Error is terminal until callers explicitly set the source inactive.
61
+ if (state === CameraState.Inactive) {
46
62
  this.startCamera(entity);
47
63
  }
48
64
  }
@@ -52,19 +68,23 @@ class CameraSystem extends createSystem({
52
68
  * Async operation - sets state to Starting, then Active when complete
53
69
  * Users should check state or null-check texture/videoElement before using
54
70
  *
55
- * Checks state after each async operation to abort if stopCamera was called
71
+ * Checks an operation generation after each async operation so a restarted
72
+ * camera cannot be overwritten by an older request that resolves later.
56
73
  */
57
74
  async startCamera(entity) {
75
+ const operationId = this.beginOperation(entity);
76
+ this.releaseCameraResources(entity);
58
77
  // Set state to Starting to prevent duplicate attempts
59
78
  entity.setValue(CameraSource, 'state', CameraState.Starting);
79
+ let stream = null;
80
+ let video = null;
81
+ let texture = null;
60
82
  try {
61
83
  let deviceId = entity.getValue(CameraSource, 'deviceId');
62
84
  // Auto-select camera if no deviceId provided
63
85
  if (!deviceId) {
64
86
  const devices = await CameraUtils.getDevices();
65
- // Check if we should abort (stopCamera was called during async operation)
66
- const currentState = entity.getValue(CameraSource, 'state');
67
- if (currentState !== CameraState.Starting) {
87
+ if (!this.isCurrentStart(entity, operationId)) {
68
88
  return; // Aborted
69
89
  }
70
90
  const facing = entity.getValue(CameraSource, 'facing');
@@ -100,7 +120,7 @@ class CameraSystem extends createSystem({
100
120
  const height = entity.getValue(CameraSource, 'height');
101
121
  const frameRate = entity.getValue(CameraSource, 'frameRate');
102
122
  // Request camera stream
103
- const stream = await navigator.mediaDevices.getUserMedia({
123
+ stream = await navigator.mediaDevices.getUserMedia({
104
124
  video: {
105
125
  deviceId: { exact: deviceId },
106
126
  width: { ideal: width },
@@ -108,50 +128,45 @@ class CameraSystem extends createSystem({
108
128
  frameRate: { ideal: frameRate },
109
129
  },
110
130
  });
111
- // Check if we should abort after getting stream
112
- const currentState = entity.getValue(CameraSource, 'state');
113
- if (currentState !== CameraState.Starting) {
131
+ if (!this.isCurrentStart(entity, operationId)) {
114
132
  // Aborted - clean up the stream we just created
115
133
  this.cleanupCameraResources(stream, null, null);
116
134
  return;
117
135
  }
118
136
  // Create video element
119
- const video = document.createElement('video');
120
- video.setAttribute('playsinline', '');
121
- video.setAttribute('autoplay', '');
122
- video.muted = true;
123
- video.srcObject = stream;
137
+ const createdVideo = document.createElement('video');
138
+ video = createdVideo;
139
+ createdVideo.setAttribute('playsinline', '');
140
+ createdVideo.setAttribute('autoplay', '');
141
+ createdVideo.muted = true;
142
+ createdVideo.srcObject = stream;
124
143
  // Wait for video to be ready
125
144
  await new Promise((resolve, reject) => {
126
145
  const onCanPlay = () => {
127
- video.removeEventListener('canplay', onCanPlay);
128
- video.removeEventListener('error', onError);
146
+ createdVideo.removeEventListener('canplay', onCanPlay);
147
+ createdVideo.removeEventListener('error', onError);
129
148
  resolve();
130
149
  };
131
150
  const onError = (error) => {
132
- video.removeEventListener('canplay', onCanPlay);
133
- video.removeEventListener('error', onError);
151
+ createdVideo.removeEventListener('canplay', onCanPlay);
152
+ createdVideo.removeEventListener('error', onError);
134
153
  reject(error);
135
154
  };
136
- video.addEventListener('canplay', onCanPlay);
137
- video.addEventListener('error', onError);
155
+ createdVideo.addEventListener('canplay', onCanPlay);
156
+ createdVideo.addEventListener('error', onError);
138
157
  });
139
- // Check if we should abort after video ready
140
- const finalState = entity.getValue(CameraSource, 'state');
141
- if (finalState !== CameraState.Starting) {
158
+ if (!this.isCurrentStart(entity, operationId)) {
142
159
  // Aborted - clean up everything
143
160
  this.cleanupCameraResources(stream, video, null);
144
161
  return;
145
162
  }
146
163
  // Start playback
147
- await video.play();
164
+ await createdVideo.play();
148
165
  // Create VideoTexture
149
- const texture = new VideoTexture(video);
166
+ texture = new VideoTexture(createdVideo);
150
167
  texture.minFilter = LinearFilter;
151
168
  texture.magFilter = LinearFilter;
152
- // Final check before committing - ensure state is still Starting
153
- const committingState = entity.getValue(CameraSource, 'state');
154
- if (committingState !== CameraState.Starting) {
169
+ if (!this.isCurrentStart(entity, operationId)) {
155
170
  // Aborted at the last moment - clean up everything
156
171
  this.cleanupCameraResources(stream, video, texture);
157
172
  return;
@@ -163,31 +178,47 @@ class CameraSystem extends createSystem({
163
178
  entity.setValue(CameraSource, 'state', CameraState.Active);
164
179
  }
165
180
  catch (error) {
166
- console.error('Failed to start camera:', error);
167
- // Clean up any partial state
168
- const stream = entity.getValue(CameraSource, 'stream');
169
- const video = entity.getValue(CameraSource, 'videoElement');
170
- const texture = entity.getValue(CameraSource, 'texture');
171
181
  this.cleanupCameraResources(stream, video, texture);
172
- entity.setValue(CameraSource, 'stream', null);
173
- entity.setValue(CameraSource, 'videoElement', null);
174
- entity.setValue(CameraSource, 'texture', null);
175
- entity.setValue(CameraSource, 'state', CameraState.Error);
182
+ if (this.isCurrentStart(entity, operationId)) {
183
+ console.error('Failed to start camera:', error);
184
+ entity.setValue(CameraSource, 'stream', null);
185
+ entity.setValue(CameraSource, 'videoElement', null);
186
+ entity.setValue(CameraSource, 'texture', null);
187
+ entity.setValue(CameraSource, 'state', CameraState.Error);
188
+ }
176
189
  }
177
190
  }
178
191
  /**
179
192
  * Stop camera stream for an entity
180
193
  */
181
194
  stopCamera(entity) {
195
+ this.beginOperation(entity);
196
+ this.releaseCameraResources(entity);
197
+ entity.setValue(CameraSource, 'state', CameraState.Inactive);
198
+ }
199
+ releaseCameraResources(entity) {
182
200
  const stream = entity.getValue(CameraSource, 'stream');
183
201
  const video = entity.getValue(CameraSource, 'videoElement');
184
202
  const texture = entity.getValue(CameraSource, 'texture');
185
203
  this.cleanupCameraResources(stream, video, texture);
186
- // Clear component values and set state to Inactive
187
204
  entity.setValue(CameraSource, 'stream', null);
188
205
  entity.setValue(CameraSource, 'videoElement', null);
189
206
  entity.setValue(CameraSource, 'texture', null);
190
- entity.setValue(CameraSource, 'state', CameraState.Inactive);
207
+ }
208
+ stopAllCameras() {
209
+ for (const entity of this.queries.cameras.entities) {
210
+ this.stopCamera(entity);
211
+ }
212
+ }
213
+ beginOperation(entity) {
214
+ var _a;
215
+ const operationId = ((_a = this.operationIds.get(entity)) !== null && _a !== void 0 ? _a : 0) + 1;
216
+ this.operationIds.set(entity, operationId);
217
+ return operationId;
218
+ }
219
+ isCurrentStart(entity, operationId) {
220
+ return (this.operationIds.get(entity) === operationId &&
221
+ entity.getValue(CameraSource, 'state') === CameraState.Starting);
191
222
  }
192
223
  /**
193
224
  * Clean up camera resources (stream, video element, texture)
@@ -1 +1 @@
1
- {"version":3,"file":"camera-system.js","sources":["../../src/camera/camera-system.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"camera-system.js","sources":["../../src/camera/camera-system.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { Entity } from '../ecs/entity.js';\nimport { createSystem } from '../ecs/system.js';\nimport { VisibilityState } from '../ecs/world.js';\nimport { LinearFilter, VideoTexture } from '../runtime/three.js';\nimport { CameraSource } from './camera-source.js';\nimport { CameraUtils } from './camera-utils.js';\nimport {\n CameraFacing,\n CameraState,\n type CameraFacingType,\n type CameraStateType,\n} from './types.js';\n\n/**\n * CameraSystem - Manages camera stream lifecycle for CameraSource components\n * Automatically starts streams when the world is visible, including browser\n * non-immersive mode and immersive XR sessions.\n */\nexport class CameraSystem extends createSystem({\n cameras: { required: [CameraSource] },\n}) {\n private readonly operationIds = new WeakMap<Entity, number>();\n\n init() {\n const stopIfDocumentHidden = () => {\n if (document.visibilityState === 'hidden') {\n this.stopAllCameras();\n }\n };\n const hasDocumentVisibility =\n typeof document !== 'undefined' &&\n typeof document.addEventListener === 'function';\n if (hasDocumentVisibility) {\n document.addEventListener('visibilitychange', stopIfDocumentHidden);\n }\n\n this.cleanupFuncs.push(\n this.world.visibilityState.subscribe((state) => {\n if (state === VisibilityState.Hidden) {\n this.stopAllCameras();\n }\n }),\n this.queries.cameras.subscribe('disqualify', (entity) => {\n this.stopCamera(entity);\n }),\n () => {\n if (hasDocumentVisibility) {\n document.removeEventListener(\n 'visibilitychange',\n stopIfDocumentHidden,\n );\n }\n this.stopAllCameras();\n },\n );\n }\n\n update() {\n // CameraSource uses browser media APIs and works outside immersive XR.\n const documentHidden =\n typeof document !== 'undefined' && document.visibilityState === 'hidden';\n if (\n documentHidden ||\n this.world.visibilityState.value === VisibilityState.Hidden\n ) {\n return;\n }\n\n for (const entity of this.queries.cameras.entities) {\n const state = entity.getValue(CameraSource, 'state') as CameraStateType;\n\n // Error is terminal until callers explicitly set the source inactive.\n if (state === CameraState.Inactive) {\n this.startCamera(entity);\n }\n }\n }\n\n /**\n * Start camera stream for an entity\n * Async operation - sets state to Starting, then Active when complete\n * Users should check state or null-check texture/videoElement before using\n *\n * Checks an operation generation after each async operation so a restarted\n * camera cannot be overwritten by an older request that resolves later.\n */\n private async startCamera(entity: Entity) {\n const operationId = this.beginOperation(entity);\n this.releaseCameraResources(entity);\n\n // Set state to Starting to prevent duplicate attempts\n entity.setValue(CameraSource, 'state', CameraState.Starting);\n let stream: MediaStream | null = null;\n let video: HTMLVideoElement | null = null;\n let texture: VideoTexture | null = null;\n\n try {\n let deviceId = entity.getValue(CameraSource, 'deviceId') as string;\n\n // Auto-select camera if no deviceId provided\n if (!deviceId) {\n const devices = await CameraUtils.getDevices();\n\n if (!this.isCurrentStart(entity, operationId)) {\n return; // Aborted\n }\n\n const facing = entity.getValue(\n CameraSource,\n 'facing',\n ) as CameraFacingType;\n\n if (facing === CameraFacing.Unknown) {\n // Unknown = any camera is fine, use first available\n if (devices.length > 0) {\n deviceId = devices[0].deviceId;\n entity.setValue(CameraSource, 'deviceId', deviceId);\n } else {\n console.error('No cameras available');\n entity.setValue(CameraSource, 'state', CameraState.Error);\n return;\n }\n } else {\n // Specific facing requested - must match or fail\n const selected = CameraUtils.findByFacing(devices, facing);\n\n if (selected) {\n deviceId = selected.deviceId;\n entity.setValue(CameraSource, 'deviceId', deviceId);\n } else {\n const facingStr = facing === CameraFacing.Back ? 'back' : 'front';\n console.error(\n `No ${facingStr}-facing camera available (found ${devices.length} camera(s))`,\n );\n entity.setValue(CameraSource, 'state', CameraState.Error);\n return;\n }\n }\n }\n\n // Get stream constraints\n const width = entity.getValue(CameraSource, 'width');\n const height = entity.getValue(CameraSource, 'height');\n const frameRate = entity.getValue(CameraSource, 'frameRate');\n\n // Request camera stream\n stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: { exact: deviceId },\n width: { ideal: width as number | undefined },\n height: { ideal: height as number | undefined },\n frameRate: { ideal: frameRate as number | undefined },\n },\n });\n\n if (!this.isCurrentStart(entity, operationId)) {\n // Aborted - clean up the stream we just created\n this.cleanupCameraResources(stream, null, null);\n return;\n }\n\n // Create video element\n const createdVideo = document.createElement('video');\n video = createdVideo;\n createdVideo.setAttribute('playsinline', '');\n createdVideo.setAttribute('autoplay', '');\n createdVideo.muted = true;\n createdVideo.srcObject = stream;\n\n // Wait for video to be ready\n await new Promise<void>((resolve, reject) => {\n const onCanPlay = () => {\n createdVideo.removeEventListener('canplay', onCanPlay);\n createdVideo.removeEventListener('error', onError);\n resolve();\n };\n\n const onError = (error: Event) => {\n createdVideo.removeEventListener('canplay', onCanPlay);\n createdVideo.removeEventListener('error', onError);\n reject(error);\n };\n\n createdVideo.addEventListener('canplay', onCanPlay);\n createdVideo.addEventListener('error', onError);\n });\n\n if (!this.isCurrentStart(entity, operationId)) {\n // Aborted - clean up everything\n this.cleanupCameraResources(stream, video, null);\n return;\n }\n\n // Start playback\n await createdVideo.play();\n\n // Create VideoTexture\n texture = new VideoTexture(createdVideo);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n\n if (!this.isCurrentStart(entity, operationId)) {\n // Aborted at the last moment - clean up everything\n this.cleanupCameraResources(stream, video, texture);\n return;\n }\n\n // Commit all resources atomically\n entity.setValue(CameraSource, 'stream', stream);\n entity.setValue(CameraSource, 'videoElement', video);\n entity.setValue(CameraSource, 'texture', texture);\n entity.setValue(CameraSource, 'state', CameraState.Active);\n } catch (error) {\n this.cleanupCameraResources(stream, video, texture);\n if (this.isCurrentStart(entity, operationId)) {\n console.error('Failed to start camera:', error);\n entity.setValue(CameraSource, 'stream', null);\n entity.setValue(CameraSource, 'videoElement', null);\n entity.setValue(CameraSource, 'texture', null);\n entity.setValue(CameraSource, 'state', CameraState.Error);\n }\n }\n }\n\n /**\n * Stop camera stream for an entity\n */\n private stopCamera(entity: Entity) {\n this.beginOperation(entity);\n this.releaseCameraResources(entity);\n entity.setValue(CameraSource, 'state', CameraState.Inactive);\n }\n\n private releaseCameraResources(entity: Entity): void {\n const stream = entity.getValue(\n CameraSource,\n 'stream',\n ) as MediaStream | null;\n const video = entity.getValue(\n CameraSource,\n 'videoElement',\n ) as HTMLVideoElement | null;\n const texture = entity.getValue(\n CameraSource,\n 'texture',\n ) as VideoTexture | null;\n\n this.cleanupCameraResources(stream, video, texture);\n\n entity.setValue(CameraSource, 'stream', null);\n entity.setValue(CameraSource, 'videoElement', null);\n entity.setValue(CameraSource, 'texture', null);\n }\n\n private stopAllCameras(): void {\n for (const entity of this.queries.cameras.entities) {\n this.stopCamera(entity);\n }\n }\n\n private beginOperation(entity: Entity): number {\n const operationId = (this.operationIds.get(entity) ?? 0) + 1;\n this.operationIds.set(entity, operationId);\n return operationId;\n }\n\n private isCurrentStart(entity: Entity, operationId: number): boolean {\n return (\n this.operationIds.get(entity) === operationId &&\n entity.getValue(CameraSource, 'state') === CameraState.Starting\n );\n }\n\n /**\n * Clean up camera resources (stream, video element, texture)\n */\n private cleanupCameraResources(\n stream: MediaStream | null,\n video: HTMLVideoElement | null,\n texture: VideoTexture | null,\n ) {\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (video) {\n video.pause();\n video.srcObject = null;\n }\n if (texture) {\n texture.dispose();\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -35,6 +35,11 @@ export declare class CameraUtils {
35
35
  * Check if camera permission is granted (doesn't request)
36
36
  */
37
37
  static hasPermission(): Promise<boolean>;
38
+ /**
39
+ * Restart a camera source after changing its configuration or handling an
40
+ * error. CameraSystem releases the previous resources before starting again.
41
+ */
42
+ static restart(entity: Entity): void;
38
43
  /**
39
44
  * Capture current video frame as a canvas
40
45
  * Returns canvas at full video resolution, ready for processing
@@ -1 +1 @@
1
- {"version":3,"file":"camera-utils.d.ts","sourceRoot":"","sources":["../../src/camera/camera-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAmC;IAE/D;;;;;;;;;;;;;OAaG;WACU,UAAU,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAoDrE;;OAEG;IACH,MAAM,CAAC,YAAY,CACjB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,MAAM,EAAE,gBAAgB,GACvB,gBAAgB,GAAG,IAAI;IAI1B;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAY9C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;CA+B9D"}
1
+ {"version":3,"file":"camera-utils.d.ts","sourceRoot":"","sources":["../../src/camera/camera-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAmC;IAE/D;;;;;;;;;;;;;OAaG;WACU,UAAU,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAoDrE;;OAEG;IACH,MAAM,CAAC,YAAY,CACjB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,MAAM,EAAE,gBAAgB,GACvB,gBAAgB,GAAG,IAAI;IAI1B;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAY9C;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;CA+B9D"}
@@ -1,5 +1,5 @@
1
1
  import { CameraSource } from './camera-source.js';
2
- import { CameraFacing } from './types.js';
2
+ import { CameraFacing, CameraState } from './types.js';
3
3
 
4
4
  /**
5
5
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -89,6 +89,13 @@ class CameraUtils {
89
89
  return false;
90
90
  }
91
91
  }
92
+ /**
93
+ * Restart a camera source after changing its configuration or handling an
94
+ * error. CameraSystem releases the previous resources before starting again.
95
+ */
96
+ static restart(entity) {
97
+ entity.setValue(CameraSource, 'state', CameraState.Inactive);
98
+ }
92
99
  /**
93
100
  * Capture current video frame as a canvas
94
101
  * Returns canvas at full video resolution, ready for processing
@@ -1 +1 @@
1
- {"version":3,"file":"camera-utils.js","sources":["../../src/camera/camera-utils.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"camera-utils.js","sources":["../../src/camera/camera-utils.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { Entity } from '../ecs/entity.js';\nimport { CameraSource } from './camera-source.js';\nimport {\n CameraFacing,\n CameraState,\n type CameraDeviceInfo,\n type CameraFacingType,\n} from './types.js';\n\n/**\n * CameraUtils - Static utilities for camera discovery and selection\n * Handles permission requests and device enumeration with caching\n */\nexport class CameraUtils {\n private static cachedDevices: CameraDeviceInfo[] | null = null;\n\n /**\n * Get available camera devices\n *\n * On first call or if refresh=true:\n * - Requests camera permission (if not granted)\n * - Enumerates all video input devices\n * - Caches results for subsequent calls\n *\n * On subsequent calls with refresh=false:\n * - Returns cached results immediately\n *\n * @param refresh - Force re-enumeration (useful for hot-plugged devices)\n * @returns Array of available camera devices\n */\n static async getDevices(refresh = false): Promise<CameraDeviceInfo[]> {\n // Return cache if available and not forcing refresh\n if (this.cachedDevices && !refresh) {\n return this.cachedDevices;\n }\n\n try {\n // Request permission by getting a temporary stream\n const tempStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n\n // Immediately stop the stream - we just needed permission\n tempStream.getTracks().forEach((track) => track.stop());\n\n // Enumerate all video devices\n const devices = await navigator.mediaDevices.enumerateDevices();\n const videoDevices = devices.filter((d) => d.kind === 'videoinput');\n\n // Map to our interface with facing detection\n this.cachedDevices = videoDevices.map((device) => {\n const label = device.label.toLowerCase();\n let facing: CameraFacingType = CameraFacing.Unknown;\n\n if (\n label.includes('back') ||\n label.includes('environment') ||\n label.includes('rear')\n ) {\n facing = CameraFacing.Back;\n } else if (\n label.includes('front') ||\n label.includes('user') ||\n label.includes('face')\n ) {\n facing = CameraFacing.Front;\n }\n\n return {\n deviceId: device.deviceId,\n label: device.label,\n facing,\n };\n });\n\n return this.cachedDevices;\n } catch (error) {\n console.error('Failed to enumerate camera devices:', error);\n throw error;\n }\n }\n\n /**\n * Find camera by facing direction from device list\n */\n static findByFacing(\n devices: CameraDeviceInfo[],\n facing: CameraFacingType,\n ): CameraDeviceInfo | null {\n return devices.find((d) => d.facing === facing) || null;\n }\n\n /**\n * Check if camera permission is granted (doesn't request)\n */\n static async hasPermission(): Promise<boolean> {\n try {\n const result = await navigator.permissions.query({\n name: 'camera' as PermissionName,\n });\n return result.state === 'granted';\n } catch {\n // Permissions API not supported\n return false;\n }\n }\n\n /**\n * Restart a camera source after changing its configuration or handling an\n * error. CameraSystem releases the previous resources before starting again.\n */\n static restart(entity: Entity): void {\n entity.setValue(CameraSource, 'state', CameraState.Inactive);\n }\n\n /**\n * Capture current video frame as a canvas\n * Returns canvas at full video resolution, ready for processing\n *\n * @param entity - Entity with CameraSource component\n * @returns HTMLCanvasElement or null if camera not ready\n *\n * @example\n * // Simple texture creation\n * const canvas = CameraUtils.captureFrame(cameraEntity);\n * if (canvas) {\n * const texture = new CanvasTexture(canvas);\n * }\n *\n * @example\n * // With post-processing\n * const canvas = CameraUtils.captureFrame(cameraEntity);\n * if (canvas) {\n * const ctx = canvas.getContext('2d');\n * ctx.filter = 'blur(2px)';\n * const texture = new CanvasTexture(canvas);\n * }\n */\n static captureFrame(entity: Entity): HTMLCanvasElement | null {\n // Get video element from CameraSource component\n const videoElement = entity.getValue(\n CameraSource,\n 'videoElement',\n ) as HTMLVideoElement | null;\n\n if (!videoElement) {\n return null;\n }\n\n // Validate video has valid dimensions\n if (videoElement.videoWidth === 0 || videoElement.videoHeight === 0) {\n return null;\n }\n\n // Create canvas at video resolution\n const canvas = document.createElement('canvas');\n canvas.width = videoElement.videoWidth;\n canvas.height = videoElement.videoHeight;\n\n // Draw current video frame to canvas\n const ctx = canvas.getContext('2d', { colorSpace: 'srgb' });\n if (!ctx) {\n return null;\n }\n\n ctx.drawImage(videoElement, 0, 0);\n\n return canvas;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../src/camera/types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;AAKG;AAEI,MAAM,YAAY,GAAG;AAC1B,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,OAAO,EAAE,SAAS;;AAWpB;;AAEG;AACI,MAAM,WAAW,GAAG;IACzB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;;;;;"}
1
+ {"version":3,"file":"types.js","sources":["../../src/camera/types.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nexport const CameraFacing = {\n Back: 'back',\n Front: 'front',\n Unknown: 'unknown',\n} as const;\n\nexport type CameraFacingType = (typeof CameraFacing)[keyof typeof CameraFacing];\n\nexport interface CameraDeviceInfo {\n deviceId: string;\n label: string;\n facing: CameraFacingType;\n}\n\n/**\n * Camera stream state lifecycle\n */\nexport const CameraState = {\n Inactive: 'inactive', // Not started\n Starting: 'starting', // Async initialization in progress\n Active: 'active', // Stream running\n Error: 'error', // Failed to start\n} as const;\n\nexport type CameraStateType = (typeof CameraState)[keyof typeof CameraState];\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAEI,MAAM,YAAY,GAAG;AAC1B,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,OAAO,EAAE,SAAS;;AAWpB;;AAEG;AACI,MAAM,WAAW,GAAG;IACzB,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"depth-occludable.js","sources":["../../src/depth/depth-occludable.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;AAKG;AAGH;AACO,MAAM,oBAAoB,GAAG;;AAElC,IAAA,aAAa,EAAE,eAAe;;AAE9B,IAAA,aAAa,EAAE,eAAe;;AAE9B,IAAA,mBAAmB,EAAE,qBAAqB;;AAG5C;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,eAAe,GAAG,eAAe,CAC5C,iBAAiB,EACjB;AACE,IAAA,IAAI,EAAE;QACJ,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,oBAAoB,CAAC,aAAa;AAC5C,KAAA;CACF,EACD,iDAAiD;;;;"}
1
+ {"version":3,"file":"depth-occludable.js","sources":["../../src/depth/depth-occludable.ts"],"sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { Types, createComponent } from '../ecs/component.js';\n/** Occlusion shader mode for {@link DepthOccludable}. @category Depth Sensing */\nexport const OcclusionShadersMode = {\n /** Soft occlusion with 13-tap blur sampling for smooth edges. */\n SoftOcclusion: 'SoftOcclusion',\n /** Hard occlusion with a single depth sample per fragment. */\n HardOcclusion: 'HardOcclusion',\n /** MinMax soft occlusion with depth preprocessing for edge-aware smooth edges. */\n MinMaxSoftOcclusion: 'MinMaxSoftOcclusion',\n};\n\n/**\n * Component for entities that should be occluded by real-world depth.\n * Add this component to entities that should be hidden when behind real-world surfaces.\n * NOTE: The depth occlusion feature may not be compatible with custom shaders.\n *\n * @example\n * ```ts\n * // Create an entity with soft occlusion (default)\n * const entity = world.createTransformEntity(mesh);\n * entity.addComponent(DepthOccludable);\n *\n * // Create an entity with hard occlusion (no blur)\n * entity.addComponent(DepthOccludable, { mode: OcclusionShadersMode.HardOcclusion });\n * ```\n *\n * @category Depth Sensing\n */\nexport const DepthOccludable = createComponent(\n 'DepthOccludable',\n {\n mode: {\n type: Types.Enum,\n enum: OcclusionShadersMode,\n default: OcclusionShadersMode.SoftOcclusion,\n },\n },\n 'Entity that can be occluded by real-world depth',\n);\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAGH;AACO,MAAM,oBAAoB,GAAG;;AAElC,IAAA,aAAa,EAAE,eAAe;;AAE9B,IAAA,aAAa,EAAE,eAAe;;AAE9B,IAAA,mBAAmB,EAAE,qBAAqB;;AAG5C;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,eAAe,GAAG,eAAe,CAC5C,iBAAiB,EACjB;AACE,IAAA,IAAI,EAAE;QACJ,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,QAAA,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,oBAAoB,CAAC,aAAa;AAC5C,KAAA;CACF,EACD,iDAAiD;;;;"}
@@ -107,6 +107,7 @@ export declare class DepthSensingSystem extends DepthSensingSystem_base {
107
107
  private depthFeatureEnabled;
108
108
  cpuDepthData: XRCPUDepthInformation[];
109
109
  gpuDepthData: XRWebGLDepthInformation[];
110
+ private hasCurrentFrameDepthData;
110
111
  private depthTextures?;
111
112
  private entityShaderMap;
112
113
  private readonly viewportSize;
@@ -123,6 +124,8 @@ export declare class DepthSensingSystem extends DepthSensingSystem_base {
123
124
  */
124
125
  private attachOcclusionToEntity;
125
126
  private detachOcclusionFromEntity;
127
+ private clearOcclusionUniforms;
128
+ private clearAllOcclusionUniforms;
126
129
  /**
127
130
  * Modifies a material's shader in-place to incorporate inline depth-based
128
131
  * occlusion. Compares the virtual fragment's view-space depth against the
@@ -1 +1 @@
1
- {"version":3,"file":"depth-sensing-system.d.ts","sourceRoot":"","sources":["../../src/depth/depth-sensing-system.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiB5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,kBAAmB,SAAQ,uBAUvC;IACC,OAAO,CAAC,mBAAmB,CAAsB;IAGjD,YAAY,EAAE,qBAAqB,EAAE,CAAM;IAC3C,YAAY,EAAE,uBAAuB,EAAE,CAAM;IAC7C,OAAO,CAAC,aAAa,CAAC,CAAgB;IAGtC,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiB;IAC9C,OAAO,CAAC,iBAAiB,CAAC,CAAyB;IACnD,OAAO,CAAC,iBAAiB,CAAK;IAE9B;;OAEG;IACH,IAAI,gBAAgB,IAAI,MAAM,CAO7B;IAED,IAAI,IAAI,IAAI;IAiEZ,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAwC/B,OAAO,CAAC,yBAAyB;IAIjC;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAsInC,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,qBAAqB;IAe7B,MAAM,IAAI,IAAI;IAgBd;;;;OAIG;IACH,OAAO,KAAK,UAAU,GAGrB;IAED,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,sBAAsB;IA8C9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;CAuChC"}
1
+ {"version":3,"file":"depth-sensing-system.d.ts","sourceRoot":"","sources":["../../src/depth/depth-sensing-system.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiB5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,kBAAmB,SAAQ,uBAUvC;IACC,OAAO,CAAC,mBAAmB,CAAsB;IAGjD,YAAY,EAAE,qBAAqB,EAAE,CAAM;IAC3C,YAAY,EAAE,uBAAuB,EAAE,CAAM;IAC7C,OAAO,CAAC,wBAAwB,CAAS;IACzC,OAAO,CAAC,aAAa,CAAC,CAAgB;IAGtC,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiB;IAC9C,OAAO,CAAC,iBAAiB,CAAC,CAAyB;IACnD,OAAO,CAAC,iBAAiB,CAAK;IAE9B;;OAEG;IACH,IAAI,gBAAgB,IAAI,MAAM,CAO7B;IAED,IAAI,IAAI,IAAI;IAmEZ,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAwC/B,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,yBAAyB;IAMjC;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAsInC,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,qBAAqB;IAe7B,MAAM,IAAI,IAAI;IA8Bd;;;;OAIG;IACH,OAAO,KAAK,UAAU,GAGrB;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,sBAAsB;IA8C9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA4CxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAW1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;CAwChC"}