@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,28 @@
1
+ const e = {
2
+ Hips: "hips",
3
+ Spine: "spine",
4
+ Spine01: "chest",
5
+ Spine02: "upperChest",
6
+ neck: "neck",
7
+ Head: "head",
8
+ LeftShoulder: "leftShoulder",
9
+ LeftArm: "leftUpperArm",
10
+ LeftForeArm: "leftLowerArm",
11
+ LeftHand: "leftHand",
12
+ RightShoulder: "rightShoulder",
13
+ RightArm: "rightUpperArm",
14
+ RightForeArm: "rightLowerArm",
15
+ RightHand: "rightHand",
16
+ LeftUpLeg: "leftUpperLeg",
17
+ LeftLeg: "leftLowerLeg",
18
+ LeftFoot: "leftFoot",
19
+ LeftToeBase: "leftToes",
20
+ RightUpLeg: "rightUpperLeg",
21
+ RightLeg: "rightLowerLeg",
22
+ RightFoot: "rightFoot",
23
+ RightToeBase: "rightToes"
24
+ };
25
+ export {
26
+ e as MIXAMO_STYLE_BONE_MAP
27
+ };
28
+ //# sourceMappingURL=mixamo-style-bone-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixamo-style-bone-map.js","sources":["../../../explore/characters/mixamo-style-bone-map.ts"],"sourcesContent":["import type { VRMHumanBoneName } from '@react-three/viverse'\n\n/**\n * Mixamo-style joint names without the `mixamorig` prefix, mapped to VRM 1.0 humanoid\n * names for `@react-three/viverse` retargeting.\n *\n * Typical extras on rigs (leave unmapped): `head_end`, `headfront`, finger bones if absent.\n */\nexport const MIXAMO_STYLE_BONE_MAP: Record<string, VRMHumanBoneName> = {\n Hips: 'hips',\n Spine: 'spine',\n Spine01: 'chest',\n Spine02: 'upperChest',\n neck: 'neck',\n Head: 'head',\n LeftShoulder: 'leftShoulder',\n LeftArm: 'leftUpperArm',\n LeftForeArm: 'leftLowerArm',\n LeftHand: 'leftHand',\n RightShoulder: 'rightShoulder',\n RightArm: 'rightUpperArm',\n RightForeArm: 'rightLowerArm',\n RightHand: 'rightHand',\n LeftUpLeg: 'leftUpperLeg',\n LeftLeg: 'leftLowerLeg',\n LeftFoot: 'leftFoot',\n LeftToeBase: 'leftToes',\n RightUpLeg: 'rightUpperLeg',\n RightLeg: 'rightLowerLeg',\n RightFoot: 'rightFoot',\n RightToeBase: 'rightToes'\n}\n"],"names":["MIXAMO_STYLE_BONE_MAP"],"mappings":"AAQO,MAAMA,IAA0D;AAAA,EACrE,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU;AAAA,EACV,eAAe;AAAA,EACf,UAAU;AAAA,EACV,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAChB;"}
@@ -0,0 +1,38 @@
1
+ import { type RefObject } from 'react';
2
+ import type { Group, Object3DEventMap } from 'three';
3
+ import type { Quaternion as QuaternionType, Vector3 as Vector3Type } from '../../types/index.js';
4
+ import { type AnimationName, type AvatarConfig } from './character-configs.js';
5
+ export interface RemoteCharacterData {
6
+ id?: string;
7
+ playerId?: string;
8
+ position?: Vector3Type;
9
+ rotation?: QuaternionType;
10
+ animation?: AnimationName;
11
+ avatarId?: string;
12
+ lastUpdate?: number;
13
+ }
14
+ export interface RemoteCharacterControllerProps {
15
+ /** Realtime endpoint. Required — there is no silent CaveGiant default. */
16
+ websocketUrl: string;
17
+ /** Room key — normally the space id. */
18
+ appId: string;
19
+ /** Local character root, read each tick to publish position/rotation. */
20
+ localCharacterRef?: RefObject<Group<Object3DEventMap> | null>;
21
+ localAvatarId?: string;
22
+ /**
23
+ * Avatar catalog for remote players. Defaults to an empty catalog (no CDN
24
+ * fallback). Pass {@link BUILTIN_AVATARS} for the CaveGiant demo assets.
25
+ */
26
+ avatars?: Record<string, AvatarConfig>;
27
+ maxRemoteCharacters?: number;
28
+ enableNetworkSync?: boolean;
29
+ onConnectionStatusChange?: (status: string) => void;
30
+ }
31
+ /**
32
+ * Publishes the local player's transform/animation and renders everyone else.
33
+ *
34
+ * Remote state is held in a ref and mirrored into React state only when the
35
+ * roster changes, so 10 Hz position updates don't re-render the tree.
36
+ */
37
+ export default function RemoteCharacterController({ websocketUrl, appId, localCharacterRef, localAvatarId, avatars, maxRemoteCharacters, enableNetworkSync, onConnectionStatusChange }: RemoteCharacterControllerProps): import("react").JSX.Element;
38
+ //# sourceMappingURL=remote-character-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-character-controller.d.ts","sourceRoot":"","sources":["../../../explore/characters/remote-character-controller.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACnG,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AAGvF,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAA;AAK5B,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,SAAS,CAAC,EAAE,aAAa,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAQD,MAAM,WAAW,8BAA8B;IAC7C,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,CAAA;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACtC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,wBAAwB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CACpD;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,EAChD,YAAY,EACZ,KAAK,EACL,iBAAiB,EACjB,aAAiC,EACjC,OAAY,EACZ,mBAAmD,EACnD,iBAAwB,EACxB,wBAAwB,EACzB,EAAE,8BAA8B,+BAmLhC"}
@@ -0,0 +1,135 @@
1
+ import { jsx as h, Fragment as x } from "react/jsx-runtime";
2
+ import { useRef as M, useState as P, useCallback as c, useEffect as R, useMemo as k, Suspense as w } from "react";
3
+ import { createLogger as F } from "../../core/logging/logger.js";
4
+ import { useCharacterSync as $ } from "../hooks/use-character-sync.js";
5
+ import { useCaveExploreStore as V } from "../stores/explore-context.js";
6
+ import { DEFAULT_AVATAR_ID as T, getAvatarConfig as q } from "./character-configs.js";
7
+ import G from "./remote-character.js";
8
+ const d = F("multiplayer:characters"), H = 50, O = 100;
9
+ function ee({
10
+ websocketUrl: p,
11
+ appId: f,
12
+ localCharacterRef: l,
13
+ localAvatarId: y = T,
14
+ avatars: g = {},
15
+ maxRemoteCharacters: S = H,
16
+ enableNetworkSync: A = !0,
17
+ onConnectionStatusChange: J
18
+ }) {
19
+ const n = V(), u = M(/* @__PURE__ */ new Map()), [C, _] = P([]), [v, b] = P(!1), m = M(!1), o = c(() => {
20
+ _(Array.from(u.current.values()));
21
+ }, []), E = c(
22
+ (e) => {
23
+ n.getState().setRoomInfo((r) => r && { ...r, players: e });
24
+ },
25
+ [n]
26
+ ), L = c(
27
+ (e) => {
28
+ const r = e.playerId || e.id;
29
+ r && (u.current.set(r, { ...e, id: r }), o());
30
+ },
31
+ [o]
32
+ ), N = c(
33
+ (e) => {
34
+ const r = e.playerId || e.id;
35
+ r && (u.current.set(r, { ...e, id: r }), o(), d.debug("Player joined:", r), n.getState().setRoomInfo((t) => !t || t.players.some((s) => s.playerId === r) ? t : {
36
+ ...t,
37
+ players: [...t.players, { playerId: r, playerName: r, isMe: !1 }]
38
+ }));
39
+ },
40
+ [o, n]
41
+ ), U = c(
42
+ (e) => {
43
+ u.current.delete(e), o(), d.debug("Player left:", e), n.getState().setRoomInfo((r) => !r || !r.players.some((t) => t.playerId === e) ? r : { ...r, players: r.players.filter((t) => t.playerId !== e) });
44
+ },
45
+ [o, n]
46
+ ), I = c(
47
+ (e, r) => {
48
+ const t = /* @__PURE__ */ new Map();
49
+ for (const s of e) {
50
+ const i = s.playerId || s.id;
51
+ i && i !== r && t.set(i, { ...s, id: i });
52
+ }
53
+ u.current = t, o(), E(
54
+ e.map((s) => {
55
+ const i = s.playerId || s.id || "";
56
+ return { playerId: i, playerName: i, isMe: i === r };
57
+ })
58
+ );
59
+ },
60
+ [o, E]
61
+ ), j = c(
62
+ (e) => {
63
+ d.debug("Joined room", e.roomId, "as", e.playerId, { isRejoin: e.isRejoin }), b(!0), m.current = !0, n.getState().setRoomInfo(() => ({
64
+ roomId: e.roomId,
65
+ roomName: X(e.roomId),
66
+ players: e.players.map((r) => {
67
+ const t = r.playerId || r.id || "";
68
+ return { playerId: t, playerName: t, isMe: t === e.playerId };
69
+ })
70
+ })), I(e.players, e.playerId);
71
+ },
72
+ [n, I]
73
+ ), a = $({
74
+ websocketUrl: p,
75
+ appId: f,
76
+ localAvatarId: y,
77
+ onPlayerUpdate: L,
78
+ onPlayerJoin: N,
79
+ onPlayerLeave: U,
80
+ onRoomSync: I,
81
+ onJoinSuccess: j,
82
+ onConnectionStatusChange: J
83
+ });
84
+ R(() => {
85
+ !a.isConnected || m.current || (m.current = !0, a.joinGame(y));
86
+ }, [a, y]), R(() => {
87
+ if (!A || !v || !a.localUserId) return;
88
+ const e = setInterval(() => {
89
+ const r = l?.current;
90
+ !r || !a.isConnected || a.updateState({
91
+ position: r.position.toArray(),
92
+ rotation: r.children[0]?.quaternion.toArray(),
93
+ animation: r.userData.currentAnimation
94
+ });
95
+ }, O);
96
+ return () => clearInterval(e);
97
+ }, [A, v, l, a]), R(() => {
98
+ const e = n;
99
+ return () => {
100
+ u.current.clear(), m.current = !1, e.getState().setRoomInfo(() => {
101
+ });
102
+ };
103
+ }, [n]);
104
+ const D = k(() => C.slice(0, S).flatMap((e) => {
105
+ if (!e.id) return [];
106
+ const r = q(e.avatarId || T, g);
107
+ return r ? [
108
+ // Per-player boundary: an avatar's mesh and its six clips each suspend
109
+ // separately. A shared boundary would unmount the local character (and
110
+ // reset its position) every time someone joins.
111
+ /* @__PURE__ */ h(w, { fallback: null, children: /* @__PURE__ */ h(
112
+ G,
113
+ {
114
+ userId: e.id,
115
+ characterConfig: r,
116
+ position: e.position,
117
+ rotation: e.rotation,
118
+ currentAnimation: e.animation ?? "idle"
119
+ }
120
+ ) }, e.id)
121
+ ] : (d.warn(`No avatar config for id "${e.avatarId}"; skipping player ${e.id}.`), []);
122
+ }), [C, S, g]);
123
+ return /* @__PURE__ */ h(x, { children: D });
124
+ }
125
+ function X(p) {
126
+ if (!p) return "#0000";
127
+ let f = 0;
128
+ for (let l = 0; l < p.length; l++)
129
+ f = f * 31 + p.charCodeAt(l) >>> 0;
130
+ return `#${f % 9e3 + 1e3}`;
131
+ }
132
+ export {
133
+ ee as default
134
+ };
135
+ //# sourceMappingURL=remote-character-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-character-controller.js","sources":["../../../explore/characters/remote-character-controller.tsx"],"sourcesContent":["import { Suspense, useCallback, useEffect, useMemo, useRef, useState, type RefObject } from 'react'\nimport type { Group, Object3DEventMap } from 'three'\nimport { createLogger } from '../../core'\nimport type { Quaternion as QuaternionType, Vector3 as Vector3Type } from '../../types'\nimport { useCharacterSync } from '../hooks/use-character-sync'\nimport { useCaveExploreStore } from '../stores/explore-context'\nimport {\n DEFAULT_AVATAR_ID,\n getAvatarConfig,\n type AnimationName,\n type AvatarConfig\n} from './character-configs'\nimport RemoteCharacter from './remote-character'\n\nconst logger = createLogger('multiplayer:characters')\n\nexport interface RemoteCharacterData {\n id?: string\n playerId?: string\n position?: Vector3Type\n rotation?: QuaternionType\n animation?: AnimationName\n avatarId?: string\n lastUpdate?: number\n}\n\n/** Cap on simultaneously rendered remote players — each one is a skinned mesh. */\nconst DEFAULT_MAX_REMOTE_CHARACTERS = 50\n\n/** How often the local player's transform is published, in ms. */\nconst STATE_UPDATE_INTERVAL_MS = 100\n\nexport interface RemoteCharacterControllerProps {\n /** Realtime endpoint. Required — there is no silent CaveGiant default. */\n websocketUrl: string\n /** Room key — normally the space id. */\n appId: string\n /** Local character root, read each tick to publish position/rotation. */\n localCharacterRef?: RefObject<Group<Object3DEventMap> | null>\n localAvatarId?: string\n /**\n * Avatar catalog for remote players. Defaults to an empty catalog (no CDN\n * fallback). Pass {@link BUILTIN_AVATARS} for the CaveGiant demo assets.\n */\n avatars?: Record<string, AvatarConfig>\n maxRemoteCharacters?: number\n enableNetworkSync?: boolean\n onConnectionStatusChange?: (status: string) => void\n}\n\n/**\n * Publishes the local player's transform/animation and renders everyone else.\n *\n * Remote state is held in a ref and mirrored into React state only when the\n * roster changes, so 10 Hz position updates don't re-render the tree.\n */\nexport default function RemoteCharacterController({\n websocketUrl,\n appId,\n localCharacterRef,\n localAvatarId = DEFAULT_AVATAR_ID,\n avatars = {},\n maxRemoteCharacters = DEFAULT_MAX_REMOTE_CHARACTERS,\n enableNetworkSync = true,\n onConnectionStatusChange\n}: RemoteCharacterControllerProps) {\n const exploreStore = useCaveExploreStore()\n const remoteCharactersRef = useRef<Map<string, RemoteCharacterData>>(new Map())\n const [remoteCharacters, setRemoteCharacters] = useState<RemoteCharacterData[]>([])\n const [isJoined, setIsJoined] = useState(false)\n const hasJoinedRef = useRef(false)\n\n const publishRoster = useCallback(() => {\n setRemoteCharacters(Array.from(remoteCharactersRef.current.values()))\n }, [])\n\n const setRoomPlayers = useCallback(\n (players: Array<{ playerId: string; playerName: string; isMe: boolean }>) => {\n exploreStore.getState().setRoomInfo((room) => (room ? { ...room, players } : room))\n },\n [exploreStore]\n )\n\n const handlePlayerUpdate = useCallback(\n (data: RemoteCharacterData) => {\n const id = data.playerId || data.id\n if (!id) return\n remoteCharactersRef.current.set(id, { ...data, id })\n publishRoster()\n },\n [publishRoster]\n )\n\n const handlePlayerJoin = useCallback(\n (data: RemoteCharacterData) => {\n const id = data.playerId || data.id\n if (!id) return\n remoteCharactersRef.current.set(id, { ...data, id })\n publishRoster()\n logger.debug('Player joined:', id)\n\n exploreStore.getState().setRoomInfo((room) => {\n if (!room || room.players.some((player) => player.playerId === id)) return room\n return {\n ...room,\n players: [...room.players, { playerId: id, playerName: id, isMe: false }]\n }\n })\n },\n [publishRoster, exploreStore]\n )\n\n const handlePlayerLeave = useCallback(\n (playerId: string) => {\n remoteCharactersRef.current.delete(playerId)\n publishRoster()\n logger.debug('Player left:', playerId)\n\n exploreStore.getState().setRoomInfo((room) => {\n if (!room || !room.players.some((player) => player.playerId === playerId)) return room\n return { ...room, players: room.players.filter((p) => p.playerId !== playerId) }\n })\n },\n [publishRoster, exploreStore]\n )\n\n const handleRoomSync = useCallback(\n (players: RemoteCharacterData[], localPlayerId?: string) => {\n const next = new Map<string, RemoteCharacterData>()\n for (const player of players) {\n const id = player.playerId || player.id\n if (id && id !== localPlayerId) next.set(id, { ...player, id })\n }\n remoteCharactersRef.current = next\n publishRoster()\n\n setRoomPlayers(\n players.map((player) => {\n const id = player.playerId || player.id || ''\n return { playerId: id, playerName: id, isMe: id === localPlayerId }\n })\n )\n },\n [publishRoster, setRoomPlayers]\n )\n\n const handleJoinSuccess = useCallback(\n (data: {\n roomId: string\n playerId: string\n players: RemoteCharacterData[]\n isRejoin: boolean\n }) => {\n logger.debug('Joined room', data.roomId, 'as', data.playerId, { isRejoin: data.isRejoin })\n setIsJoined(true)\n hasJoinedRef.current = true\n\n exploreStore.getState().setRoomInfo(() => ({\n roomId: data.roomId,\n roomName: formatRoomName(data.roomId),\n players: data.players.map((player) => {\n const id = player.playerId || player.id || ''\n return { playerId: id, playerName: id, isMe: id === data.playerId }\n })\n }))\n\n handleRoomSync(data.players, data.playerId)\n },\n [exploreStore, handleRoomSync]\n )\n\n const websocket = useCharacterSync({\n websocketUrl,\n appId,\n localAvatarId,\n onPlayerUpdate: handlePlayerUpdate,\n onPlayerJoin: handlePlayerJoin,\n onPlayerLeave: handlePlayerLeave,\n onRoomSync: handleRoomSync,\n onJoinSuccess: handleJoinSuccess,\n onConnectionStatusChange\n })\n\n // Join once per connection.\n useEffect(() => {\n if (!websocket.isConnected || hasJoinedRef.current) return\n hasJoinedRef.current = true\n websocket.joinGame(localAvatarId)\n }, [websocket, localAvatarId])\n\n // Publish local transform on a fixed interval (not per frame — that would\n // flood the socket at display refresh rate).\n useEffect(() => {\n if (!enableNetworkSync || !isJoined || !websocket.localUserId) return\n\n const interval = setInterval(() => {\n const character = localCharacterRef?.current\n if (!character || !websocket.isConnected) return\n websocket.updateState({\n position: character.position.toArray() as Vector3Type,\n rotation: character.children[0]?.quaternion.toArray() as QuaternionType,\n animation: character.userData.currentAnimation as AnimationName\n })\n }, STATE_UPDATE_INTERVAL_MS)\n\n return () => clearInterval(interval)\n }, [enableNetworkSync, isJoined, localCharacterRef, websocket])\n\n useEffect(() => {\n const store = exploreStore\n return () => {\n remoteCharactersRef.current.clear()\n hasJoinedRef.current = false\n store.getState().setRoomInfo(() => undefined)\n }\n }, [exploreStore])\n\n const rendered = useMemo(() => {\n return remoteCharacters.slice(0, maxRemoteCharacters).flatMap((data) => {\n if (!data.id) return []\n const avatarConfig = getAvatarConfig(data.avatarId || DEFAULT_AVATAR_ID, avatars)\n if (!avatarConfig) {\n logger.warn(`No avatar config for id \"${data.avatarId}\"; skipping player ${data.id}.`)\n return []\n }\n\n return [\n // Per-player boundary: an avatar's mesh and its six clips each suspend\n // separately. A shared boundary would unmount the local character (and\n // reset its position) every time someone joins.\n <Suspense key={data.id} fallback={null}>\n <RemoteCharacter\n userId={data.id}\n characterConfig={avatarConfig}\n position={data.position}\n rotation={data.rotation}\n currentAnimation={data.animation ?? 'idle'}\n />\n </Suspense>\n ]\n })\n }, [remoteCharacters, maxRemoteCharacters, avatars])\n\n return <>{rendered}</>\n}\n\n/**\n * Short, stable display name derived from a room id (`\"#4271\"`).\n *\n * Hashing keeps it deterministic so every client in a room shows the same label\n * without an extra round trip.\n */\nfunction formatRoomName(roomId: string): string {\n if (!roomId) return '#0000'\n let hash = 0\n for (let i = 0; i < roomId.length; i++) {\n hash = (hash * 31 + roomId.charCodeAt(i)) >>> 0\n }\n return `#${(hash % 9000) + 1000}`\n}\n"],"names":["logger","createLogger","DEFAULT_MAX_REMOTE_CHARACTERS","STATE_UPDATE_INTERVAL_MS","RemoteCharacterController","websocketUrl","appId","localCharacterRef","localAvatarId","DEFAULT_AVATAR_ID","avatars","maxRemoteCharacters","enableNetworkSync","onConnectionStatusChange","exploreStore","useCaveExploreStore","remoteCharactersRef","useRef","remoteCharacters","setRemoteCharacters","useState","isJoined","setIsJoined","hasJoinedRef","publishRoster","useCallback","setRoomPlayers","players","room","handlePlayerUpdate","data","id","handlePlayerJoin","player","handlePlayerLeave","playerId","p","handleRoomSync","localPlayerId","next","handleJoinSuccess","formatRoomName","websocket","useCharacterSync","useEffect","interval","character","store","rendered","useMemo","avatarConfig","getAvatarConfig","jsx","Suspense","RemoteCharacter","roomId","hash","i"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Quaternion as QuaternionType, Vector3 as Vector3Type } from '../../types/index.js';
2
+ import { type AnimationName, type AvatarConfig } from './character-configs.js';
3
+ export interface RemoteCharacterProps {
4
+ userId: string;
5
+ characterConfig: AvatarConfig;
6
+ /** Latest network position; interpolated toward each frame. */
7
+ position?: Vector3Type;
8
+ /** Latest network rotation; interpolated toward each frame. */
9
+ rotation?: QuaternionType;
10
+ currentAnimation?: AnimationName;
11
+ }
12
+ /**
13
+ * Another player's avatar, driven purely by network state.
14
+ *
15
+ * Position and rotation are interpolated on the render loop rather than snapped,
16
+ * because updates arrive far slower than the frame rate.
17
+ */
18
+ export default function RemoteCharacter({ characterConfig, position, rotation, currentAnimation }: RemoteCharacterProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=remote-character.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-character.d.ts","sourceRoot":"","sources":["../../../explore/characters/remote-character.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAA;AAwB5B,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,YAAY,CAAA;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,gBAAgB,CAAC,EAAE,aAAa,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,gBAAgB,EACjB,EAAE,oBAAoB,+BAwGtB"}
@@ -0,0 +1,63 @@
1
+ import { jsx as P } from "react/jsx-runtime";
2
+ import { useGLTF as u, useAnimations as k } from "@react-three/drei";
3
+ import { useFrame as b } from "@react-three/fiber";
4
+ import { useRef as m, useMemo as x, useEffect as D, useCallback as y } from "react";
5
+ import { Vector3 as h, Quaternion as v, LoopOnce as H, LoopRepeat as Q } from "three";
6
+ import { clone as g } from "three/examples/jsm/utils/SkeletonUtils.js";
7
+ import { SUPPORTED_ANIMATION_NAMES as q } from "./character-configs.js";
8
+ const G = 0.1, V = 0.1, L = 0.2, W = /* @__PURE__ */ new Set(["jumpDown", "jumpUp", "jumpForward"]), z = 0.8;
9
+ function a(o, i, r) {
10
+ const c = o?.[0];
11
+ if (!c) return;
12
+ const s = c.clone();
13
+ s.name = i, r.push(s);
14
+ }
15
+ function nn({
16
+ characterConfig: o,
17
+ position: i,
18
+ rotation: r,
19
+ currentAnimation: c
20
+ }) {
21
+ const s = m(null), A = m(null), O = m({}), R = m(null), j = m(new h()), w = m(new v()), d = u(o.model.url), p = x(() => d.scene ? g(d.scene) : null, [d.scene]), T = u(o.animations.idle.url), _ = u(o.animations.walk.url), E = u(o.animations.run.url), I = u(o.animations.jumpDown.url), N = u(o.animations.jumpUp.url), S = u(o.animations.jumpForward.url), C = x(() => {
22
+ const n = [];
23
+ return a(T.animations, "idle", n), a(_.animations, "walk", n), a(E.animations, "run", n), a(I.animations, "jumpDown", n), a(N.animations, "jumpUp", n), a(S.animations, "jumpForward", n), n;
24
+ }, [
25
+ T.animations,
26
+ _.animations,
27
+ E.animations,
28
+ I.animations,
29
+ N.animations,
30
+ S.animations
31
+ ]), l = k(C, s);
32
+ D(() => {
33
+ if (!l || !p) return;
34
+ A.current = l.mixer;
35
+ const n = {};
36
+ for (const t of q) {
37
+ const e = l.clips.find((U) => U.name === t), M = s.current;
38
+ if (!e || !M) continue;
39
+ const f = l.mixer.clipAction(e, M);
40
+ W.has(t) ? (f.loop = H, f.clampWhenFinished = !0) : f.loop = Q, n[t] = f;
41
+ }
42
+ return O.current = n, () => {
43
+ for (const t of Object.values(n)) t.stop();
44
+ R.current = null;
45
+ };
46
+ }, [l, p]);
47
+ const F = y((n) => {
48
+ const t = O.current[n];
49
+ if (!A.current || !t) return;
50
+ const e = R.current;
51
+ e !== t && (e?.fadeOut(L), t.reset().fadeIn(L).play(), R.current = t);
52
+ }, []);
53
+ return D(() => {
54
+ i && j.current.set(i[0], i[1], i[2]), r && w.current.set(r[0], r[1], r[2], r[3]), c && F(c);
55
+ }, [i, r, c, F]), b((n, t) => {
56
+ const e = s.current;
57
+ e && (e.position.lerp(j.current, G), e.quaternion.slerp(w.current, V), A.current?.update(t));
58
+ }), /* @__PURE__ */ P("group", { ref: s, children: p ? /* @__PURE__ */ P("primitive", { scale: z, "rotation-y": Math.PI, object: p }) : null });
59
+ }
60
+ export {
61
+ nn as default
62
+ };
63
+ //# sourceMappingURL=remote-character.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-character.js","sources":["../../../explore/characters/remote-character.tsx"],"sourcesContent":["import { useAnimations, useGLTF } from '@react-three/drei'\nimport { useFrame } from '@react-three/fiber'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport type { AnimationClip, Group } from 'three'\nimport {\n LoopOnce,\n LoopRepeat,\n Quaternion,\n Vector3,\n type AnimationAction,\n type AnimationMixer\n} from 'three'\nimport { clone } from 'three/examples/jsm/utils/SkeletonUtils.js'\nimport type { Quaternion as QuaternionType, Vector3 as Vector3Type } from '../../types'\nimport {\n SUPPORTED_ANIMATION_NAMES,\n type AnimationName,\n type AvatarConfig\n} from './character-configs'\n\n/** Remote transforms arrive at ~10 Hz; these smooth them to display rate. */\nconst POSITION_LERP_FACTOR = 0.1\nconst ROTATION_LERP_FACTOR = 0.1\nconst ANIMATION_CROSSFADE_SEC = 0.2\n\nconst ONE_SHOT_ANIMATIONS = new Set<AnimationName>(['jumpDown', 'jumpUp', 'jumpForward'])\n\nconst REMOTE_CHARACTER_SCALE = 0.8\n\n/** Clips ship one per file; clone + rename so one mixer can address them all. */\nfunction pushClonedNamedClip(\n clips: AnimationClip[] | undefined,\n name: string,\n out: AnimationClip[]\n): void {\n const first = clips?.[0]\n if (!first) return\n const clip = first.clone()\n clip.name = name\n out.push(clip)\n}\n\nexport interface RemoteCharacterProps {\n userId: string\n characterConfig: AvatarConfig\n /** Latest network position; interpolated toward each frame. */\n position?: Vector3Type\n /** Latest network rotation; interpolated toward each frame. */\n rotation?: QuaternionType\n currentAnimation?: AnimationName\n}\n\n/**\n * Another player's avatar, driven purely by network state.\n *\n * Position and rotation are interpolated on the render loop rather than snapped,\n * because updates arrive far slower than the frame rate.\n */\nexport default function RemoteCharacter({\n characterConfig,\n position,\n rotation,\n currentAnimation\n}: RemoteCharacterProps) {\n const groupRef = useRef<Group>(null)\n const mixerRef = useRef<AnimationMixer | null>(null)\n const actionsRef = useRef<Record<string, AnimationAction>>({})\n const currentActionRef = useRef<AnimationAction | null>(null)\n\n const targetPositionRef = useRef(new Vector3())\n const targetQuaternionRef = useRef(new Quaternion())\n\n const gltf = useGLTF(characterConfig.model.url)\n const gltfScene = useMemo(() => (gltf.scene ? clone(gltf.scene) : null), [gltf.scene])\n\n const idleAnim = useGLTF(characterConfig.animations.idle.url)\n const walkAnim = useGLTF(characterConfig.animations.walk.url)\n const runAnim = useGLTF(characterConfig.animations.run.url)\n const jumpDownAnim = useGLTF(characterConfig.animations.jumpDown.url)\n const jumpUpAnim = useGLTF(characterConfig.animations.jumpUp.url)\n const jumpForwardAnim = useGLTF(characterConfig.animations.jumpForward.url)\n\n const allAnimations = useMemo(() => {\n const animations: AnimationClip[] = []\n pushClonedNamedClip(idleAnim.animations, 'idle', animations)\n pushClonedNamedClip(walkAnim.animations, 'walk', animations)\n pushClonedNamedClip(runAnim.animations, 'run', animations)\n pushClonedNamedClip(jumpDownAnim.animations, 'jumpDown', animations)\n pushClonedNamedClip(jumpUpAnim.animations, 'jumpUp', animations)\n pushClonedNamedClip(jumpForwardAnim.animations, 'jumpForward', animations)\n return animations\n }, [\n idleAnim.animations,\n walkAnim.animations,\n runAnim.animations,\n jumpDownAnim.animations,\n jumpUpAnim.animations,\n jumpForwardAnim.animations\n ])\n\n const animations = useAnimations(allAnimations, groupRef)\n\n useEffect(() => {\n if (!animations || !gltfScene) return\n\n mixerRef.current = animations.mixer\n const actions: Record<string, AnimationAction> = {}\n\n for (const name of SUPPORTED_ANIMATION_NAMES) {\n const clip = animations.clips.find((candidate) => candidate.name === name)\n const root = groupRef.current\n if (!clip || !root) continue\n\n const action = animations.mixer.clipAction(clip, root)\n if (ONE_SHOT_ANIMATIONS.has(name)) {\n action.loop = LoopOnce\n action.clampWhenFinished = true\n } else {\n action.loop = LoopRepeat\n }\n actions[name] = action\n }\n\n actionsRef.current = actions\n\n return () => {\n for (const action of Object.values(actions)) action.stop()\n currentActionRef.current = null\n }\n }, [animations, gltfScene])\n\n const playAnimation = useCallback((animationName: AnimationName) => {\n const nextAction = actionsRef.current[animationName]\n if (!mixerRef.current || !nextAction) return\n\n const currentAction = currentActionRef.current\n if (currentAction === nextAction) return\n\n currentAction?.fadeOut(ANIMATION_CROSSFADE_SEC)\n nextAction.reset().fadeIn(ANIMATION_CROSSFADE_SEC).play()\n currentActionRef.current = nextAction\n }, [])\n\n useEffect(() => {\n if (position) targetPositionRef.current.set(position[0], position[1], position[2])\n if (rotation) {\n targetQuaternionRef.current.set(rotation[0], rotation[1], rotation[2], rotation[3])\n }\n if (currentAnimation) playAnimation(currentAnimation)\n }, [position, rotation, currentAnimation, playAnimation])\n\n useFrame((_, delta) => {\n const group = groupRef.current\n if (!group) return\n\n group.position.lerp(targetPositionRef.current, POSITION_LERP_FACTOR)\n group.quaternion.slerp(targetQuaternionRef.current, ROTATION_LERP_FACTOR)\n mixerRef.current?.update(delta)\n })\n\n return (\n <group ref={groupRef}>\n {gltfScene ? (\n <primitive scale={REMOTE_CHARACTER_SCALE} rotation-y={Math.PI} object={gltfScene} />\n ) : null}\n </group>\n )\n}\n"],"names":["POSITION_LERP_FACTOR","ROTATION_LERP_FACTOR","ANIMATION_CROSSFADE_SEC","ONE_SHOT_ANIMATIONS","REMOTE_CHARACTER_SCALE","pushClonedNamedClip","clips","name","out","first","clip","RemoteCharacter","characterConfig","position","rotation","currentAnimation","groupRef","useRef","mixerRef","actionsRef","currentActionRef","targetPositionRef","Vector3","targetQuaternionRef","Quaternion","gltf","useGLTF","gltfScene","useMemo","clone","idleAnim","walkAnim","runAnim","jumpDownAnim","jumpUpAnim","jumpForwardAnim","allAnimations","animations","useAnimations","useEffect","actions","SUPPORTED_ANIMATION_NAMES","candidate","root","action","LoopOnce","LoopRepeat","playAnimation","useCallback","animationName","nextAction","currentAction","useFrame","_","delta","group","jsx"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface ConnectedSpacesRendererProps {
2
+ primarySpaceId: string | undefined;
3
+ revealOnEnter: boolean;
4
+ connectorLabels: boolean;
5
+ onPrimaryInitialized: () => void;
6
+ }
7
+ /**
8
+ * Render every loaded space — the primary plus its preloaded neighbors — with
9
+ * visibility, physics, and connector sensors gated on the active space id, and
10
+ * group matrices driven by the computed seamless transforms.
11
+ *
12
+ * Neighbors stay mounted (hidden) so their splat meshes remain in GPU memory,
13
+ * which is what makes a seamless transition instant.
14
+ */
15
+ export default function ConnectedSpacesRenderer({ primarySpaceId, revealOnEnter, connectorLabels, onPrimaryInitialized }: ConnectedSpacesRendererProps): import("react").JSX.Element;
16
+ //# sourceMappingURL=connected-spaces-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connected-spaces-renderer.d.ts","sourceRoot":"","sources":["../../explore/connected-spaces-renderer.tsx"],"names":[],"mappings":"AAwHA,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,EAAE,OAAO,CAAA;IACxB,oBAAoB,EAAE,MAAM,IAAI,CAAA;CACjC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,EAC9C,cAAc,EACd,aAAa,EACb,eAAe,EACf,oBAAoB,EACrB,EAAE,4BAA4B,+BA6B9B"}
@@ -0,0 +1,103 @@
1
+ import { jsx as s, Fragment as I } from "react/jsx-runtime";
2
+ import { useMemo as l, memo as v, useCallback as b, Suspense as x } from "react";
3
+ import { Matrix4 as E } from "three";
4
+ import { useCaveEventBus as h } from "../core/context/cave-world-context.js";
5
+ import y from "../space/cave-space.js";
6
+ import { useCaveExplore as f, useCaveExploreStore as g } from "./stores/explore-context.js";
7
+ const j = /* @__PURE__ */ Object.freeze({}), k = v(function({
8
+ id: t,
9
+ space: p,
10
+ active: n,
11
+ isPrimary: c,
12
+ revealOnEnter: a,
13
+ connectorLabels: d,
14
+ onPrimaryInitialized: o,
15
+ connectedSpaces: m,
16
+ readySpaceIds: u,
17
+ activeConnectorId: e
18
+ }) {
19
+ const r = g(), S = h(), C = b(() => {
20
+ r.getState().markSpaceReady(t), S.emit("space:transfer:ready", { spaceId: t }), c && o();
21
+ }, [t, r, S, c, o]);
22
+ return /* @__PURE__ */ s(x, { fallback: null, children: /* @__PURE__ */ s(
23
+ y,
24
+ {
25
+ space: p,
26
+ spaceId: t,
27
+ physics: n,
28
+ active: n,
29
+ connectedSpaces: m,
30
+ readySpaceIds: u,
31
+ activeConnectorId: e,
32
+ connectorLabels: d,
33
+ revealOnEnter: a && c,
34
+ onInitialized: C
35
+ }
36
+ ) });
37
+ }), M = v(function({
38
+ id: t,
39
+ space: p,
40
+ m16: n,
41
+ isActive: c,
42
+ isPrimary: a,
43
+ revealOnEnter: d,
44
+ connectorLabels: o,
45
+ onPrimaryInitialized: m,
46
+ connectedSpaces: u,
47
+ readySpaceIds: e,
48
+ activeConnectorId: r
49
+ }) {
50
+ const S = l(() => n ? new E().fromArray(n) : void 0, [n]);
51
+ return /* @__PURE__ */ s(
52
+ "group",
53
+ {
54
+ visible: c,
55
+ name: a ? "cave-space-primary" : `cave-space-connected-${t}`,
56
+ ...S ? { matrix: S, matrixAutoUpdate: !1 } : {},
57
+ children: /* @__PURE__ */ s(
58
+ k,
59
+ {
60
+ id: t,
61
+ space: p,
62
+ active: c,
63
+ isPrimary: a,
64
+ revealOnEnter: d,
65
+ connectorLabels: o,
66
+ onPrimaryInitialized: m,
67
+ connectedSpaces: u,
68
+ readySpaceIds: c ? e : j,
69
+ activeConnectorId: c ? r : void 0
70
+ }
71
+ )
72
+ }
73
+ );
74
+ });
75
+ function B({
76
+ primarySpaceId: i,
77
+ revealOnEnter: t,
78
+ connectorLabels: p,
79
+ onPrimaryInitialized: n
80
+ }) {
81
+ const c = f((e) => e.activeSpaceId), a = f((e) => e.connectedSpaces), d = f((e) => e.readySpaceIds), o = f((e) => e.spaceTransforms), m = f((e) => e.activeConnector?.id), u = l(() => Object.entries(a), [a]);
82
+ return /* @__PURE__ */ s(I, { children: u.map(([e, r]) => /* @__PURE__ */ s(
83
+ M,
84
+ {
85
+ id: e,
86
+ space: r,
87
+ m16: o[e],
88
+ isActive: c === e,
89
+ isPrimary: e === i,
90
+ revealOnEnter: t,
91
+ connectorLabels: p,
92
+ onPrimaryInitialized: n,
93
+ connectedSpaces: a,
94
+ readySpaceIds: d,
95
+ activeConnectorId: m
96
+ },
97
+ e
98
+ )) });
99
+ }
100
+ export {
101
+ B as default
102
+ };
103
+ //# sourceMappingURL=connected-spaces-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connected-spaces-renderer.js","sources":["../../explore/connected-spaces-renderer.tsx"],"sourcesContent":["import { memo, Suspense, useCallback, useMemo } from 'react'\nimport { Matrix4 } from 'three'\nimport { useCaveEventBus } from '../core'\nimport { CaveSpace } from '../space'\nimport type { CaveSpace as CaveSpaceConfig, Matrix16 } from '../types'\nimport { useCaveExplore, useCaveExploreStore } from './stores/explore-context'\n\nconst EMPTY_READY_SPACE_IDS = /* @__PURE__ */ Object.freeze({}) as Record<string, true>\n\ninterface SpaceSubtreeProps {\n id: string\n space: CaveSpaceConfig\n active: boolean\n isPrimary: boolean\n revealOnEnter: boolean\n connectorLabels: boolean\n onPrimaryInitialized: () => void\n connectedSpaces: Record<string, CaveSpaceConfig>\n readySpaceIds: Record<string, true>\n activeConnectorId?: string\n}\n\n/**\n * One space's content.\n *\n * Memoised so a re-render caused by *another* space's matrix or active flag\n * doesn't cascade into this subtree's expensive parts (splat mesh, per-object\n * Suspense boundaries). Its own Suspense boundary keeps a still-streaming\n * sibling from blanking the whole canvas.\n */\nconst SpaceSubtree = memo(function SpaceSubtree({\n id,\n space,\n active,\n isPrimary,\n revealOnEnter,\n connectorLabels,\n onPrimaryInitialized,\n connectedSpaces,\n readySpaceIds,\n activeConnectorId\n}: SpaceSubtreeProps) {\n const store = useCaveExploreStore()\n const eventBus = useCaveEventBus()\n\n const handleInitialized = useCallback(() => {\n store.getState().markSpaceReady(id)\n eventBus.emit('space:transfer:ready', { spaceId: id })\n if (isPrimary) onPrimaryInitialized()\n }, [id, store, eventBus, isPrimary, onPrimaryInitialized])\n\n return (\n <Suspense fallback={null}>\n <CaveSpace\n space={space}\n spaceId={id}\n physics={active}\n active={active}\n connectedSpaces={connectedSpaces}\n readySpaceIds={readySpaceIds}\n activeConnectorId={activeConnectorId}\n connectorLabels={connectorLabels}\n revealOnEnter={revealOnEnter && isPrimary}\n onInitialized={handleInitialized}\n />\n </Suspense>\n )\n})\n\ninterface ConnectedSpaceGroupProps extends Omit<SpaceSubtreeProps, 'active'> {\n m16: Matrix16 | undefined\n isActive: boolean\n}\n\n/**\n * A space's world-space group plus its subtree.\n *\n * The `Matrix4` is derived from this space's own `Matrix16`, so a neighbor load\n * that changes one space's transform doesn't re-allocate every other space's\n * matrix — unchanged spaces keep a stable `matrix` prop reference.\n */\nconst ConnectedSpaceGroup = memo(function ConnectedSpaceGroup({\n id,\n space,\n m16,\n isActive,\n isPrimary,\n revealOnEnter,\n connectorLabels,\n onPrimaryInitialized,\n connectedSpaces,\n readySpaceIds,\n activeConnectorId\n}: ConnectedSpaceGroupProps) {\n const matrix = useMemo(() => (m16 ? new Matrix4().fromArray(m16) : undefined), [m16])\n\n return (\n <group\n visible={isActive}\n name={isPrimary ? 'cave-space-primary' : `cave-space-connected-${id}`}\n {...(matrix ? { matrix, matrixAutoUpdate: false } : {})}\n >\n <SpaceSubtree\n id={id}\n space={space}\n active={isActive}\n isPrimary={isPrimary}\n revealOnEnter={revealOnEnter}\n connectorLabels={connectorLabels}\n onPrimaryInitialized={onPrimaryInitialized}\n connectedSpaces={connectedSpaces}\n // Inactive spaces don't render connector UI, so hand them frozen empty\n // inputs and keep their memo from invalidating on unrelated updates.\n readySpaceIds={isActive ? readySpaceIds : EMPTY_READY_SPACE_IDS}\n activeConnectorId={isActive ? activeConnectorId : undefined}\n />\n </group>\n )\n})\n\nexport interface ConnectedSpacesRendererProps {\n primarySpaceId: string | undefined\n revealOnEnter: boolean\n connectorLabels: boolean\n onPrimaryInitialized: () => void\n}\n\n/**\n * Render every loaded space — the primary plus its preloaded neighbors — with\n * visibility, physics, and connector sensors gated on the active space id, and\n * group matrices driven by the computed seamless transforms.\n *\n * Neighbors stay mounted (hidden) so their splat meshes remain in GPU memory,\n * which is what makes a seamless transition instant.\n */\nexport default function ConnectedSpacesRenderer({\n primarySpaceId,\n revealOnEnter,\n connectorLabels,\n onPrimaryInitialized\n}: ConnectedSpacesRendererProps) {\n const activeSpaceId = useCaveExplore((s) => s.activeSpaceId)\n const connectedSpaces = useCaveExplore((s) => s.connectedSpaces)\n const readySpaceIds = useCaveExplore((s) => s.readySpaceIds)\n const spaceTransforms = useCaveExplore((s) => s.spaceTransforms)\n const activeConnectorId = useCaveExplore((s) => s.activeConnector?.id)\n\n const entries = useMemo(() => Object.entries(connectedSpaces), [connectedSpaces])\n\n return (\n <>\n {entries.map(([id, space]) => (\n <ConnectedSpaceGroup\n key={id}\n id={id}\n space={space}\n m16={spaceTransforms[id]}\n isActive={activeSpaceId === id}\n isPrimary={id === primarySpaceId}\n revealOnEnter={revealOnEnter}\n connectorLabels={connectorLabels}\n onPrimaryInitialized={onPrimaryInitialized}\n connectedSpaces={connectedSpaces}\n readySpaceIds={readySpaceIds}\n activeConnectorId={activeConnectorId}\n />\n ))}\n </>\n )\n}\n"],"names":["EMPTY_READY_SPACE_IDS","SpaceSubtree","memo","id","space","active","isPrimary","revealOnEnter","connectorLabels","onPrimaryInitialized","connectedSpaces","readySpaceIds","activeConnectorId","store","useCaveExploreStore","eventBus","useCaveEventBus","handleInitialized","useCallback","jsx","Suspense","CaveSpace","ConnectedSpaceGroup","m16","isActive","matrix","useMemo","Matrix4","ConnectedSpacesRenderer","primarySpaceId","activeSpaceId","useCaveExplore","s","spaceTransforms","entries"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Register a single global keydown listener that resolves the pressed key
3
+ * against the current action prompt.
4
+ *
5
+ * Deliberately reads through `store.getState()` instead of subscribing to
6
+ * `actions`. Subscribing would re-render the component hosting this hook —
7
+ * the parent of `<ExploreSimpleCharacter>` — on every prompt show/hide, and
8
+ * that cascade hits a bug in `@react-three/viverse`'s
9
+ * `useSimpleCharacterActionBindings`: its dep-less effect recreates the
10
+ * keyboard bindings on every render (the `instanceof` guard can never pass),
11
+ * and a fresh `KeyboardActionBinding` starts with an empty `pressedKeys` set.
12
+ * The visible symptom is the character stopping mid-walk whenever a connector
13
+ * prompt appears.
14
+ */
15
+ export declare function useActionShortcuts(): void;
16
+ //# sourceMappingURL=use-action-shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-action-shortcuts.d.ts","sourceRoot":"","sources":["../../../explore/hooks/use-action-shortcuts.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CA0BzC"}
@@ -0,0 +1,23 @@
1
+ import { useEffect as c } from "react";
2
+ import { useActionPromptStore as i } from "../stores/explore-context.js";
3
+ function f() {
4
+ const o = i();
5
+ c(() => {
6
+ const r = (t) => {
7
+ if (t.target instanceof HTMLInputElement || t.target instanceof HTMLTextAreaElement || t.repeat || t.metaKey || t.ctrlKey || t.altKey) return;
8
+ const { actions: n } = o.getState();
9
+ if (n.length === 0) return;
10
+ const s = t.key.toLowerCase();
11
+ for (const e of n)
12
+ if (!(e.disabled || !e.shortcut) && s === e.shortcut.toLowerCase()) {
13
+ t.preventDefault(), e.onAction();
14
+ return;
15
+ }
16
+ };
17
+ return document.addEventListener("keydown", r), () => document.removeEventListener("keydown", r);
18
+ }, [o]);
19
+ }
20
+ export {
21
+ f as useActionShortcuts
22
+ };
23
+ //# sourceMappingURL=use-action-shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-action-shortcuts.js","sources":["../../../explore/hooks/use-action-shortcuts.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport { useActionPromptStore } from '../stores/explore-context'\n\n/**\n * Register a single global keydown listener that resolves the pressed key\n * against the current action prompt.\n *\n * Deliberately reads through `store.getState()` instead of subscribing to\n * `actions`. Subscribing would re-render the component hosting this hook —\n * the parent of `<ExploreSimpleCharacter>` — on every prompt show/hide, and\n * that cascade hits a bug in `@react-three/viverse`'s\n * `useSimpleCharacterActionBindings`: its dep-less effect recreates the\n * keyboard bindings on every render (the `instanceof` guard can never pass),\n * and a fresh `KeyboardActionBinding` starts with an empty `pressedKeys` set.\n * The visible symptom is the character stopping mid-walk whenever a connector\n * prompt appears.\n */\nexport function useActionShortcuts(): void {\n const store = useActionPromptStore()\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.target instanceof HTMLInputElement) return\n if (event.target instanceof HTMLTextAreaElement) return\n if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return\n\n const { actions } = store.getState()\n if (actions.length === 0) return\n\n const pressed = event.key.toLowerCase()\n for (const action of actions) {\n if (action.disabled || !action.shortcut) continue\n if (pressed === action.shortcut.toLowerCase()) {\n event.preventDefault()\n action.onAction()\n return\n }\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [store])\n}\n"],"names":["useActionShortcuts","store","useActionPromptStore","useEffect","handleKeyDown","event","actions","pressed","action"],"mappings":";;AAiBO,SAASA,IAA2B;AACzC,QAAMC,IAAQC,EAAA;AAEd,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAgB,CAACC,MAAyB;AAG9C,UAFIA,EAAM,kBAAkB,oBACxBA,EAAM,kBAAkB,uBACxBA,EAAM,UAAUA,EAAM,WAAWA,EAAM,WAAWA,EAAM,OAAQ;AAEpE,YAAM,EAAE,SAAAC,EAAA,IAAYL,EAAM,SAAA;AAC1B,UAAIK,EAAQ,WAAW,EAAG;AAE1B,YAAMC,IAAUF,EAAM,IAAI,YAAA;AAC1B,iBAAWG,KAAUF;AACnB,YAAI,EAAAE,EAAO,YAAY,CAACA,EAAO,aAC3BD,MAAYC,EAAO,SAAS,YAAA,GAAe;AAC7C,UAAAH,EAAM,eAAA,GACNG,EAAO,SAAA;AACP;AAAA,QACF;AAAA,IAEJ;AAEA,oBAAS,iBAAiB,WAAWJ,CAAa,GAC3C,MAAM,SAAS,oBAAoB,WAAWA,CAAa;AAAA,EACpE,GAAG,CAACH,CAAK,CAAC;AACZ;"}
@@ -0,0 +1,11 @@
1
+ import type { CaveSpace } from '../../types/index.js';
2
+ /**
3
+ * Notify the host of the scene the player is currently in — once for the
4
+ * initial scene and again after every seamless / portal transition.
5
+ *
6
+ * Uses an imperative store subscription rather than a selector so a scene change
7
+ * doesn't re-render the (heavy) viewer subtree just to fire a callback, and
8
+ * reads the latest callback from a ref.
9
+ */
10
+ export declare function useActiveSpaceNotify(onActiveSpaceChange?: (spaceId: string, space?: CaveSpace) => void): void;
11
+ //# sourceMappingURL=use-active-space-notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-active-space-notify.d.ts","sourceRoot":"","sources":["../../../explore/hooks/use-active-space-notify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG5C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,IAAI,GACjE,IAAI,CAmBN"}
@@ -0,0 +1,17 @@
1
+ import { useRef as f, useEffect as s } from "react";
2
+ import { useCaveExploreStore as u } from "../stores/explore-context.js";
3
+ function i(r) {
4
+ const t = u(), c = f(r);
5
+ s(() => {
6
+ c.current = r;
7
+ }, [r]), s(() => {
8
+ const o = (e) => {
9
+ e && c.current?.(e, t.getState().connectedSpaces[e]);
10
+ };
11
+ return o(t.getState().activeSpaceId), t.subscribe((e) => e.activeSpaceId, o);
12
+ }, [t]);
13
+ }
14
+ export {
15
+ i as useActiveSpaceNotify
16
+ };
17
+ //# sourceMappingURL=use-active-space-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-active-space-notify.js","sources":["../../../explore/hooks/use-active-space-notify.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport type { CaveSpace } from '../../types'\nimport { useCaveExploreStore } from '../stores/explore-context'\n\n/**\n * Notify the host of the scene the player is currently in — once for the\n * initial scene and again after every seamless / portal transition.\n *\n * Uses an imperative store subscription rather than a selector so a scene change\n * doesn't re-render the (heavy) viewer subtree just to fire a callback, and\n * reads the latest callback from a ref.\n */\nexport function useActiveSpaceNotify(\n onActiveSpaceChange?: (spaceId: string, space?: CaveSpace) => void\n): void {\n const store = useCaveExploreStore()\n const callbackRef = useRef(onActiveSpaceChange)\n\n useEffect(() => {\n callbackRef.current = onActiveSpaceChange\n }, [onActiveSpaceChange])\n\n useEffect(() => {\n const notify = (id: string | undefined) => {\n if (!id) return\n // Pass the active scene's loaded config so hosts can read metadata\n // (e.g. `metadata.name`) straight from the JSON — no external name maps.\n callbackRef.current?.(id, store.getState().connectedSpaces[id])\n }\n\n notify(store.getState().activeSpaceId)\n return store.subscribe((state) => state.activeSpaceId, notify)\n }, [store])\n}\n"],"names":["useActiveSpaceNotify","onActiveSpaceChange","store","useCaveExploreStore","callbackRef","useRef","useEffect","notify","id","state"],"mappings":";;AAYO,SAASA,EACdC,GACM;AACN,QAAMC,IAAQC,EAAA,GACRC,IAAcC,EAAOJ,CAAmB;AAE9C,EAAAK,EAAU,MAAM;AACd,IAAAF,EAAY,UAAUH;AAAA,EACxB,GAAG,CAACA,CAAmB,CAAC,GAExBK,EAAU,MAAM;AACd,UAAMC,IAAS,CAACC,MAA2B;AACzC,MAAKA,KAGLJ,EAAY,UAAUI,GAAIN,EAAM,WAAW,gBAAgBM,CAAE,CAAC;AAAA,IAChE;AAEA,WAAAD,EAAOL,EAAM,SAAA,EAAW,aAAa,GAC9BA,EAAM,UAAU,CAACO,MAAUA,EAAM,eAAeF,CAAM;AAAA,EAC/D,GAAG,CAACL,CAAK,CAAC;AACZ;"}