@cavegiant/cave-world-r3f 1.0.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.
Files changed (339) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +189 -0
  4. package/dist/core/connector-label/readiness.d.ts +11 -0
  5. package/dist/core/connector-label/readiness.d.ts.map +1 -0
  6. package/dist/core/connector-label/readiness.js +31 -0
  7. package/dist/core/connector-label/readiness.js.map +1 -0
  8. package/dist/core/connector-label/types.d.ts +64 -0
  9. package/dist/core/connector-label/types.d.ts.map +1 -0
  10. package/dist/core/connector-label/types.js +47 -0
  11. package/dist/core/connector-label/types.js.map +1 -0
  12. package/dist/core/context/cave-world-context.d.ts +96 -0
  13. package/dist/core/context/cave-world-context.d.ts.map +1 -0
  14. package/dist/core/context/cave-world-context.js +100 -0
  15. package/dist/core/context/cave-world-context.js.map +1 -0
  16. package/dist/core/errors.d.ts +34 -0
  17. package/dist/core/errors.d.ts.map +1 -0
  18. package/dist/core/errors.js +17 -0
  19. package/dist/core/errors.js.map +1 -0
  20. package/dist/core/events/event-bus.d.ts +122 -0
  21. package/dist/core/events/event-bus.d.ts.map +1 -0
  22. package/dist/core/events/event-bus.js +62 -0
  23. package/dist/core/events/event-bus.js.map +1 -0
  24. package/dist/core/hooks/use-cave-event.d.ts +13 -0
  25. package/dist/core/hooks/use-cave-event.d.ts.map +1 -0
  26. package/dist/core/hooks/use-cave-event.js +12 -0
  27. package/dist/core/hooks/use-cave-event.js.map +1 -0
  28. package/dist/core/i18n/messages.d.ts +82 -0
  29. package/dist/core/i18n/messages.d.ts.map +1 -0
  30. package/dist/core/i18n/messages.js +131 -0
  31. package/dist/core/i18n/messages.js.map +1 -0
  32. package/dist/core/index.d.ts +11 -0
  33. package/dist/core/index.d.ts.map +1 -0
  34. package/dist/core/index.js +47 -0
  35. package/dist/core/index.js.map +1 -0
  36. package/dist/core/logging/logger.d.ts +29 -0
  37. package/dist/core/logging/logger.d.ts.map +1 -0
  38. package/dist/core/logging/logger.js +47 -0
  39. package/dist/core/logging/logger.js.map +1 -0
  40. package/dist/core/registry/component-registry.d.ts +41 -0
  41. package/dist/core/registry/component-registry.d.ts.map +1 -0
  42. package/dist/core/registry/component-registry.js +34 -0
  43. package/dist/core/registry/component-registry.js.map +1 -0
  44. package/dist/core/registry/object-registry.d.ts +38 -0
  45. package/dist/core/registry/object-registry.d.ts.map +1 -0
  46. package/dist/core/registry/object-registry.js +32 -0
  47. package/dist/core/registry/object-registry.js.map +1 -0
  48. package/dist/explore/cave-explore.d.ts +85 -0
  49. package/dist/explore/cave-explore.d.ts.map +1 -0
  50. package/dist/explore/cave-explore.js +204 -0
  51. package/dist/explore/cave-explore.js.map +1 -0
  52. package/dist/explore/cave-orbit-viewer.d.ts +76 -0
  53. package/dist/explore/cave-orbit-viewer.d.ts.map +1 -0
  54. package/dist/explore/cave-orbit-viewer.js +123 -0
  55. package/dist/explore/cave-orbit-viewer.js.map +1 -0
  56. package/dist/explore/characters/character-configs.d.ts +38 -0
  57. package/dist/explore/characters/character-configs.d.ts.map +1 -0
  58. package/dist/explore/characters/character-configs.js +45 -0
  59. package/dist/explore/characters/character-configs.js.map +1 -0
  60. package/dist/explore/characters/character-controls.d.ts +44 -0
  61. package/dist/explore/characters/character-controls.d.ts.map +1 -0
  62. package/dist/explore/characters/character-pose.d.ts +19 -0
  63. package/dist/explore/characters/character-pose.d.ts.map +1 -0
  64. package/dist/explore/characters/character-pose.js +13 -0
  65. package/dist/explore/characters/character-pose.js.map +1 -0
  66. package/dist/explore/characters/local-character-model.d.ts +53 -0
  67. package/dist/explore/characters/local-character-model.d.ts.map +1 -0
  68. package/dist/explore/characters/local-character-model.js +36 -0
  69. package/dist/explore/characters/local-character-model.js.map +1 -0
  70. package/dist/explore/characters/mixamo-style-bone-map.d.ts +9 -0
  71. package/dist/explore/characters/mixamo-style-bone-map.d.ts.map +1 -0
  72. package/dist/explore/characters/mixamo-style-bone-map.js +28 -0
  73. package/dist/explore/characters/mixamo-style-bone-map.js.map +1 -0
  74. package/dist/explore/characters/remote-character-controller.d.ts +38 -0
  75. package/dist/explore/characters/remote-character-controller.d.ts.map +1 -0
  76. package/dist/explore/characters/remote-character-controller.js +135 -0
  77. package/dist/explore/characters/remote-character-controller.js.map +1 -0
  78. package/dist/explore/characters/remote-character.d.ts +19 -0
  79. package/dist/explore/characters/remote-character.d.ts.map +1 -0
  80. package/dist/explore/characters/remote-character.js +63 -0
  81. package/dist/explore/characters/remote-character.js.map +1 -0
  82. package/dist/explore/connected-spaces-renderer.d.ts +16 -0
  83. package/dist/explore/connected-spaces-renderer.d.ts.map +1 -0
  84. package/dist/explore/connected-spaces-renderer.js +103 -0
  85. package/dist/explore/connected-spaces-renderer.js.map +1 -0
  86. package/dist/explore/hooks/use-action-shortcuts.d.ts +16 -0
  87. package/dist/explore/hooks/use-action-shortcuts.d.ts.map +1 -0
  88. package/dist/explore/hooks/use-action-shortcuts.js +23 -0
  89. package/dist/explore/hooks/use-action-shortcuts.js.map +1 -0
  90. package/dist/explore/hooks/use-active-space-notify.d.ts +11 -0
  91. package/dist/explore/hooks/use-active-space-notify.d.ts.map +1 -0
  92. package/dist/explore/hooks/use-active-space-notify.js +17 -0
  93. package/dist/explore/hooks/use-active-space-notify.js.map +1 -0
  94. package/dist/explore/hooks/use-character-sync.d.ts +46 -0
  95. package/dist/explore/hooks/use-character-sync.d.ts.map +1 -0
  96. package/dist/explore/hooks/use-character-sync.js +72 -0
  97. package/dist/explore/hooks/use-character-sync.js.map +1 -0
  98. package/dist/explore/hooks/use-connector-preloader.d.ts +20 -0
  99. package/dist/explore/hooks/use-connector-preloader.d.ts.map +1 -0
  100. package/dist/explore/hooks/use-connector-preloader.js +78 -0
  101. package/dist/explore/hooks/use-connector-preloader.js.map +1 -0
  102. package/dist/explore/hooks/use-connector-transitions.d.ts +31 -0
  103. package/dist/explore/hooks/use-connector-transitions.d.ts.map +1 -0
  104. package/dist/explore/hooks/use-connector-transitions.js +63 -0
  105. package/dist/explore/hooks/use-connector-transitions.js.map +1 -0
  106. package/dist/explore/hooks/use-explore-actions.d.ts +17 -0
  107. package/dist/explore/hooks/use-explore-actions.d.ts.map +1 -0
  108. package/dist/explore/hooks/use-explore-actions.js +134 -0
  109. package/dist/explore/hooks/use-explore-actions.js.map +1 -0
  110. package/dist/explore/hooks/use-load-error-notify.d.ts +11 -0
  111. package/dist/explore/hooks/use-load-error-notify.d.ts.map +1 -0
  112. package/dist/explore/hooks/use-load-error-notify.js +18 -0
  113. package/dist/explore/hooks/use-load-error-notify.js.map +1 -0
  114. package/dist/explore/hooks/use-primary-space-loader.d.ts +24 -0
  115. package/dist/explore/hooks/use-primary-space-loader.d.ts.map +1 -0
  116. package/dist/explore/hooks/use-primary-space-loader.js +29 -0
  117. package/dist/explore/hooks/use-primary-space-loader.js.map +1 -0
  118. package/dist/explore/index.d.ts +37 -0
  119. package/dist/explore/index.d.ts.map +1 -0
  120. package/dist/explore/index.js +107 -0
  121. package/dist/explore/index.js.map +1 -0
  122. package/dist/explore/loaders/cave-loader.d.ts +58 -0
  123. package/dist/explore/loaders/cave-loader.d.ts.map +1 -0
  124. package/dist/explore/loaders/cave-loader.js +79 -0
  125. package/dist/explore/loaders/cave-loader.js.map +1 -0
  126. package/dist/explore/math/space-transforms.d.ts +49 -0
  127. package/dist/explore/math/space-transforms.d.ts.map +1 -0
  128. package/dist/explore/math/space-transforms.js +54 -0
  129. package/dist/explore/math/space-transforms.js.map +1 -0
  130. package/dist/explore/overlays/action-bubble.d.ts +8 -0
  131. package/dist/explore/overlays/action-bubble.d.ts.map +1 -0
  132. package/dist/explore/overlays/action-bubble.js +18 -0
  133. package/dist/explore/overlays/action-bubble.js.map +1 -0
  134. package/dist/explore/overlays/action-panel.d.ts +12 -0
  135. package/dist/explore/overlays/action-panel.d.ts.map +1 -0
  136. package/dist/explore/overlays/action-panel.js +69 -0
  137. package/dist/explore/overlays/action-panel.js.map +1 -0
  138. package/dist/explore/overlays/connector-label-beacon.d.ts +11 -0
  139. package/dist/explore/overlays/connector-label-beacon.d.ts.map +1 -0
  140. package/dist/explore/overlays/connector-label-beacon.js +38 -0
  141. package/dist/explore/overlays/connector-label-beacon.js.map +1 -0
  142. package/dist/explore/overlays/connector-label-tag-shell.d.ts +16 -0
  143. package/dist/explore/overlays/connector-label-tag-shell.d.ts.map +1 -0
  144. package/dist/explore/overlays/connector-label-tag-shell.js +18 -0
  145. package/dist/explore/overlays/connector-label-tag-shell.js.map +1 -0
  146. package/dist/explore/overlays/detail-window.d.ts +9 -0
  147. package/dist/explore/overlays/detail-window.d.ts.map +1 -0
  148. package/dist/explore/overlays/detail-window.js +92 -0
  149. package/dist/explore/overlays/detail-window.js.map +1 -0
  150. package/dist/explore/overlays/explore-helper.d.ts +44 -0
  151. package/dist/explore/overlays/explore-helper.d.ts.map +1 -0
  152. package/dist/explore/overlays/explore-helper.js +57 -0
  153. package/dist/explore/overlays/explore-helper.js.map +1 -0
  154. package/dist/explore/overlays/icons.d.ts +16 -0
  155. package/dist/explore/overlays/icons.d.ts.map +1 -0
  156. package/dist/explore/overlays/icons.js +34 -0
  157. package/dist/explore/overlays/icons.js.map +1 -0
  158. package/dist/explore/overlays/space-load-error-overlay.d.ts +27 -0
  159. package/dist/explore/overlays/space-load-error-overlay.d.ts.map +1 -0
  160. package/dist/explore/overlays/space-load-error-overlay.js +24 -0
  161. package/dist/explore/overlays/space-load-error-overlay.js.map +1 -0
  162. package/dist/explore/services/websocket.service.d.ts +180 -0
  163. package/dist/explore/services/websocket.service.d.ts.map +1 -0
  164. package/dist/explore/services/websocket.service.js +187 -0
  165. package/dist/explore/services/websocket.service.js.map +1 -0
  166. package/dist/explore/simple-character.d.ts +46 -0
  167. package/dist/explore/simple-character.d.ts.map +1 -0
  168. package/dist/explore/simple-character.js +119 -0
  169. package/dist/explore/simple-character.js.map +1 -0
  170. package/dist/explore/stores/action-prompt.store.d.ts +27 -0
  171. package/dist/explore/stores/action-prompt.store.d.ts.map +1 -0
  172. package/dist/explore/stores/action-prompt.store.js +14 -0
  173. package/dist/explore/stores/action-prompt.store.js.map +1 -0
  174. package/dist/explore/stores/cave-explore.store.d.ts +77 -0
  175. package/dist/explore/stores/cave-explore.store.d.ts.map +1 -0
  176. package/dist/explore/stores/cave-explore.store.js +66 -0
  177. package/dist/explore/stores/cave-explore.store.js.map +1 -0
  178. package/dist/explore/stores/explore-context.d.ts +35 -0
  179. package/dist/explore/stores/explore-context.d.ts.map +1 -0
  180. package/dist/explore/stores/explore-context.js +43 -0
  181. package/dist/explore/stores/explore-context.js.map +1 -0
  182. package/dist/explore/styles/cave-world-css.d.ts +10 -0
  183. package/dist/explore/styles/cave-world-css.d.ts.map +1 -0
  184. package/dist/explore/styles/cave-world-css.js +935 -0
  185. package/dist/explore/styles/cave-world-css.js.map +1 -0
  186. package/dist/explore/styles/inject.d.ts +32 -0
  187. package/dist/explore/styles/inject.d.ts.map +1 -0
  188. package/dist/explore/styles/inject.js +40 -0
  189. package/dist/explore/styles/inject.js.map +1 -0
  190. package/dist/explore/utils/schedule-idle.d.ts +12 -0
  191. package/dist/explore/utils/schedule-idle.d.ts.map +1 -0
  192. package/dist/explore/utils/schedule-idle.js +16 -0
  193. package/dist/explore/utils/schedule-idle.js.map +1 -0
  194. package/dist/explore/viewer-shared.d.ts +56 -0
  195. package/dist/explore/viewer-shared.d.ts.map +1 -0
  196. package/dist/index.d.ts +16 -0
  197. package/dist/index.d.ts.map +1 -0
  198. package/dist/index.js +78 -0
  199. package/dist/index.js.map +1 -0
  200. package/dist/space/cave-base-layer.d.ts +42 -0
  201. package/dist/space/cave-base-layer.d.ts.map +1 -0
  202. package/dist/space/cave-base-layer.js +221 -0
  203. package/dist/space/cave-base-layer.js.map +1 -0
  204. package/dist/space/cave-custom-layer.d.ts +12 -0
  205. package/dist/space/cave-custom-layer.d.ts.map +1 -0
  206. package/dist/space/cave-custom-layer.js +17 -0
  207. package/dist/space/cave-custom-layer.js.map +1 -0
  208. package/dist/space/cave-env.d.ts +6 -0
  209. package/dist/space/cave-env.d.ts.map +1 -0
  210. package/dist/space/cave-env.js +23 -0
  211. package/dist/space/cave-env.js.map +1 -0
  212. package/dist/space/cave-space.d.ts +46 -0
  213. package/dist/space/cave-space.d.ts.map +1 -0
  214. package/dist/space/cave-space.js +37 -0
  215. package/dist/space/cave-space.js.map +1 -0
  216. package/dist/space/connector-label-host.d.ts +21 -0
  217. package/dist/space/connector-label-host.d.ts.map +1 -0
  218. package/dist/space/connector-label-host.js +65 -0
  219. package/dist/space/connector-label-host.js.map +1 -0
  220. package/dist/space/index.d.ts +18 -0
  221. package/dist/space/index.d.ts.map +1 -0
  222. package/dist/space/index.js +47 -0
  223. package/dist/space/index.js.map +1 -0
  224. package/dist/space/objects/builtin-registrar.d.ts +17 -0
  225. package/dist/space/objects/builtin-registrar.d.ts.map +1 -0
  226. package/dist/space/objects/builtin-registrar.js +19 -0
  227. package/dist/space/objects/builtin-registrar.js.map +1 -0
  228. package/dist/space/objects/custom-object.d.ts +9 -0
  229. package/dist/space/objects/custom-object.d.ts.map +1 -0
  230. package/dist/space/objects/custom-object.js +56 -0
  231. package/dist/space/objects/custom-object.js.map +1 -0
  232. package/dist/space/objects/image-object.d.ts +7 -0
  233. package/dist/space/objects/image-object.d.ts.map +1 -0
  234. package/dist/space/objects/image-object.js +14 -0
  235. package/dist/space/objects/image-object.js.map +1 -0
  236. package/dist/space/objects/model-object/fbx-object.d.ts +8 -0
  237. package/dist/space/objects/model-object/fbx-object.d.ts.map +1 -0
  238. package/dist/space/objects/model-object/fbx-object.js +26 -0
  239. package/dist/space/objects/model-object/fbx-object.js.map +1 -0
  240. package/dist/space/objects/model-object/gltf-object.d.ts +9 -0
  241. package/dist/space/objects/model-object/gltf-object.d.ts.map +1 -0
  242. package/dist/space/objects/model-object/gltf-object.js +66 -0
  243. package/dist/space/objects/model-object/gltf-object.js.map +1 -0
  244. package/dist/space/objects/model-object/index.d.ts +9 -0
  245. package/dist/space/objects/model-object/index.d.ts.map +1 -0
  246. package/dist/space/objects/model-object/index.js +12 -0
  247. package/dist/space/objects/model-object/index.js.map +1 -0
  248. package/dist/space/objects/model-object/splat-object.d.ts +9 -0
  249. package/dist/space/objects/model-object/splat-object.d.ts.map +1 -0
  250. package/dist/space/objects/model-object/splat-object.js +19 -0
  251. package/dist/space/objects/model-object/splat-object.js.map +1 -0
  252. package/dist/space/objects/object-components/windows/index.d.ts +5 -0
  253. package/dist/space/objects/object-components/windows/index.d.ts.map +1 -0
  254. package/dist/space/objects/object-components/windows/index.js +20 -0
  255. package/dist/space/objects/object-components/windows/index.js.map +1 -0
  256. package/dist/space/objects/placeholder-object.d.ts +7 -0
  257. package/dist/space/objects/placeholder-object.d.ts.map +1 -0
  258. package/dist/space/objects/placeholder-object.js +12 -0
  259. package/dist/space/objects/placeholder-object.js.map +1 -0
  260. package/dist/space/objects/poi-object.d.ts +7 -0
  261. package/dist/space/objects/poi-object.d.ts.map +1 -0
  262. package/dist/space/objects/poi-object.js +38 -0
  263. package/dist/space/objects/poi-object.js.map +1 -0
  264. package/dist/space/objects/portal-object.d.ts +7 -0
  265. package/dist/space/objects/portal-object.d.ts.map +1 -0
  266. package/dist/space/objects/portal-object.js +84 -0
  267. package/dist/space/objects/portal-object.js.map +1 -0
  268. package/dist/space/objects/video-object.d.ts +7 -0
  269. package/dist/space/objects/video-object.d.ts.map +1 -0
  270. package/dist/space/objects/video-object.js +32 -0
  271. package/dist/space/objects/video-object.js.map +1 -0
  272. package/dist/space/polygon-boundary.d.ts +10 -0
  273. package/dist/space/polygon-boundary.d.ts.map +1 -0
  274. package/dist/space/polygon-boundary.js +205 -0
  275. package/dist/space/polygon-boundary.js.map +1 -0
  276. package/dist/space/splats/spark/robust-splat-mesh.d.ts +59 -0
  277. package/dist/space/splats/spark/robust-splat-mesh.d.ts.map +1 -0
  278. package/dist/space/splats/spark/robust-splat-mesh.js +105 -0
  279. package/dist/space/splats/spark/robust-splat-mesh.js.map +1 -0
  280. package/dist/space/splats/spark/splat-mesh.d.ts +5 -0
  281. package/dist/space/splats/spark/splat-mesh.d.ts.map +1 -0
  282. package/dist/space/splats/spark/splat-mesh.js +7 -0
  283. package/dist/space/splats/spark/splat-mesh.js.map +1 -0
  284. package/dist/space/splats/spark/splat-spread-reveal.d.ts +14 -0
  285. package/dist/space/splats/spark/splat-spread-reveal.d.ts.map +1 -0
  286. package/dist/space/splats/spark/splat-spread-reveal.js +45 -0
  287. package/dist/space/splats/spark/splat-spread-reveal.js.map +1 -0
  288. package/dist/space/utils/cave-world-player.d.ts +3 -0
  289. package/dist/space/utils/cave-world-player.d.ts.map +1 -0
  290. package/dist/space/utils/cave-world-player.js +5 -0
  291. package/dist/space/utils/cave-world-player.js.map +1 -0
  292. package/dist/space/utils/configure-canvas.d.ts +20 -0
  293. package/dist/space/utils/configure-canvas.d.ts.map +1 -0
  294. package/dist/space/utils/configure-canvas.js +12 -0
  295. package/dist/space/utils/configure-canvas.js.map +1 -0
  296. package/dist/space/utils/polygon-boundary-geometry.d.ts +8 -0
  297. package/dist/space/utils/polygon-boundary-geometry.d.ts.map +1 -0
  298. package/dist/space/utils/polygon-boundary-geometry.js +20 -0
  299. package/dist/space/utils/polygon-boundary-geometry.js.map +1 -0
  300. package/dist/space/utils/polygon-boundary-segments.d.ts +50 -0
  301. package/dist/space/utils/polygon-boundary-segments.d.ts.map +1 -0
  302. package/dist/space/utils/polygon-boundary-segments.js +64 -0
  303. package/dist/space/utils/polygon-boundary-segments.js.map +1 -0
  304. package/dist/space/utils/rotation-compat.d.ts +4 -0
  305. package/dist/space/utils/rotation-compat.d.ts.map +1 -0
  306. package/dist/space/utils/rotation-compat.js +9 -0
  307. package/dist/space/utils/rotation-compat.js.map +1 -0
  308. package/dist/space/utils/select-splat-level.d.ts +52 -0
  309. package/dist/space/utils/select-splat-level.d.ts.map +1 -0
  310. package/dist/space/utils/select-splat-level.js +43 -0
  311. package/dist/space/utils/select-splat-level.js.map +1 -0
  312. package/dist/space/utils/spark-performance.d.ts +10 -0
  313. package/dist/space/utils/spark-performance.d.ts.map +1 -0
  314. package/dist/space/utils/spark-performance.js +10 -0
  315. package/dist/space/utils/spark-performance.js.map +1 -0
  316. package/dist/space/utils/splat-collider-helper.d.ts +5 -0
  317. package/dist/space/utils/splat-collider-helper.d.ts.map +1 -0
  318. package/dist/space/utils/splat-collider-helper.js +162 -0
  319. package/dist/space/utils/splat-collider-helper.js.map +1 -0
  320. package/dist/space/utils/touch-primary-device.d.ts +16 -0
  321. package/dist/space/utils/touch-primary-device.d.ts.map +1 -0
  322. package/dist/space/utils/touch-primary-device.js +52 -0
  323. package/dist/space/utils/touch-primary-device.js.map +1 -0
  324. package/dist/space/utils/use-visibility-frameloop.d.ts +20 -0
  325. package/dist/space/utils/use-visibility-frameloop.d.ts.map +1 -0
  326. package/dist/space/utils/use-visibility-frameloop.js +18 -0
  327. package/dist/space/utils/use-visibility-frameloop.js.map +1 -0
  328. package/dist/styles.css +930 -0
  329. package/dist/types/index.d.ts +2 -0
  330. package/dist/types/index.d.ts.map +1 -0
  331. package/dist/types/index.js +2 -0
  332. package/dist/types/index.js.map +1 -0
  333. package/dist/types/space-types.d.ts +404 -0
  334. package/dist/types/space-types.d.ts.map +1 -0
  335. package/doc/API.md +617 -0
  336. package/doc/ARCHITECTURE.md +264 -0
  337. package/doc/multiplayer-protocol.md +757 -0
  338. package/doc/scene-json-structure.md +567 -0
  339. package/package.json +131 -0
@@ -0,0 +1,205 @@
1
+ import { jsx as o, jsxs as L } from "react/jsx-runtime";
2
+ import { BvhPhysicsSensor as Y } from "@react-three/viverse";
3
+ import { useFrame as P } from "@react-three/fiber";
4
+ import { useMemo as g, useEffect as _, useRef as f, useState as A, useCallback as x } from "react";
5
+ import { Vector3 as v, MeshBasicMaterial as $, AdditiveBlending as w, DoubleSide as G, ShaderMaterial as k } from "three";
6
+ import { useCaveEventBus as X } from "../core/context/cave-world-context.js";
7
+ import { buildPolygonBoundarySegments as U, findBoundaryContactAnchor as C, projectPlayerOntoSegmentWall as Z, boundaryContactAnchorToPosition as q } from "./utils/polygon-boundary-segments.js";
8
+ import { buildPolygonBoundaryColliderGeometry as O } from "./utils/polygon-boundary-geometry.js";
9
+ import { CAVE_WORLD_LOCAL_PLAYER_FLAG as z } from "./utils/cave-world-player.js";
10
+ const J = 0.08, K = 0.55, Q = 0.2, ee = 0.15, N = 2.6, ne = 0.6, te = /* @__PURE__ */ new $({ visible: !1 }), M = /* @__PURE__ */ new v(), u = /* @__PURE__ */ new v(), S = /* @__PURE__ */ new v(), T = /* @__PURE__ */ new v();
11
+ function re(e, i, t, s) {
12
+ if (!e.current?.parent) {
13
+ let l = null;
14
+ i.traverse((c) => {
15
+ l || c.userData?.[z] && (l = c);
16
+ }), e.current = l;
17
+ }
18
+ return e.current ? (e.current.getWorldPosition(s), s) : t.getWorldPosition(s);
19
+ }
20
+ function oe() {
21
+ return new k({
22
+ vertexShader: `
23
+ varying vec2 vUv;
24
+ void main() {
25
+ vUv = uv;
26
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
27
+ }
28
+ `,
29
+ fragmentShader: `
30
+ varying vec2 vUv;
31
+ void main() {
32
+ float gridScale = 18.0;
33
+ vec2 gridUv = vUv * gridScale;
34
+ vec2 grid = abs(fract(gridUv - 0.5) - 0.5) / fwidth(gridUv);
35
+ float line = min(grid.x, grid.y);
36
+ float gridLine = 1.0 - min(line, 1.0);
37
+ float alpha = mix(0.07, 0.2, gridLine);
38
+ gl_FragColor = vec4(0.52, 0.82, 0.98, alpha);
39
+ }
40
+ `,
41
+ transparent: !0,
42
+ depthWrite: !1,
43
+ side: G,
44
+ blending: w
45
+ });
46
+ }
47
+ const ie = `
48
+ varying vec2 vUv;
49
+ void main() {
50
+ vUv = uv;
51
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
52
+ }
53
+ `, le = `
54
+ uniform float uTime;
55
+ varying vec2 vUv;
56
+
57
+ void main() {
58
+ vec2 centered = vUv - 0.5;
59
+ float radial = length(centered) * 2.0;
60
+ float falloff = 1.0 - smoothstep(0.35, 1.0, radial);
61
+
62
+ float gridScale = 14.0;
63
+ vec2 gridUv = vUv * gridScale;
64
+ vec2 grid = abs(fract(gridUv - 0.5) - 0.5) / fwidth(gridUv);
65
+ float line = min(grid.x, grid.y);
66
+ float gridLine = 1.0 - min(line, 1.0);
67
+
68
+ float pulse = 0.5 + 0.5 * sin(uTime * 8.0);
69
+ vec3 color = mix(vec3(1.0, 0.58, 0.12), vec3(1.0, 0.16, 0.04), pulse);
70
+ float alpha = mix(0.25, 0.75, gridLine) * pulse * falloff;
71
+
72
+ gl_FragColor = vec4(color, alpha);
73
+ }
74
+ `, ae = { uTime: { value: 0 } };
75
+ function se({
76
+ segment: e,
77
+ material: i,
78
+ visible: t
79
+ }) {
80
+ return t ? /* @__PURE__ */ o(
81
+ "mesh",
82
+ {
83
+ position: e.position,
84
+ rotation: [0, e.yaw, 0],
85
+ renderOrder: 10,
86
+ material: i,
87
+ children: /* @__PURE__ */ o("planeGeometry", { args: [e.length, e.height] })
88
+ }
89
+ ) : null;
90
+ }
91
+ function ye({ boundary: e }) {
92
+ const i = g(
93
+ () => U(e.polygon.points, e.polygon.height),
94
+ [e.polygon.height, e.polygon.points]
95
+ ), t = g(
96
+ () => O(i, J),
97
+ [i]
98
+ );
99
+ return _(() => () => t.dispose(), [t]), e.collisionEnabled === !1 || i.length === 0 ? null : /* @__PURE__ */ o("mesh", { geometry: t, children: /* @__PURE__ */ o("meshStandardMaterial", { visible: !1 }) });
100
+ }
101
+ function Se({
102
+ boundary: e,
103
+ active: i
104
+ }) {
105
+ const t = X(), s = f(null), l = f(null), c = f(!1), [b, W] = A(!1), d = f(!1), D = f({ current: null }), a = g(
106
+ () => U(e.polygon.points, e.polygon.height),
107
+ [e.polygon.height, e.polygon.points]
108
+ ), F = g(
109
+ () => new Map(a.map((n) => [n.index, n])),
110
+ [a]
111
+ ), h = g(
112
+ () => O(a, K, {
113
+ length: Q,
114
+ height: ee
115
+ }),
116
+ [a]
117
+ ), [y] = A(oe), E = f(null);
118
+ _(
119
+ () => () => {
120
+ y.dispose(), h.dispose();
121
+ },
122
+ [y, h]
123
+ );
124
+ const I = x(
125
+ (n) => {
126
+ n && !d.current ? (d.current = !0, t.emit("boundary:contact", { boundaryId: e.id, proximity: 1 })) : !n && d.current && (d.current = !1, t.emit("boundary:release", { boundaryId: e.id }));
127
+ },
128
+ [e.id, t]
129
+ ), H = x(
130
+ (n) => {
131
+ c.current = n, W(n), I(n), !n && l.current && (l.current.visible = !1, l.current.scale.set(1, 1, 1));
132
+ },
133
+ [I]
134
+ );
135
+ return _(() => () => {
136
+ d.current && t.emit("boundary:release", { boundaryId: e.id }), d.current = !1, c.current = !1;
137
+ }, [e.id, t]), P(({ clock: n }) => {
138
+ const m = E.current;
139
+ m && (m.uniforms.uTime.value = n.elapsedTime);
140
+ }), P(({ scene: n, camera: m, clock: j }) => {
141
+ const r = l.current;
142
+ if (!c.current || !s.current || !r) {
143
+ r && (r.visible = !1, r.scale.set(1, 1, 1));
144
+ return;
145
+ }
146
+ re(D.current, n, m, M), u.copy(M), s.current.worldToLocal(u), S.copy(u), S.y += ne;
147
+ const R = C(
148
+ e.polygon.points,
149
+ e.polygon.height,
150
+ u,
151
+ a
152
+ ) ?? C(
153
+ e.polygon.points,
154
+ e.polygon.height,
155
+ u,
156
+ a,
157
+ 1 / 0
158
+ );
159
+ if (!R) {
160
+ r.visible = !1;
161
+ return;
162
+ }
163
+ const p = F.get(R.segmentIndex);
164
+ if (!p) {
165
+ r.visible = !1;
166
+ return;
167
+ }
168
+ const V = Z(p, S);
169
+ q(p, V, T), r.position.copy(T), r.rotation.set(0, p.yaw, 0);
170
+ const B = 0.92 + 0.08 * Math.sin(j.elapsedTime * 8);
171
+ r.scale.set(B, B, 1), r.visible = !0;
172
+ }), a.length === 0 || !i ? null : /* @__PURE__ */ L("group", { ref: s, children: [
173
+ /* @__PURE__ */ o(Y, { onIntersectedChanged: H, children: /* @__PURE__ */ o("mesh", { geometry: h, children: /* @__PURE__ */ o("primitive", { object: te, attach: "material" }) }) }),
174
+ a.map((n) => /* @__PURE__ */ o(
175
+ se,
176
+ {
177
+ segment: n,
178
+ material: y,
179
+ visible: b
180
+ },
181
+ `${e.id}-calm-${n.index}`
182
+ )),
183
+ /* @__PURE__ */ L("mesh", { ref: l, visible: !1, renderOrder: 11, children: [
184
+ /* @__PURE__ */ o("planeGeometry", { args: [N, N] }),
185
+ /* @__PURE__ */ o(
186
+ "shaderMaterial",
187
+ {
188
+ ref: E,
189
+ uniforms: ae,
190
+ vertexShader: ie,
191
+ fragmentShader: le,
192
+ transparent: !0,
193
+ depthWrite: !1,
194
+ side: G,
195
+ blending: w
196
+ }
197
+ )
198
+ ] })
199
+ ] });
200
+ }
201
+ export {
202
+ ye as PolygonBoundaryColliders,
203
+ Se as PolygonBoundaryFence
204
+ };
205
+ //# sourceMappingURL=polygon-boundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-boundary.js","sources":["../../space/polygon-boundary.tsx"],"sourcesContent":["import { BvhPhysicsSensor } from '@react-three/viverse'\nimport { useFrame } from '@react-three/fiber'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AdditiveBlending,\n DoubleSide,\n MeshBasicMaterial,\n ShaderMaterial,\n Vector3 as ThreeVec3,\n type Camera,\n type Group,\n type Mesh,\n type Object3D,\n type Scene\n} from 'three'\nimport type { PolygonBoundaryDef } from '../types'\nimport { useCaveEventBus } from '../core'\nimport {\n boundaryContactAnchorToPosition,\n buildPolygonBoundarySegments,\n findBoundaryContactAnchor,\n projectPlayerOntoSegmentWall,\n type PolygonBoundarySegment\n} from './utils/polygon-boundary-segments'\nimport { buildPolygonBoundaryColliderGeometry } from './utils/polygon-boundary-geometry'\nimport { CAVE_WORLD_LOCAL_PLAYER_FLAG } from './utils/cave-world-player'\n\nconst COLLIDER_DEPTH = 0.08\nconst SENSOR_DEPTH = 0.55\nconst SENSOR_LENGTH_PADDING = 0.2\nconst SENSOR_HEIGHT_PADDING = 0.15\n/** Warning patch size on the fence plane (m). */\nconst WARNING_BLOB_SIZE = 2.6\n/** Character root is at feet — sample chest height for the Meta-style contact patch. */\nconst PLAYER_WARNING_HEIGHT_OFFSET = 0.6\n\nconst INVISIBLE_MATERIAL = /* @__PURE__ */ new MeshBasicMaterial({ visible: false })\nconst _playerWorld = /* @__PURE__ */ new ThreeVec3()\nconst _playerLocal = /* @__PURE__ */ new ThreeVec3()\nconst _playerSampleLocal = /* @__PURE__ */ new ThreeVec3()\nconst _blobPosition = /* @__PURE__ */ new ThreeVec3()\n\n/**\n * Per-fence cache of the local player object.\n *\n * Deliberately not module-level: two viewers on one page would otherwise share\n * (and fight over) a single cached player. Re-traverses whenever the cached\n * object has been detached from the scene graph.\n */\ninterface LocalPlayerCache {\n current: Object3D | null\n}\n\nfunction resolvePlayerWorldPosition(\n cache: LocalPlayerCache,\n scene: Scene,\n camera: Camera,\n target: ThreeVec3\n): ThreeVec3 {\n if (!cache.current?.parent) {\n let found: Object3D | null = null\n scene.traverse((object) => {\n if (found) return\n if (object.userData?.[CAVE_WORLD_LOCAL_PLAYER_FLAG]) found = object\n })\n cache.current = found\n }\n\n if (cache.current) {\n cache.current.getWorldPosition(target)\n return target\n }\n // No local player (e.g. orbit viewer): the camera is the best stand-in.\n return camera.getWorldPosition(target)\n}\n\nfunction createCalmFenceMaterial() {\n return new ShaderMaterial({\n vertexShader: `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n varying vec2 vUv;\n void main() {\n float gridScale = 18.0;\n vec2 gridUv = vUv * gridScale;\n vec2 grid = abs(fract(gridUv - 0.5) - 0.5) / fwidth(gridUv);\n float line = min(grid.x, grid.y);\n float gridLine = 1.0 - min(line, 1.0);\n float alpha = mix(0.07, 0.2, gridLine);\n gl_FragColor = vec4(0.52, 0.82, 0.98, alpha);\n }\n `,\n transparent: true,\n depthWrite: false,\n side: DoubleSide,\n blending: AdditiveBlending\n })\n}\n\nconst WARNING_BLOB_VERTEX_SHADER = `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `\n\nconst WARNING_BLOB_FRAGMENT_SHADER = `\n uniform float uTime;\n varying vec2 vUv;\n\n void main() {\n vec2 centered = vUv - 0.5;\n float radial = length(centered) * 2.0;\n float falloff = 1.0 - smoothstep(0.35, 1.0, radial);\n\n float gridScale = 14.0;\n vec2 gridUv = vUv * gridScale;\n vec2 grid = abs(fract(gridUv - 0.5) - 0.5) / fwidth(gridUv);\n float line = min(grid.x, grid.y);\n float gridLine = 1.0 - min(line, 1.0);\n\n float pulse = 0.5 + 0.5 * sin(uTime * 8.0);\n vec3 color = mix(vec3(1.0, 0.58, 0.12), vec3(1.0, 0.16, 0.04), pulse);\n float alpha = mix(0.25, 0.75, gridLine) * pulse * falloff;\n\n gl_FragColor = vec4(color, alpha);\n }\n `\n\n/** Animated uniform for the warning patch; driven per frame through a ref. */\nconst WARNING_BLOB_UNIFORMS = { uTime: { value: 0 } }\n\nfunction PolygonBoundaryCalmSegment({\n segment,\n material,\n visible\n}: {\n segment: PolygonBoundarySegment\n material: ShaderMaterial\n visible: boolean\n}) {\n if (!visible) return null\n\n return (\n <mesh\n position={segment.position}\n rotation={[0, segment.yaw, 0]}\n renderOrder={10}\n material={material}\n >\n <planeGeometry args={[segment.length, segment.height]} />\n </mesh>\n )\n}\n\n/** Single merged collider mesh — mount inside `<BvhPhysicsBody>`. */\nexport function PolygonBoundaryColliders({ boundary }: { boundary: PolygonBoundaryDef }) {\n const segments = useMemo(\n () => buildPolygonBoundarySegments(boundary.polygon.points, boundary.polygon.height),\n [boundary.polygon.height, boundary.polygon.points]\n )\n\n const geometry = useMemo(\n () => buildPolygonBoundaryColliderGeometry(segments, COLLIDER_DEPTH),\n [segments]\n )\n\n useEffect(() => () => geometry.dispose(), [geometry])\n\n if (boundary.collisionEnabled === false || segments.length === 0) return null\n\n return (\n <mesh geometry={geometry}>\n <meshStandardMaterial visible={false} />\n </mesh>\n )\n}\n\nexport function PolygonBoundaryFence({\n boundary,\n active\n}: {\n boundary: PolygonBoundaryDef\n active: boolean\n}) {\n const eventBus = useCaveEventBus()\n const localSpaceRef = useRef<Group>(null)\n const warningBlobRef = useRef<Mesh>(null)\n const inContactRef = useRef(false)\n\n const [inContact, setInContact] = useState(false)\n const contactEmittedRef = useRef(false)\n const localPlayerCache = useRef<LocalPlayerCache>({ current: null })\n\n const segments = useMemo(\n () => buildPolygonBoundarySegments(boundary.polygon.points, boundary.polygon.height),\n [boundary.polygon.height, boundary.polygon.points]\n )\n const segmentByIndex = useMemo(\n () => new Map(segments.map((segment) => [segment.index, segment])),\n [segments]\n )\n\n const sensorGeometry = useMemo(\n () =>\n buildPolygonBoundaryColliderGeometry(segments, SENSOR_DEPTH, {\n length: SENSOR_LENGTH_PADDING,\n height: SENSOR_HEIGHT_PADDING\n }),\n [segments]\n )\n\n // The calm fence material is shared by every segment mesh and never mutated,\n // so one lazily-created instance is enough. Lazy `useState` (not `useMemo`)\n // guarantees it is built exactly once — a material must not be swapped while\n // the fence is on screen.\n const [calmMaterial] = useState(createCalmFenceMaterial)\n // The warning patch animates, so it is declared as JSX and driven through a\n // ref: mutating a hook-owned value each frame is not allowed.\n const warningMaterialRef = useRef<ShaderMaterial>(null)\n\n useEffect(\n () => () => {\n calmMaterial.dispose()\n sensorGeometry.dispose()\n },\n [calmMaterial, sensorGeometry]\n )\n\n const syncBoundaryEvents = useCallback(\n (touching: boolean) => {\n if (touching && !contactEmittedRef.current) {\n contactEmittedRef.current = true\n eventBus.emit('boundary:contact', { boundaryId: boundary.id, proximity: 1 })\n } else if (!touching && contactEmittedRef.current) {\n contactEmittedRef.current = false\n eventBus.emit('boundary:release', { boundaryId: boundary.id })\n }\n },\n [boundary.id, eventBus]\n )\n\n const handleSensorChange = useCallback(\n (intersected: boolean) => {\n inContactRef.current = intersected\n setInContact(intersected)\n syncBoundaryEvents(intersected)\n if (!intersected && warningBlobRef.current) {\n warningBlobRef.current.visible = false\n warningBlobRef.current.scale.set(1, 1, 1)\n }\n },\n [syncBoundaryEvents]\n )\n\n useEffect(() => {\n return () => {\n if (contactEmittedRef.current) {\n eventBus.emit('boundary:release', { boundaryId: boundary.id })\n }\n contactEmittedRef.current = false\n inContactRef.current = false\n }\n }, [boundary.id, eventBus])\n\n useFrame(({ clock }) => {\n const material = warningMaterialRef.current\n if (material) material.uniforms.uTime.value = clock.elapsedTime\n })\n\n useFrame(({ scene, camera, clock }) => {\n const blob = warningBlobRef.current\n if (!inContactRef.current || !localSpaceRef.current || !blob) {\n if (blob) {\n blob.visible = false\n blob.scale.set(1, 1, 1)\n }\n return\n }\n\n resolvePlayerWorldPosition(localPlayerCache.current, scene, camera, _playerWorld)\n _playerLocal.copy(_playerWorld)\n localSpaceRef.current.worldToLocal(_playerLocal)\n _playerSampleLocal.copy(_playerLocal)\n _playerSampleLocal.y += PLAYER_WARNING_HEIGHT_OFFSET\n\n const anchor =\n findBoundaryContactAnchor(\n boundary.polygon.points,\n boundary.polygon.height,\n _playerLocal,\n segments\n ) ??\n findBoundaryContactAnchor(\n boundary.polygon.points,\n boundary.polygon.height,\n _playerLocal,\n segments,\n Infinity\n )\n\n if (!anchor) {\n blob.visible = false\n return\n }\n\n const segment = segmentByIndex.get(anchor.segmentIndex)\n if (!segment) {\n blob.visible = false\n return\n }\n\n const projection = projectPlayerOntoSegmentWall(segment, _playerSampleLocal)\n boundaryContactAnchorToPosition(segment, projection, _blobPosition)\n blob.position.copy(_blobPosition)\n blob.rotation.set(0, segment.yaw, 0)\n const pulseScale = 0.92 + 0.08 * Math.sin(clock.elapsedTime * 8)\n blob.scale.set(pulseScale, pulseScale, 1)\n blob.visible = true\n })\n\n if (segments.length === 0 || !active) return null\n\n return (\n <group ref={localSpaceRef}>\n <BvhPhysicsSensor onIntersectedChanged={handleSensorChange}>\n <mesh geometry={sensorGeometry}>\n <primitive object={INVISIBLE_MATERIAL} attach=\"material\" />\n </mesh>\n </BvhPhysicsSensor>\n\n {segments.map((segment) => (\n <PolygonBoundaryCalmSegment\n key={`${boundary.id}-calm-${segment.index}`}\n segment={segment}\n material={calmMaterial}\n visible={inContact}\n />\n ))}\n\n <mesh ref={warningBlobRef} visible={false} renderOrder={11}>\n <planeGeometry args={[WARNING_BLOB_SIZE, WARNING_BLOB_SIZE]} />\n <shaderMaterial\n ref={warningMaterialRef}\n uniforms={WARNING_BLOB_UNIFORMS}\n vertexShader={WARNING_BLOB_VERTEX_SHADER}\n fragmentShader={WARNING_BLOB_FRAGMENT_SHADER}\n transparent\n depthWrite={false}\n side={DoubleSide}\n blending={AdditiveBlending}\n />\n </mesh>\n </group>\n )\n}\n"],"names":["COLLIDER_DEPTH","SENSOR_DEPTH","SENSOR_LENGTH_PADDING","SENSOR_HEIGHT_PADDING","WARNING_BLOB_SIZE","PLAYER_WARNING_HEIGHT_OFFSET","INVISIBLE_MATERIAL","MeshBasicMaterial","_playerWorld","ThreeVec3","_playerLocal","_playerSampleLocal","_blobPosition","resolvePlayerWorldPosition","cache","scene","camera","target","found","object","CAVE_WORLD_LOCAL_PLAYER_FLAG","createCalmFenceMaterial","ShaderMaterial","DoubleSide","AdditiveBlending","WARNING_BLOB_VERTEX_SHADER","WARNING_BLOB_FRAGMENT_SHADER","WARNING_BLOB_UNIFORMS","PolygonBoundaryCalmSegment","segment","material","visible","jsx","PolygonBoundaryColliders","boundary","segments","useMemo","buildPolygonBoundarySegments","geometry","buildPolygonBoundaryColliderGeometry","useEffect","PolygonBoundaryFence","active","eventBus","useCaveEventBus","localSpaceRef","useRef","warningBlobRef","inContactRef","inContact","setInContact","useState","contactEmittedRef","localPlayerCache","segmentByIndex","sensorGeometry","calmMaterial","warningMaterialRef","syncBoundaryEvents","useCallback","touching","handleSensorChange","intersected","useFrame","clock","blob","anchor","findBoundaryContactAnchor","projection","projectPlayerOntoSegmentWall","boundaryContactAnchorToPosition","pulseScale","jsxs","BvhPhysicsSensor"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { ThreeEvent } from '@react-three/fiber';
2
+ import { type SparkSplatMesh } from './splat-mesh.js';
3
+ /** Automatic re-download attempts before a splat failure is treated as terminal. */
4
+ export declare const SPLAT_LOAD_DEFAULT_MAX_RETRIES = 3;
5
+ /**
6
+ * Watchdog window (ms). A splat that neither finishes decoding nor rejects
7
+ * within this window is treated as a stalled download and retried. Kept
8
+ * generous so a slow-but-progressing download on a weak network isn't killed;
9
+ * genuine failures reject far sooner than this.
10
+ */
11
+ export declare const SPLAT_LOAD_DEFAULT_TIMEOUT_MS = 30000;
12
+ /** Exponential backoff (ms) between automatic retries, indexed by attempt. */
13
+ export declare const SPLAT_LOAD_RETRY_BACKOFF_MS: readonly [500, 1500, 3000];
14
+ /** Resolve the delay before the next automatic splat re-download. */
15
+ export declare function splatRetryDelayMs(attempt: number): number;
16
+ export interface RobustSplatMeshProps {
17
+ url: string;
18
+ visible?: boolean;
19
+ quaternion?: [number, number, number, number];
20
+ /** Fired once the splat has decoded and uploaded successfully. */
21
+ onLoad?: (mesh: SparkSplatMesh) => void | Promise<void>;
22
+ /** Fired once after all automatic retries are exhausted. */
23
+ onError?: (error: unknown) => void;
24
+ onClick?: (event: ThreeEvent<MouseEvent>) => void;
25
+ onDoubleClick?: (event: ThreeEvent<MouseEvent>) => void;
26
+ onPointerDown?: (event: ThreeEvent<PointerEvent>) => void;
27
+ userData?: Record<string, unknown>;
28
+ /** Space id, for error/telemetry context. */
29
+ spaceId?: string;
30
+ /**
31
+ * Play the spread reveal once after the splat finishes loading. Intended for
32
+ * the primary entry scene only — preloaded neighbors leave it `false` so
33
+ * transitions show the scene instantly.
34
+ */
35
+ revealOnEnter?: boolean;
36
+ maxRetries?: number;
37
+ timeoutMs?: number;
38
+ }
39
+ /**
40
+ * Production-hardened wrapper around spark's `SplatMesh`.
41
+ *
42
+ * spark exposes only `onLoad`: there is no `onError`, and a failed or stalled
43
+ * download leaves `mesh.initialized` rejected with nothing catching it. Since
44
+ * readiness gates on `onLoad` (see `CaveBaseLayer`), that would hang the viewer
45
+ * on an infinite loading screen. This wrapper:
46
+ *
47
+ * - attaches to `mesh.initialized` to catch spark's unhandled rejection,
48
+ * - adds a watchdog timeout for silently-stalled downloads,
49
+ * - auto-retries a bounded number of times by remounting the underlying mesh
50
+ * through a fresh `args` reference,
51
+ * - emits `space:error` for every failure (with `willRetry`) for telemetry, and
52
+ * - reports terminal failure through `onError` so a prompt can replace the
53
+ * frozen page.
54
+ *
55
+ * A user-triggered retry (`retrySpaceLoad()` → `retryToken` bump) resets the
56
+ * attempt counter and forces a fresh download.
57
+ */
58
+ export default function RobustSplatMesh({ url, visible, quaternion, onLoad, onError, onClick, onDoubleClick, onPointerDown, userData, spaceId, revealOnEnter, maxRetries, timeoutMs }: RobustSplatMeshProps): import("react").JSX.Element;
59
+ //# sourceMappingURL=robust-splat-mesh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robust-splat-mesh.d.ts","sourceRoot":"","sources":["../../../../space/splats/spark/robust-splat-mesh.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAW7D,oFAAoF;AACpF,eAAO,MAAM,8BAA8B,IAAI,CAAA;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAAS,CAAA;AAEnD,8EAA8E;AAC9E,eAAO,MAAM,2BAA2B,4BAA6B,CAAA;AAOrE,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C,kEAAkE;IAClE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IACjD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IACvD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,GAAG,EACH,OAAc,EACd,UAA4B,EAC5B,MAAM,EACN,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,QAAQ,EACR,OAAO,EACP,aAAqB,EACrB,UAA2C,EAC3C,SAAyC,EAC1C,EAAE,oBAAoB,+BAuJtB"}
@@ -0,0 +1,105 @@
1
+ import { jsx as X } from "react/jsx-runtime";
2
+ import { useRef as a, useState as j, useEffect as P, useCallback as h, useMemo as q } from "react";
3
+ import { useCaveEventBus as H, useCaveWorldStore as Q } from "../../../core/context/cave-world-context.js";
4
+ import { createLogger as W } from "../../../core/logging/logger.js";
5
+ import Y from "./splat-mesh.js";
6
+ import { createSpreadRevealTime as x, applySpreadReveal as G, SPREAD_REVEAL_TIME_SCALE as J, SPREAD_REVEAL_DURATION_SEC as Z, clearSpreadReveal as tt } from "./splat-spread-reveal.js";
7
+ const et = W("space:splat"), rt = 3, nt = 3e4, U = [500, 1500, 3e3], at = 5, ot = [1, 0, 0, 0];
8
+ function ct(e) {
9
+ return U[e] ?? U.at(-1);
10
+ }
11
+ function pt({
12
+ url: e,
13
+ visible: I = !0,
14
+ quaternion: N = ot,
15
+ onLoad: R,
16
+ onError: A,
17
+ onClick: O,
18
+ onDoubleClick: b,
19
+ onPointerDown: w,
20
+ userData: B,
21
+ spaceId: u,
22
+ revealOnEnter: f = !1,
23
+ maxRetries: _ = rt,
24
+ timeoutMs: S = nt
25
+ }) {
26
+ const L = H(), k = Q((t) => t.retryToken), M = a(null), o = `${e}\0${k}`, [d, D] = j({ key: o, attempt: 0 }), c = d.key === o ? d.attempt : 0;
27
+ d.key !== o && D({ key: o, attempt: 0 });
28
+ const v = a(R), $ = a(A);
29
+ P(() => {
30
+ v.current = R, $.current = A;
31
+ }, [R, A]);
32
+ const s = a(!1), E = a(x()), l = a(0), i = a(!1), g = h((t) => {
33
+ l.current = 0, E.current.value = 0, G(t, E.current), i.current = !0;
34
+ }, []), C = h(
35
+ (t) => {
36
+ s.current || (s.current = !0, f && g(t), v.current?.(t));
37
+ },
38
+ [f, g]
39
+ ), V = q(() => {
40
+ const t = { url: e, onLoad: C };
41
+ return f && (t.onFrame = ({ mesh: r, deltaTime: m }) => {
42
+ i.current && (l.current += m, E.current.value = l.current * J, r.updateVersion(), l.current >= Z && (i.current = !1, tt(r), r.onFrame = void 0));
43
+ }), [t];
44
+ }, [e, C, f, c, k]);
45
+ return P(() => {
46
+ s.current = !1, i.current = !1;
47
+ let t = !1, r;
48
+ const m = (n) => {
49
+ if (t || s.current) return;
50
+ s.current = !0;
51
+ const p = c < _;
52
+ if (L.emit("space:error", { error: n, willRetry: p, spaceId: u, url: e }), et.warn(
53
+ `Splat load failed (attempt ${c + 1}/${_ + 1})${u ? ` for space ${u}` : ""}:`,
54
+ n
55
+ ), !p) {
56
+ $.current?.(n);
57
+ return;
58
+ }
59
+ const K = ct(c);
60
+ r = setTimeout(() => {
61
+ t || D((T) => T.key === o ? { ...T, attempt: T.attempt + 1 } : T);
62
+ }, K);
63
+ }, y = setTimeout(() => {
64
+ m(new Error(`Splat load timed out after ${S}ms: ${e}`));
65
+ }, S);
66
+ let z = 0;
67
+ const F = () => {
68
+ if (t) return;
69
+ const n = M.current?.initialized;
70
+ if (!n || typeof n.then != "function") {
71
+ z++ < at && queueMicrotask(F);
72
+ return;
73
+ }
74
+ n.then(
75
+ () => clearTimeout(y),
76
+ (p) => {
77
+ clearTimeout(y), m(p);
78
+ }
79
+ );
80
+ };
81
+ return F(), () => {
82
+ t = !0, clearTimeout(y), r && clearTimeout(r);
83
+ };
84
+ }, [e, o, c, S, _, L, u]), /* @__PURE__ */ X(
85
+ Y,
86
+ {
87
+ ref: M,
88
+ visible: I,
89
+ quaternion: N,
90
+ args: V,
91
+ onClick: O,
92
+ onDoubleClick: b,
93
+ onPointerDown: w,
94
+ userData: B
95
+ }
96
+ );
97
+ }
98
+ export {
99
+ rt as SPLAT_LOAD_DEFAULT_MAX_RETRIES,
100
+ nt as SPLAT_LOAD_DEFAULT_TIMEOUT_MS,
101
+ U as SPLAT_LOAD_RETRY_BACKOFF_MS,
102
+ pt as default,
103
+ ct as splatRetryDelayMs
104
+ };
105
+ //# sourceMappingURL=robust-splat-mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robust-splat-mesh.js","sources":["../../../../space/splats/spark/robust-splat-mesh.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { ThreeEvent } from '@react-three/fiber'\nimport type { SplatMeshOptions } from '@sparkjsdev/spark'\nimport { createLogger, useCaveEventBus, useCaveWorldStore } from '../../../core'\nimport SplatMesh, { type SparkSplatMesh } from './splat-mesh'\nimport {\n applySpreadReveal,\n clearSpreadReveal,\n createSpreadRevealTime,\n SPREAD_REVEAL_DURATION_SEC,\n SPREAD_REVEAL_TIME_SCALE\n} from './splat-spread-reveal'\n\nconst logger = createLogger('space:splat')\n\n/** Automatic re-download attempts before a splat failure is treated as terminal. */\nexport const SPLAT_LOAD_DEFAULT_MAX_RETRIES = 3\n\n/**\n * Watchdog window (ms). A splat that neither finishes decoding nor rejects\n * within this window is treated as a stalled download and retried. Kept\n * generous so a slow-but-progressing download on a weak network isn't killed;\n * genuine failures reject far sooner than this.\n */\nexport const SPLAT_LOAD_DEFAULT_TIMEOUT_MS = 30_000\n\n/** Exponential backoff (ms) between automatic retries, indexed by attempt. */\nexport const SPLAT_LOAD_RETRY_BACKOFF_MS = [500, 1500, 3000] as const\n\n/** Bounded microtask retries while waiting for the mesh ref to be populated. */\nconst MAX_REF_ATTACH_ATTEMPTS = 5\n\nconst INIT_QUATERNION: [number, number, number, number] = [1, 0, 0, 0]\n\n/** Resolve the delay before the next automatic splat re-download. */\nexport function splatRetryDelayMs(attempt: number): number {\n return SPLAT_LOAD_RETRY_BACKOFF_MS[attempt] ?? SPLAT_LOAD_RETRY_BACKOFF_MS.at(-1)!\n}\n\nexport interface RobustSplatMeshProps {\n url: string\n visible?: boolean\n quaternion?: [number, number, number, number]\n /** Fired once the splat has decoded and uploaded successfully. */\n onLoad?: (mesh: SparkSplatMesh) => void | Promise<void>\n /** Fired once after all automatic retries are exhausted. */\n onError?: (error: unknown) => void\n onClick?: (event: ThreeEvent<MouseEvent>) => void\n onDoubleClick?: (event: ThreeEvent<MouseEvent>) => void\n onPointerDown?: (event: ThreeEvent<PointerEvent>) => void\n userData?: Record<string, unknown>\n /** Space id, for error/telemetry context. */\n spaceId?: string\n /**\n * Play the spread reveal once after the splat finishes loading. Intended for\n * the primary entry scene only — preloaded neighbors leave it `false` so\n * transitions show the scene instantly.\n */\n revealOnEnter?: boolean\n maxRetries?: number\n timeoutMs?: number\n}\n\n/**\n * Production-hardened wrapper around spark's `SplatMesh`.\n *\n * spark exposes only `onLoad`: there is no `onError`, and a failed or stalled\n * download leaves `mesh.initialized` rejected with nothing catching it. Since\n * readiness gates on `onLoad` (see `CaveBaseLayer`), that would hang the viewer\n * on an infinite loading screen. This wrapper:\n *\n * - attaches to `mesh.initialized` to catch spark's unhandled rejection,\n * - adds a watchdog timeout for silently-stalled downloads,\n * - auto-retries a bounded number of times by remounting the underlying mesh\n * through a fresh `args` reference,\n * - emits `space:error` for every failure (with `willRetry`) for telemetry, and\n * - reports terminal failure through `onError` so a prompt can replace the\n * frozen page.\n *\n * A user-triggered retry (`retrySpaceLoad()` → `retryToken` bump) resets the\n * attempt counter and forces a fresh download.\n */\nexport default function RobustSplatMesh({\n url,\n visible = true,\n quaternion = INIT_QUATERNION,\n onLoad,\n onError,\n onClick,\n onDoubleClick,\n onPointerDown,\n userData,\n spaceId,\n revealOnEnter = false,\n maxRetries = SPLAT_LOAD_DEFAULT_MAX_RETRIES,\n timeoutMs = SPLAT_LOAD_DEFAULT_TIMEOUT_MS\n}: RobustSplatMeshProps) {\n const eventBus = useCaveEventBus()\n const retryToken = useCaveWorldStore((s) => s.retryToken)\n\n const meshRef = useRef<SparkSplatMesh | null>(null)\n\n // Identity of the thing being loaded. Bundling the attempt counter with it in\n // one state object lets a url/retry change reset `attempt` in the same update\n // — deriving it during render from a ref would both trip the refs lint rule\n // and risk building `splatArgs` from a stale attempt (downloading twice).\n const loadKey = `${url}\\u0000${retryToken}`\n const [load, setLoad] = useState({ key: loadKey, attempt: 0 })\n const attempt = load.key === loadKey ? load.attempt : 0\n if (load.key !== loadKey) {\n setLoad({ key: loadKey, attempt: 0 })\n }\n\n // Keep the latest callbacks in refs so the load/watchdog effect stays keyed\n // only on identity that should force a re-download.\n const onLoadRef = useRef(onLoad)\n const onErrorRef = useRef(onError)\n useEffect(() => {\n onLoadRef.current = onLoad\n onErrorRef.current = onError\n }, [onLoad, onError])\n\n const settledRef = useRef(false)\n const revealTimeRef = useRef(createSpreadRevealTime())\n const revealElapsedRef = useRef(0)\n const revealPlayingRef = useRef(false)\n\n const startSpreadReveal = useCallback((mesh: SparkSplatMesh) => {\n revealElapsedRef.current = 0\n revealTimeRef.current.value = 0\n applySpreadReveal(mesh, revealTimeRef.current)\n revealPlayingRef.current = true\n }, [])\n\n const handleLoad = useCallback(\n (mesh: SparkSplatMesh) => {\n if (settledRef.current) return\n settledRef.current = true\n if (revealOnEnter) startSpreadReveal(mesh)\n onLoadRef.current?.(mesh)\n },\n [revealOnEnter, startSpreadReveal]\n )\n\n // A new array identity remounts the underlying spark mesh, which is how a\n // retry re-downloads the asset — hence `attempt` / `retryToken` in the deps.\n const splatArgs = useMemo(() => {\n const options: SplatMeshOptions = { url, onLoad: handleLoad }\n\n if (revealOnEnter) {\n options.onFrame = ({ mesh, deltaTime }) => {\n if (!revealPlayingRef.current) return\n revealElapsedRef.current += deltaTime\n revealTimeRef.current.value = revealElapsedRef.current * SPREAD_REVEAL_TIME_SCALE\n mesh.updateVersion()\n if (revealElapsedRef.current >= SPREAD_REVEAL_DURATION_SEC) {\n revealPlayingRef.current = false\n clearSpreadReveal(mesh)\n mesh.onFrame = undefined\n }\n }\n }\n\n return [options] as [SplatMeshOptions]\n // eslint-disable-next-line react-hooks/exhaustive-deps -- remount key\n }, [url, handleLoad, revealOnEnter, attempt, retryToken])\n\n useEffect(() => {\n settledRef.current = false\n revealPlayingRef.current = false\n\n let cancelled = false\n let retryTimer: ReturnType<typeof setTimeout> | undefined\n\n const fail = (error: unknown) => {\n if (cancelled || settledRef.current) return\n settledRef.current = true\n\n const willRetry = attempt < maxRetries\n eventBus.emit('space:error', { error, willRetry, spaceId, url })\n logger.warn(\n `Splat load failed (attempt ${attempt + 1}/${maxRetries + 1})` +\n `${spaceId ? ` for space ${spaceId}` : ''}:`,\n error\n )\n\n if (!willRetry) {\n onErrorRef.current?.(error)\n return\n }\n const backoff = splatRetryDelayMs(attempt)\n retryTimer = setTimeout(() => {\n if (cancelled) return\n setLoad((prev) => (prev.key === loadKey ? { ...prev, attempt: prev.attempt + 1 } : prev))\n }, backoff)\n }\n\n // Watchdog for silently-stalled downloads.\n const timer = setTimeout(() => {\n fail(new Error(`Splat load timed out after ${timeoutMs}ms: ${url}`))\n }, timeoutMs)\n\n // Catch spark's (otherwise unhandled) rejection and clear the watchdog on\n // success. The mesh ref is populated during commit, before this passive\n // effect, so read it directly; a bounded microtask fallback covers the rare\n // case where it isn't ready yet. Avoid requestAnimationFrame — it is paused\n // in background tabs, which would delay detection to the watchdog.\n let attachAttempts = 0\n const attach = () => {\n if (cancelled) return\n const initialized = (meshRef.current as unknown as { initialized?: Promise<unknown> } | null)\n ?.initialized\n\n if (!initialized || typeof initialized.then !== 'function') {\n if (attachAttempts++ < MAX_REF_ATTACH_ATTEMPTS) queueMicrotask(attach)\n return\n }\n\n initialized.then(\n () => clearTimeout(timer),\n (error: unknown) => {\n clearTimeout(timer)\n fail(error)\n }\n )\n }\n attach()\n\n return () => {\n cancelled = true\n clearTimeout(timer)\n if (retryTimer) clearTimeout(retryTimer)\n }\n }, [url, loadKey, attempt, timeoutMs, maxRetries, eventBus, spaceId])\n\n return (\n <SplatMesh\n ref={meshRef}\n visible={visible}\n quaternion={quaternion}\n args={splatArgs}\n onClick={onClick}\n onDoubleClick={onDoubleClick}\n onPointerDown={onPointerDown}\n userData={userData}\n />\n )\n}\n"],"names":["logger","createLogger","SPLAT_LOAD_DEFAULT_MAX_RETRIES","SPLAT_LOAD_DEFAULT_TIMEOUT_MS","SPLAT_LOAD_RETRY_BACKOFF_MS","MAX_REF_ATTACH_ATTEMPTS","INIT_QUATERNION","splatRetryDelayMs","attempt","RobustSplatMesh","url","visible","quaternion","onLoad","onError","onClick","onDoubleClick","onPointerDown","userData","spaceId","revealOnEnter","maxRetries","timeoutMs","eventBus","useCaveEventBus","retryToken","useCaveWorldStore","s","meshRef","useRef","loadKey","load","setLoad","useState","onLoadRef","onErrorRef","useEffect","settledRef","revealTimeRef","createSpreadRevealTime","revealElapsedRef","revealPlayingRef","startSpreadReveal","useCallback","mesh","applySpreadReveal","handleLoad","splatArgs","useMemo","options","deltaTime","SPREAD_REVEAL_TIME_SCALE","SPREAD_REVEAL_DURATION_SEC","clearSpreadReveal","cancelled","retryTimer","fail","error","willRetry","backoff","prev","timer","attachAttempts","attach","initialized","jsx","SplatMesh"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { SplatMesh as SparkSplatMesh } from '@sparkjsdev/spark';
2
+ declare const SplatMesh: import("react").ExoticComponent<import("@react-three/fiber/dist/declarations/src/core/utils").Mutable<import("@react-three/fiber/dist/declarations/src/core/utils").Overwrite<Partial<import("@react-three/fiber/dist/declarations/src/core/utils").Overwrite<SparkSplatMesh, import("@react-three/fiber").MathProps<SparkSplatMesh> & import("@react-three/fiber").ReactProps<SparkSplatMesh> & Partial<import("@react-three/fiber").EventHandlers>>>, Omit<import("@react-three/fiber").InstanceProps<SparkSplatMesh, typeof SparkSplatMesh>, "object">>>>;
3
+ export default SplatMesh;
4
+ export type { SparkSplatMesh };
5
+ //# sourceMappingURL=splat-mesh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splat-mesh.d.ts","sourceRoot":"","sources":["../../../../space/splats/spark/splat-mesh.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAE/D,QAAA,MAAM,SAAS,8hBAAyB,CAAA;AAExC,eAAe,SAAS,CAAA;AACxB,YAAY,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { extend as t } from "@react-three/fiber";
2
+ import { SplatMesh as e } from "@sparkjsdev/spark";
3
+ const p = t(e);
4
+ export {
5
+ p as default
6
+ };
7
+ //# sourceMappingURL=splat-mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splat-mesh.js","sources":["../../../../space/splats/spark/splat-mesh.tsx"],"sourcesContent":["import { extend } from '@react-three/fiber'\nimport { SplatMesh as SparkSplatMesh } from '@sparkjsdev/spark'\n\nconst SplatMesh = extend(SparkSplatMesh)\n\nexport default SplatMesh\nexport type { SparkSplatMesh }\n"],"names":["SplatMesh","extend","SparkSplatMesh"],"mappings":";;AAGA,MAAMA,IAAYC,EAAOC,CAAc;"}
@@ -0,0 +1,14 @@
1
+ import { dyno } from '@sparkjsdev/spark';
2
+ import type { SparkSplatMesh } from './splat-mesh.js';
3
+ type SpreadRevealTime = ReturnType<typeof dyno.dynoFloat>;
4
+ /** Wall-clock seconds before the spread reveal modifier is removed. */
5
+ export declare const SPREAD_REVEAL_DURATION_SEC = 6;
6
+ /** Shader time multiplier so the visual completes within {@link SPREAD_REVEAL_DURATION_SEC}. */
7
+ export declare const SPREAD_REVEAL_TIME_SCALE = 2;
8
+ /** Default for `CaveExplore.revealOnEnter` / `CaveOrbitViewer.revealOnEnter`. */
9
+ export declare const REVEAL_ON_ENTER_DEFAULT_ENABLED = true;
10
+ export declare function createSpreadRevealTime(): SpreadRevealTime;
11
+ export declare function applySpreadReveal(mesh: SparkSplatMesh, animateT: SpreadRevealTime): void;
12
+ export declare function clearSpreadReveal(mesh: SparkSplatMesh): void;
13
+ export {};
14
+ //# sourceMappingURL=splat-spread-reveal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splat-spread-reveal.d.ts","sourceRoot":"","sources":["../../../../space/splats/spark/splat-spread-reveal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,mBAAmB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAA;AAEzD,uEAAuE;AACvE,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,iFAAiF;AACjF,eAAO,MAAM,+BAA+B,OAAO,CAAA;AAEnD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AAiCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAGxF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAG5D"}
@@ -0,0 +1,45 @@
1
+ import { dyno as e } from "@sparkjsdev/spark";
2
+ const r = 6, p = 2, d = !0;
3
+ function i() {
4
+ return e.dynoFloat(0);
5
+ }
6
+ function n(a) {
7
+ return e.dynoBlock({ gsplat: e.Gsplat }, { gsplat: e.Gsplat }, ({ gsplat: t }) => (t = new e.Dyno({
8
+ inTypes: { gsplat: e.Gsplat, t: "float" },
9
+ outTypes: { gsplat: e.Gsplat },
10
+ statements: ({ inputs: l, outputs: o }) => e.unindentLines(`
11
+ ${o.gsplat} = ${l.gsplat};
12
+ float t = ${l.t};
13
+ vec3 scales = ${l.gsplat}.scales;
14
+ vec3 localPos = ${l.gsplat}.center;
15
+ vec4 origRgba = ${l.gsplat}.rgba;
16
+ float l = length(localPos.xyz);
17
+
18
+ // Phase 1: entire scene visible immediately as a uniform point cloud.
19
+ vec3 pointScale = vec3(0.002);
20
+
21
+ // Phase 2: radial wave — splats snap to full scale when the wave reaches them.
22
+ float expandT = max(0.0, t - 2.0) - l * 0.3;
23
+ float expanded = step(0.0, expandT);
24
+
25
+ ${o.gsplat}.center = localPos;
26
+ ${o.gsplat}.scales = mix(pointScale, scales, expanded);
27
+ ${o.gsplat}.rgba = origRgba;
28
+ `)
29
+ }).apply({ gsplat: t, t: a }).gsplat, { gsplat: t }));
30
+ }
31
+ function g(a, t) {
32
+ a.objectModifier = n(t), a.updateGenerator();
33
+ }
34
+ function E(a) {
35
+ a.objectModifier = void 0, a.updateGenerator();
36
+ }
37
+ export {
38
+ d as REVEAL_ON_ENTER_DEFAULT_ENABLED,
39
+ r as SPREAD_REVEAL_DURATION_SEC,
40
+ p as SPREAD_REVEAL_TIME_SCALE,
41
+ g as applySpreadReveal,
42
+ E as clearSpreadReveal,
43
+ i as createSpreadRevealTime
44
+ };
45
+ //# sourceMappingURL=splat-spread-reveal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splat-spread-reveal.js","sources":["../../../../space/splats/spark/splat-spread-reveal.ts"],"sourcesContent":["import { dyno, type GsplatModifier } from '@sparkjsdev/spark'\nimport type { SparkSplatMesh } from './splat-mesh'\n\ntype SpreadRevealTime = ReturnType<typeof dyno.dynoFloat>\n\n/** Wall-clock seconds before the spread reveal modifier is removed. */\nexport const SPREAD_REVEAL_DURATION_SEC = 6\n\n/** Shader time multiplier so the visual completes within {@link SPREAD_REVEAL_DURATION_SEC}. */\nexport const SPREAD_REVEAL_TIME_SCALE = 2\n\n/** Default for `CaveExplore.revealOnEnter` / `CaveOrbitViewer.revealOnEnter`. */\nexport const REVEAL_ON_ENTER_DEFAULT_ENABLED = true\n\nexport function createSpreadRevealTime(): SpreadRevealTime {\n return dyno.dynoFloat(0)\n}\n\nfunction createSpreadModifier(animateT: SpreadRevealTime): GsplatModifier {\n return dyno.dynoBlock({ gsplat: dyno.Gsplat }, { gsplat: dyno.Gsplat }, ({ gsplat }) => {\n const d = new dyno.Dyno({\n inTypes: { gsplat: dyno.Gsplat, t: 'float' },\n outTypes: { gsplat: dyno.Gsplat },\n statements: ({ inputs, outputs }) =>\n dyno.unindentLines(`\n ${outputs.gsplat} = ${inputs.gsplat};\n float t = ${inputs.t};\n vec3 scales = ${inputs.gsplat}.scales;\n vec3 localPos = ${inputs.gsplat}.center;\n vec4 origRgba = ${inputs.gsplat}.rgba;\n float l = length(localPos.xyz);\n\n // Phase 1: entire scene visible immediately as a uniform point cloud.\n vec3 pointScale = vec3(0.002);\n\n // Phase 2: radial wave — splats snap to full scale when the wave reaches them.\n float expandT = max(0.0, t - 2.0) - l * 0.3;\n float expanded = step(0.0, expandT);\n\n ${outputs.gsplat}.center = localPos;\n ${outputs.gsplat}.scales = mix(pointScale, scales, expanded);\n ${outputs.gsplat}.rgba = origRgba;\n `)\n })\n gsplat = d.apply({ gsplat, t: animateT }).gsplat\n return { gsplat }\n })\n}\n\nexport function applySpreadReveal(mesh: SparkSplatMesh, animateT: SpreadRevealTime): void {\n mesh.objectModifier = createSpreadModifier(animateT)\n mesh.updateGenerator()\n}\n\nexport function clearSpreadReveal(mesh: SparkSplatMesh): void {\n mesh.objectModifier = undefined\n mesh.updateGenerator()\n}\n"],"names":["SPREAD_REVEAL_DURATION_SEC","SPREAD_REVEAL_TIME_SCALE","REVEAL_ON_ENTER_DEFAULT_ENABLED","createSpreadRevealTime","dyno","createSpreadModifier","animateT","gsplat","inputs","outputs","applySpreadReveal","mesh","clearSpreadReveal"],"mappings":";AAMO,MAAMA,IAA6B,GAG7BC,IAA2B,GAG3BC,IAAkC;AAExC,SAASC,IAA2C;AACzD,SAAOC,EAAK,UAAU,CAAC;AACzB;AAEA,SAASC,EAAqBC,GAA4C;AACxE,SAAOF,EAAK,UAAU,EAAE,QAAQA,EAAK,OAAA,GAAU,EAAE,QAAQA,EAAK,OAAA,GAAU,CAAC,EAAE,QAAAG,SAyBzEA,IAxBU,IAAIH,EAAK,KAAK;AAAA,IACtB,SAAS,EAAE,QAAQA,EAAK,QAAQ,GAAG,QAAA;AAAA,IACnC,UAAU,EAAE,QAAQA,EAAK,OAAA;AAAA,IACzB,YAAY,CAAC,EAAE,QAAAI,GAAQ,SAAAC,EAAA,MACrBL,EAAK,cAAc;AAAA,cACbK,EAAQ,MAAM,MAAMD,EAAO,MAAM;AAAA,wBACvBA,EAAO,CAAC;AAAA,4BACJA,EAAO,MAAM;AAAA,8BACXA,EAAO,MAAM;AAAA,8BACbA,EAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAU7BC,EAAQ,MAAM;AAAA,cACdA,EAAQ,MAAM;AAAA,cACdA,EAAQ,MAAM;AAAA,WACjB;AAAA,EAAA,CACN,EACU,MAAM,EAAE,QAAAF,GAAQ,GAAGD,EAAA,CAAU,EAAE,QACnC,EAAE,QAAAC,EAAA,EACV;AACH;AAEO,SAASG,EAAkBC,GAAsBL,GAAkC;AACxF,EAAAK,EAAK,iBAAiBN,EAAqBC,CAAQ,GACnDK,EAAK,gBAAA;AACP;AAEO,SAASC,EAAkBD,GAA4B;AAC5D,EAAAA,EAAK,iBAAiB,QACtBA,EAAK,gBAAA;AACP;"}
@@ -0,0 +1,3 @@
1
+ /** userData flag on the local player physics root — read by boundary fence visuals. */
2
+ export declare const CAVE_WORLD_LOCAL_PLAYER_FLAG = "caveWorldLocalPlayer";
3
+ //# sourceMappingURL=cave-world-player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cave-world-player.d.ts","sourceRoot":"","sources":["../../../space/utils/cave-world-player.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,eAAO,MAAM,4BAA4B,yBAAyB,CAAA"}
@@ -0,0 +1,5 @@
1
+ const L = "caveWorldLocalPlayer";
2
+ export {
3
+ L as CAVE_WORLD_LOCAL_PLAYER_FLAG
4
+ };
5
+ //# sourceMappingURL=cave-world-player.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cave-world-player.js","sources":["../../../space/utils/cave-world-player.ts"],"sourcesContent":["/** userData flag on the local player physics root — read by boundary fence visuals. */\nexport const CAVE_WORLD_LOCAL_PLAYER_FLAG = 'caveWorldLocalPlayer'\n"],"names":["CAVE_WORLD_LOCAL_PLAYER_FLAG"],"mappings":"AACO,MAAMA,IAA+B;"}
@@ -0,0 +1,20 @@
1
+ import type { WebGLRenderer } from 'three';
2
+ /**
3
+ * Apply the splat-friendly pixel-ratio cap to an R3F renderer.
4
+ *
5
+ * Splat blending cost scales with pixel count, so an uncapped
6
+ * `devicePixelRatio` on a 3x phone display burns frame time for no visible
7
+ * gain. Call from `<Canvas onCreated>` when composing your own canvas.
8
+ * @see https://sparkjs.dev/docs/performance/
9
+ */
10
+ export declare function configureSparkWebGLRenderer(gl: WebGLRenderer): void;
11
+ /**
12
+ * Make a canvas behave like a game viewport rather than a document.
13
+ *
14
+ * - `touch-action: none` — drag/orbit gestures aren't stolen by the browser
15
+ * (which would fire `pointercancel` mid-gesture);
16
+ * - `user-select` / `-webkit-touch-callout` — no long-press text selection or
17
+ * iOS callout menu over the scene.
18
+ */
19
+ export declare function configureCaveCanvasDomElement(canvas: HTMLCanvasElement): void;
20
+ //# sourceMappingURL=configure-canvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure-canvas.d.ts","sourceRoot":"","sources":["../../../space/utils/configure-canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAG1C;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAEnE;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAM7E"}
@@ -0,0 +1,12 @@
1
+ import { getSparkCanvasDpr as t } from "./spark-performance.js";
2
+ function r(e) {
3
+ e.setPixelRatio(t());
4
+ }
5
+ function n(e) {
6
+ e.style.touchAction = "none", e.style.userSelect = "none", e.style.setProperty("-webkit-user-select", "none"), e.style.setProperty("-webkit-touch-callout", "none"), e.style.setProperty("-webkit-tap-highlight-color", "transparent");
7
+ }
8
+ export {
9
+ n as configureCaveCanvasDomElement,
10
+ r as configureSparkWebGLRenderer
11
+ };
12
+ //# sourceMappingURL=configure-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure-canvas.js","sources":["../../../space/utils/configure-canvas.ts"],"sourcesContent":["import type { WebGLRenderer } from 'three'\nimport { getSparkCanvasDpr } from './spark-performance'\n\n/**\n * Apply the splat-friendly pixel-ratio cap to an R3F renderer.\n *\n * Splat blending cost scales with pixel count, so an uncapped\n * `devicePixelRatio` on a 3x phone display burns frame time for no visible\n * gain. Call from `<Canvas onCreated>` when composing your own canvas.\n * @see https://sparkjs.dev/docs/performance/\n */\nexport function configureSparkWebGLRenderer(gl: WebGLRenderer): void {\n gl.setPixelRatio(getSparkCanvasDpr())\n}\n\n/**\n * Make a canvas behave like a game viewport rather than a document.\n *\n * - `touch-action: none` — drag/orbit gestures aren't stolen by the browser\n * (which would fire `pointercancel` mid-gesture);\n * - `user-select` / `-webkit-touch-callout` — no long-press text selection or\n * iOS callout menu over the scene.\n */\nexport function configureCaveCanvasDomElement(canvas: HTMLCanvasElement): void {\n canvas.style.touchAction = 'none'\n canvas.style.userSelect = 'none'\n canvas.style.setProperty('-webkit-user-select', 'none')\n canvas.style.setProperty('-webkit-touch-callout', 'none')\n canvas.style.setProperty('-webkit-tap-highlight-color', 'transparent')\n}\n"],"names":["configureSparkWebGLRenderer","gl","getSparkCanvasDpr","configureCaveCanvasDomElement","canvas"],"mappings":";AAWO,SAASA,EAA4BC,GAAyB;AACnE,EAAAA,EAAG,cAAcC,GAAmB;AACtC;AAUO,SAASC,EAA8BC,GAAiC;AAC7E,EAAAA,EAAO,MAAM,cAAc,QAC3BA,EAAO,MAAM,aAAa,QAC1BA,EAAO,MAAM,YAAY,uBAAuB,MAAM,GACtDA,EAAO,MAAM,YAAY,yBAAyB,MAAM,GACxDA,EAAO,MAAM,YAAY,+BAA+B,aAAa;AACvE;"}
@@ -0,0 +1,8 @@
1
+ import { BufferGeometry } from 'three';
2
+ import type { PolygonBoundarySegment } from './polygon-boundary-segments.js';
3
+ /** Merge segment wall boxes into one static BufferGeometry for a single BVH body. */
4
+ export declare function buildPolygonBoundaryColliderGeometry(segments: PolygonBoundarySegment[], depth: number, padding?: {
5
+ length?: number;
6
+ height?: number;
7
+ }): BufferGeometry;
8
+ //# sourceMappingURL=polygon-boundary-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-boundary-geometry.d.ts","sourceRoot":"","sources":["../../../space/utils/polygon-boundary-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,cAAc,EAAgC,MAAM,OAAO,CAAA;AAEjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAQzE,qFAAqF;AACrF,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,sBAAsB,EAAE,EAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,cAAc,CAsBhB"}