@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,180 @@
1
+ import type { Vector3 as Vector3Type, Quaternion as QuaternionType } from '../../types/index.js';
2
+ import type { AnimationName } from '../characters/character-configs.js';
3
+ /**
4
+ * CaveGiant public demo multiplayer endpoint.
5
+ *
6
+ * Exported for demos and CaveGiant-hosted apps. Production integrators must
7
+ * pass their own `multiplayer.url` — the SDK does not connect here unless you
8
+ * opt in explicitly.
9
+ */
10
+ export declare const DEFAULT_WEBSOCKET_URL = "wss://api-live-mbspace.cavegiant.com/gameplay";
11
+ /** Connection lifecycle for {@link WebSocketService}. */
12
+ export declare const WebSocketStatusEnum: {
13
+ readonly CONNECTING: "connecting";
14
+ readonly CONNECTED: "connected";
15
+ readonly DISCONNECTED: "disconnected";
16
+ readonly RECONNECTING: "reconnecting";
17
+ readonly ERROR: "error";
18
+ };
19
+ export type WebSocketStatus = (typeof WebSocketStatusEnum)[keyof typeof WebSocketStatusEnum];
20
+ /** Wire protocol actions — see `doc/multiplayer-protocol.md`. */
21
+ export declare const MessageActionEnum: {
22
+ readonly JOIN_GAME: "JOIN_GAME";
23
+ readonly UPDATE_STATE: "UPDATE_STATE";
24
+ readonly SYNC_STATE: "SYNC_STATE";
25
+ readonly PING: "PING";
26
+ readonly JOIN_SUCCESS: "JOIN_SUCCESS";
27
+ readonly PLAYER_JOINED: "PLAYER_JOINED";
28
+ readonly PLAYER_LEFT: "PLAYER_LEFT";
29
+ readonly STATE_UPDATE: "STATE_UPDATE";
30
+ readonly STATE_SYNC: "STATE_SYNC";
31
+ readonly PONG: "PONG";
32
+ readonly ERROR: "ERROR";
33
+ };
34
+ export type MessageAction = (typeof MessageActionEnum)[keyof typeof MessageActionEnum];
35
+ export interface BaseMessage {
36
+ action: MessageAction;
37
+ data: unknown;
38
+ }
39
+ export interface PlayerData {
40
+ id: string;
41
+ position?: Vector3Type;
42
+ rotation?: QuaternionType;
43
+ animation?: AnimationName;
44
+ avatarId?: string;
45
+ lastUpdate?: number;
46
+ }
47
+ export interface JoinGameMessage extends BaseMessage {
48
+ action: typeof MessageActionEnum.JOIN_GAME;
49
+ data: {
50
+ appId: string;
51
+ avatarId: string;
52
+ };
53
+ }
54
+ export interface UpdateStateMessage extends BaseMessage {
55
+ action: typeof MessageActionEnum.UPDATE_STATE;
56
+ data: {
57
+ position?: Vector3Type;
58
+ rotation?: QuaternionType;
59
+ animation?: AnimationName;
60
+ avatarId?: string;
61
+ };
62
+ }
63
+ export interface SyncStateMessage extends BaseMessage {
64
+ action: typeof MessageActionEnum.SYNC_STATE;
65
+ data: unknown;
66
+ }
67
+ export interface PingMessage extends BaseMessage {
68
+ action: typeof MessageActionEnum.PING;
69
+ data: unknown;
70
+ }
71
+ export interface JoinSuccessMessage extends BaseMessage {
72
+ action: typeof MessageActionEnum.JOIN_SUCCESS;
73
+ data: {
74
+ roomId: string;
75
+ playerId: string;
76
+ players: PlayerData[];
77
+ isRejoin: boolean;
78
+ };
79
+ }
80
+ export interface PlayerJoinedMessage extends BaseMessage {
81
+ action: typeof MessageActionEnum.PLAYER_JOINED;
82
+ data: PlayerData & {
83
+ playerId: string;
84
+ };
85
+ }
86
+ export interface PlayerLeftMessage extends BaseMessage {
87
+ action: typeof MessageActionEnum.PLAYER_LEFT;
88
+ data: {
89
+ playerId: string;
90
+ };
91
+ }
92
+ export interface StateUpdateMessage extends BaseMessage {
93
+ action: typeof MessageActionEnum.STATE_UPDATE;
94
+ data: PlayerData & {
95
+ playerId: string;
96
+ };
97
+ }
98
+ export interface StateSyncMessage extends BaseMessage {
99
+ action: typeof MessageActionEnum.STATE_SYNC;
100
+ data: {
101
+ players: PlayerData[];
102
+ };
103
+ }
104
+ export interface PongMessage extends BaseMessage {
105
+ action: typeof MessageActionEnum.PONG;
106
+ data: {
107
+ timestamp: number;
108
+ };
109
+ }
110
+ export interface ErrorMessage extends BaseMessage {
111
+ action: typeof MessageActionEnum.ERROR;
112
+ data: {
113
+ error_code: string;
114
+ error_msg: string;
115
+ };
116
+ }
117
+ export type WebSocketMessage = JoinGameMessage | UpdateStateMessage | SyncStateMessage | PingMessage | JoinSuccessMessage | PlayerJoinedMessage | PlayerLeftMessage | StateUpdateMessage | StateSyncMessage | PongMessage | ErrorMessage;
118
+ export type MessageListener = (message: WebSocketMessage) => void;
119
+ export type StatusListener = (status: WebSocketStatus) => void;
120
+ export type ErrorListener = (error: Event) => void;
121
+ export interface WebSocketConfig {
122
+ /** Required realtime endpoint (`wss://…`). */
123
+ url: string;
124
+ reconnectInterval?: number;
125
+ maxReconnectAttempts?: number;
126
+ pingInterval?: number;
127
+ timeout?: number;
128
+ }
129
+ /**
130
+ * Thin WebSocket client for the multiplayer protocol.
131
+ *
132
+ * Construct with an explicit `url`. Use {@link DEFAULT_WEBSOCKET_URL} only when
133
+ * you intentionally want the CaveGiant demo backend.
134
+ */
135
+ export declare class WebSocketService {
136
+ private ws;
137
+ private config;
138
+ private status;
139
+ private reconnectAttempts;
140
+ private reconnectTimer;
141
+ private pingTimer;
142
+ private messageListeners;
143
+ private statusListeners;
144
+ private errorListeners;
145
+ constructor(config: WebSocketConfig);
146
+ /** Open the socket (or resolve immediately if already connected). */
147
+ connect(): Promise<void>;
148
+ /** Close the socket and cancel reconnect / ping timers. */
149
+ disconnect(): void;
150
+ /** Send a protocol message. Returns false when the socket is not connected. */
151
+ send(message: WebSocketMessage): boolean;
152
+ /** Join (or rejoin) a room identified by `appId`. */
153
+ joinGame(appId: string, avatarId: string): boolean;
154
+ /** Publish the local player's transform / animation. */
155
+ updateState(data: {
156
+ position?: Vector3Type;
157
+ rotation?: QuaternionType;
158
+ animation?: AnimationName;
159
+ avatarId?: string;
160
+ }): boolean;
161
+ /** Request a full room state snapshot from the server. */
162
+ syncState(): boolean;
163
+ /** Application-level heartbeat. */
164
+ ping(): boolean;
165
+ addMessageListener(listener: MessageListener): () => void;
166
+ addStatusListener(listener: StatusListener): () => void;
167
+ addErrorListener(listener: ErrorListener): () => void;
168
+ getStatus(): WebSocketStatus;
169
+ isConnected(): boolean;
170
+ private handleMessage;
171
+ private setStatus;
172
+ private notifyErrorListeners;
173
+ private scheduleReconnect;
174
+ private stopReconnect;
175
+ private startPing;
176
+ private stopPing;
177
+ /** Disconnect and drop all listeners. */
178
+ destroy(): void;
179
+ }
180
+ //# sourceMappingURL=websocket.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.service.d.ts","sourceRoot":"","sources":["../../../explore/services/websocket.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ import { createLogger as c } from "../../core/logging/logger.js";
2
+ const i = c("multiplayer:socket"), u = "wss://api-live-mbspace.cavegiant.com/gameplay", r = {
3
+ CONNECTING: "connecting",
4
+ CONNECTED: "connected",
5
+ DISCONNECTED: "disconnected",
6
+ RECONNECTING: "reconnecting",
7
+ ERROR: "error"
8
+ }, o = {
9
+ JOIN_GAME: "JOIN_GAME",
10
+ UPDATE_STATE: "UPDATE_STATE",
11
+ SYNC_STATE: "SYNC_STATE",
12
+ PING: "PING",
13
+ JOIN_SUCCESS: "JOIN_SUCCESS",
14
+ PLAYER_JOINED: "PLAYER_JOINED",
15
+ PLAYER_LEFT: "PLAYER_LEFT",
16
+ STATE_UPDATE: "STATE_UPDATE",
17
+ STATE_SYNC: "STATE_SYNC",
18
+ PONG: "PONG",
19
+ ERROR: "ERROR"
20
+ }, a = {
21
+ reconnectInterval: 3e3,
22
+ maxReconnectAttempts: 5,
23
+ pingInterval: 3e4,
24
+ timeout: 1e4
25
+ };
26
+ class T {
27
+ ws = null;
28
+ config;
29
+ status = r.DISCONNECTED;
30
+ reconnectAttempts = 0;
31
+ reconnectTimer = null;
32
+ pingTimer = null;
33
+ messageListeners = /* @__PURE__ */ new Set();
34
+ statusListeners = /* @__PURE__ */ new Set();
35
+ errorListeners = /* @__PURE__ */ new Set();
36
+ constructor(t) {
37
+ if (!t.url)
38
+ throw new Error("WebSocketService requires config.url");
39
+ this.config = { ...a, ...t };
40
+ }
41
+ /** Open the socket (or resolve immediately if already connected). */
42
+ connect() {
43
+ return new Promise((t, e) => {
44
+ if (this.status === r.CONNECTED) {
45
+ t();
46
+ return;
47
+ }
48
+ this.setStatus(r.CONNECTING);
49
+ try {
50
+ this.ws = new WebSocket(this.config.url);
51
+ const s = setTimeout(() => {
52
+ this.ws?.readyState === WebSocket.CONNECTING && (this.ws.close(), e(new Error("Connection timeout")));
53
+ }, this.config.timeout);
54
+ this.ws.onopen = () => {
55
+ clearTimeout(s), this.setStatus(r.CONNECTED), this.reconnectAttempts = 0, this.startPing(), t();
56
+ }, this.ws.onclose = (n) => {
57
+ clearTimeout(s), this.setStatus(r.DISCONNECTED), this.stopPing(), !n.wasClean && this.reconnectAttempts < this.config.maxReconnectAttempts && this.scheduleReconnect();
58
+ }, this.ws.onerror = (n) => {
59
+ clearTimeout(s), this.setStatus(r.ERROR), this.notifyErrorListeners(n), e(n);
60
+ }, this.ws.onmessage = (n) => {
61
+ this.handleMessage(n);
62
+ };
63
+ } catch (s) {
64
+ this.setStatus(r.ERROR), e(s);
65
+ }
66
+ });
67
+ }
68
+ /** Close the socket and cancel reconnect / ping timers. */
69
+ disconnect() {
70
+ this.stopReconnect(), this.stopPing(), this.ws && (this.ws.close(1e3, "Client disconnect"), this.ws = null), this.setStatus(r.DISCONNECTED);
71
+ }
72
+ /** Send a protocol message. Returns false when the socket is not connected. */
73
+ send(t) {
74
+ if (this.status !== r.CONNECTED || !this.ws)
75
+ return i.warn("WebSocket not connected, cannot send message"), !1;
76
+ try {
77
+ return this.ws.send(JSON.stringify(t)), !0;
78
+ } catch (e) {
79
+ return i.error("Failed to send message:", e), !1;
80
+ }
81
+ }
82
+ /** Join (or rejoin) a room identified by `appId`. */
83
+ joinGame(t, e) {
84
+ return this.send({
85
+ action: o.JOIN_GAME,
86
+ data: { appId: t, avatarId: e }
87
+ });
88
+ }
89
+ /** Publish the local player's transform / animation. */
90
+ updateState(t) {
91
+ return this.send({
92
+ action: o.UPDATE_STATE,
93
+ data: t
94
+ });
95
+ }
96
+ /** Request a full room state snapshot from the server. */
97
+ syncState() {
98
+ return this.send({
99
+ action: o.SYNC_STATE,
100
+ data: {}
101
+ });
102
+ }
103
+ /** Application-level heartbeat. */
104
+ ping() {
105
+ return this.send({
106
+ action: o.PING,
107
+ data: {}
108
+ });
109
+ }
110
+ addMessageListener(t) {
111
+ return this.messageListeners.add(t), () => this.messageListeners.delete(t);
112
+ }
113
+ addStatusListener(t) {
114
+ return this.statusListeners.add(t), () => this.statusListeners.delete(t);
115
+ }
116
+ addErrorListener(t) {
117
+ return this.errorListeners.add(t), () => this.errorListeners.delete(t);
118
+ }
119
+ getStatus() {
120
+ return this.status;
121
+ }
122
+ isConnected() {
123
+ return this.status === r.CONNECTED;
124
+ }
125
+ handleMessage(t) {
126
+ try {
127
+ const e = JSON.parse(t.data);
128
+ if (e.action === o.PONG)
129
+ return;
130
+ this.messageListeners.forEach((s) => {
131
+ try {
132
+ s(e);
133
+ } catch (n) {
134
+ i.error("Error in message listener:", n);
135
+ }
136
+ });
137
+ } catch (e) {
138
+ i.error("Failed to parse WebSocket message:", e);
139
+ }
140
+ }
141
+ setStatus(t) {
142
+ this.status !== t && (this.status = t, this.statusListeners.forEach((e) => {
143
+ try {
144
+ e(t);
145
+ } catch (s) {
146
+ i.error("Error in status listener:", s);
147
+ }
148
+ }));
149
+ }
150
+ notifyErrorListeners(t) {
151
+ this.errorListeners.forEach((e) => {
152
+ try {
153
+ e(t);
154
+ } catch (s) {
155
+ i.error("Error in error listener:", s);
156
+ }
157
+ });
158
+ }
159
+ scheduleReconnect() {
160
+ this.reconnectTimer || (this.setStatus(r.RECONNECTING), this.reconnectAttempts++, this.reconnectTimer = setTimeout(() => {
161
+ this.reconnectTimer = null, this.connect().catch(() => {
162
+ });
163
+ }, this.config.reconnectInterval));
164
+ }
165
+ stopReconnect() {
166
+ this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = null);
167
+ }
168
+ startPing() {
169
+ this.stopPing(), this.pingTimer = setInterval(() => {
170
+ this.isConnected() && this.ping();
171
+ }, this.config.pingInterval);
172
+ }
173
+ stopPing() {
174
+ this.pingTimer && (clearInterval(this.pingTimer), this.pingTimer = null);
175
+ }
176
+ /** Disconnect and drop all listeners. */
177
+ destroy() {
178
+ this.disconnect(), this.messageListeners.clear(), this.statusListeners.clear(), this.errorListeners.clear();
179
+ }
180
+ }
181
+ export {
182
+ u as DEFAULT_WEBSOCKET_URL,
183
+ o as MessageActionEnum,
184
+ T as WebSocketService,
185
+ r as WebSocketStatusEnum
186
+ };
187
+ //# sourceMappingURL=websocket.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.service.js","sources":["../../../explore/services/websocket.service.ts"],"sourcesContent":["import { createLogger } from '../../core'\nimport type { Vector3 as Vector3Type, Quaternion as QuaternionType } from '../../types'\nimport type { AnimationName } from '../characters/character-configs'\n\nconst logger = createLogger('multiplayer:socket')\n\n/**\n * CaveGiant public demo multiplayer endpoint.\n *\n * Exported for demos and CaveGiant-hosted apps. Production integrators must\n * pass their own `multiplayer.url` — the SDK does not connect here unless you\n * opt in explicitly.\n */\nexport const DEFAULT_WEBSOCKET_URL = 'wss://api-live-mbspace.cavegiant.com/gameplay'\n\n/** Connection lifecycle for {@link WebSocketService}. */\nexport const WebSocketStatusEnum = {\n CONNECTING: 'connecting',\n CONNECTED: 'connected',\n DISCONNECTED: 'disconnected',\n RECONNECTING: 'reconnecting',\n ERROR: 'error'\n} as const\nexport type WebSocketStatus = (typeof WebSocketStatusEnum)[keyof typeof WebSocketStatusEnum]\n\n/** Wire protocol actions — see `doc/multiplayer-protocol.md`. */\nexport const MessageActionEnum = {\n JOIN_GAME: 'JOIN_GAME',\n UPDATE_STATE: 'UPDATE_STATE',\n SYNC_STATE: 'SYNC_STATE',\n PING: 'PING',\n JOIN_SUCCESS: 'JOIN_SUCCESS',\n PLAYER_JOINED: 'PLAYER_JOINED',\n PLAYER_LEFT: 'PLAYER_LEFT',\n STATE_UPDATE: 'STATE_UPDATE',\n STATE_SYNC: 'STATE_SYNC',\n PONG: 'PONG',\n ERROR: 'ERROR'\n} as const\nexport type MessageAction = (typeof MessageActionEnum)[keyof typeof MessageActionEnum]\n\nexport interface BaseMessage {\n action: MessageAction\n data: unknown\n}\n\nexport interface PlayerData {\n id: string\n position?: Vector3Type\n rotation?: QuaternionType\n animation?: AnimationName\n avatarId?: string\n lastUpdate?: number\n}\n\nexport interface JoinGameMessage extends BaseMessage {\n action: typeof MessageActionEnum.JOIN_GAME\n data: {\n appId: string\n avatarId: string\n }\n}\n\nexport interface UpdateStateMessage extends BaseMessage {\n action: typeof MessageActionEnum.UPDATE_STATE\n data: {\n position?: Vector3Type\n rotation?: QuaternionType\n animation?: AnimationName\n avatarId?: string\n }\n}\n\nexport interface SyncStateMessage extends BaseMessage {\n action: typeof MessageActionEnum.SYNC_STATE\n data: unknown\n}\n\nexport interface PingMessage extends BaseMessage {\n action: typeof MessageActionEnum.PING\n data: unknown\n}\n\nexport interface JoinSuccessMessage extends BaseMessage {\n action: typeof MessageActionEnum.JOIN_SUCCESS\n data: {\n roomId: string\n playerId: string\n players: PlayerData[]\n isRejoin: boolean\n }\n}\n\nexport interface PlayerJoinedMessage extends BaseMessage {\n action: typeof MessageActionEnum.PLAYER_JOINED\n data: PlayerData & { playerId: string }\n}\n\nexport interface PlayerLeftMessage extends BaseMessage {\n action: typeof MessageActionEnum.PLAYER_LEFT\n data: {\n playerId: string\n }\n}\n\nexport interface StateUpdateMessage extends BaseMessage {\n action: typeof MessageActionEnum.STATE_UPDATE\n data: PlayerData & { playerId: string }\n}\n\nexport interface StateSyncMessage extends BaseMessage {\n action: typeof MessageActionEnum.STATE_SYNC\n data: {\n players: PlayerData[]\n }\n}\n\nexport interface PongMessage extends BaseMessage {\n action: typeof MessageActionEnum.PONG\n data: {\n timestamp: number\n }\n}\n\nexport interface ErrorMessage extends BaseMessage {\n action: typeof MessageActionEnum.ERROR\n data: {\n error_code: string\n error_msg: string\n }\n}\n\nexport type WebSocketMessage =\n | JoinGameMessage\n | UpdateStateMessage\n | SyncStateMessage\n | PingMessage\n | JoinSuccessMessage\n | PlayerJoinedMessage\n | PlayerLeftMessage\n | StateUpdateMessage\n | StateSyncMessage\n | PongMessage\n | ErrorMessage\n\nexport type MessageListener = (message: WebSocketMessage) => void\nexport type StatusListener = (status: WebSocketStatus) => void\nexport type ErrorListener = (error: Event) => void\n\nexport interface WebSocketConfig {\n /** Required realtime endpoint (`wss://…`). */\n url: string\n reconnectInterval?: number\n maxReconnectAttempts?: number\n pingInterval?: number\n timeout?: number\n}\n\nconst DEFAULT_OPTIONS = {\n reconnectInterval: 3000,\n maxReconnectAttempts: 5,\n pingInterval: 30000,\n timeout: 10000\n} as const\n\n/**\n * Thin WebSocket client for the multiplayer protocol.\n *\n * Construct with an explicit `url`. Use {@link DEFAULT_WEBSOCKET_URL} only when\n * you intentionally want the CaveGiant demo backend.\n */\nexport class WebSocketService {\n private ws: WebSocket | null = null\n private config: Required<WebSocketConfig>\n private status: WebSocketStatus = WebSocketStatusEnum.DISCONNECTED\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private pingTimer: ReturnType<typeof setInterval> | null = null\n private messageListeners: Set<MessageListener> = new Set()\n private statusListeners: Set<StatusListener> = new Set()\n private errorListeners: Set<ErrorListener> = new Set()\n\n constructor(config: WebSocketConfig) {\n if (!config.url) {\n throw new Error('WebSocketService requires config.url')\n }\n this.config = { ...DEFAULT_OPTIONS, ...config }\n }\n\n /** Open the socket (or resolve immediately if already connected). */\n public connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.status === WebSocketStatusEnum.CONNECTED) {\n resolve()\n return\n }\n\n this.setStatus(WebSocketStatusEnum.CONNECTING)\n\n try {\n this.ws = new WebSocket(this.config.url)\n\n const timeout = setTimeout(() => {\n if (this.ws?.readyState === WebSocket.CONNECTING) {\n this.ws.close()\n reject(new Error('Connection timeout'))\n }\n }, this.config.timeout)\n\n this.ws.onopen = () => {\n clearTimeout(timeout)\n this.setStatus(WebSocketStatusEnum.CONNECTED)\n this.reconnectAttempts = 0\n this.startPing()\n resolve()\n }\n\n this.ws.onclose = (event) => {\n clearTimeout(timeout)\n this.setStatus(WebSocketStatusEnum.DISCONNECTED)\n this.stopPing()\n\n if (!event.wasClean && this.reconnectAttempts < this.config.maxReconnectAttempts) {\n this.scheduleReconnect()\n }\n }\n\n this.ws.onerror = (error) => {\n clearTimeout(timeout)\n this.setStatus(WebSocketStatusEnum.ERROR)\n this.notifyErrorListeners(error)\n reject(error)\n }\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event)\n }\n } catch (error) {\n this.setStatus(WebSocketStatusEnum.ERROR)\n reject(error)\n }\n })\n }\n\n /** Close the socket and cancel reconnect / ping timers. */\n public disconnect(): void {\n this.stopReconnect()\n this.stopPing()\n\n if (this.ws) {\n this.ws.close(1000, 'Client disconnect')\n this.ws = null\n }\n\n this.setStatus(WebSocketStatusEnum.DISCONNECTED)\n }\n\n /** Send a protocol message. Returns false when the socket is not connected. */\n public send(message: WebSocketMessage): boolean {\n if (this.status !== WebSocketStatusEnum.CONNECTED || !this.ws) {\n logger.warn('WebSocket not connected, cannot send message')\n return false\n }\n\n try {\n this.ws.send(JSON.stringify(message))\n return true\n } catch (error) {\n logger.error('Failed to send message:', error)\n return false\n }\n }\n\n /** Join (or rejoin) a room identified by `appId`. */\n public joinGame(appId: string, avatarId: string): boolean {\n return this.send({\n action: MessageActionEnum.JOIN_GAME,\n data: { appId, avatarId }\n })\n }\n\n /** Publish the local player's transform / animation. */\n public updateState(data: {\n position?: Vector3Type\n rotation?: QuaternionType\n animation?: AnimationName\n avatarId?: string\n }): boolean {\n return this.send({\n action: MessageActionEnum.UPDATE_STATE,\n data\n })\n }\n\n /** Request a full room state snapshot from the server. */\n public syncState(): boolean {\n return this.send({\n action: MessageActionEnum.SYNC_STATE,\n data: {}\n })\n }\n\n /** Application-level heartbeat. */\n public ping(): boolean {\n return this.send({\n action: MessageActionEnum.PING,\n data: {}\n })\n }\n\n public addMessageListener(listener: MessageListener): () => void {\n this.messageListeners.add(listener)\n return () => this.messageListeners.delete(listener)\n }\n\n public addStatusListener(listener: StatusListener): () => void {\n this.statusListeners.add(listener)\n return () => this.statusListeners.delete(listener)\n }\n\n public addErrorListener(listener: ErrorListener): () => void {\n this.errorListeners.add(listener)\n return () => this.errorListeners.delete(listener)\n }\n\n public getStatus(): WebSocketStatus {\n return this.status\n }\n\n public isConnected(): boolean {\n return this.status === WebSocketStatusEnum.CONNECTED\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n const message: WebSocketMessage = JSON.parse(event.data)\n\n if (message.action === MessageActionEnum.PONG) {\n return\n }\n\n this.messageListeners.forEach((listener) => {\n try {\n listener(message)\n } catch (error) {\n logger.error('Error in message listener:', error)\n }\n })\n } catch (error) {\n logger.error('Failed to parse WebSocket message:', error)\n }\n }\n\n private setStatus(status: WebSocketStatus): void {\n if (this.status !== status) {\n this.status = status\n this.statusListeners.forEach((listener) => {\n try {\n listener(status)\n } catch (error) {\n logger.error('Error in status listener:', error)\n }\n })\n }\n }\n\n private notifyErrorListeners(error: Event): void {\n this.errorListeners.forEach((listener) => {\n try {\n listener(error)\n } catch (err) {\n logger.error('Error in error listener:', err)\n }\n })\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n this.setStatus(WebSocketStatusEnum.RECONNECTING)\n this.reconnectAttempts++\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.connect().catch(() => {\n // Keep trying until maxReconnectAttempts is exhausted via onclose.\n })\n }, this.config.reconnectInterval)\n }\n\n private stopReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n\n private startPing(): void {\n this.stopPing()\n\n this.pingTimer = setInterval(() => {\n if (this.isConnected()) {\n this.ping()\n }\n }, this.config.pingInterval)\n }\n\n private stopPing(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n }\n\n /** Disconnect and drop all listeners. */\n public destroy(): void {\n this.disconnect()\n this.messageListeners.clear()\n this.statusListeners.clear()\n this.errorListeners.clear()\n }\n}\n"],"names":["logger","createLogger","DEFAULT_WEBSOCKET_URL","WebSocketStatusEnum","MessageActionEnum","DEFAULT_OPTIONS","WebSocketService","config","resolve","reject","timeout","event","error","message","appId","avatarId","data","listener","status","err"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { CharacterCameraBehavior } from '@react-three/viverse';
2
+ import type { AnimationAction, Group, Object3DEventMap } from 'three';
3
+ import type { AvatarConfig } from './characters/character-configs.js';
4
+ import type { CharacterControlsConfig } from './characters/character-controls.js';
5
+ import { type LocalCharacterModelProp } from './characters/local-character-model.js';
6
+ /**
7
+ * Root ref from viverse's `SimpleCharacter`, augmented at runtime with:
8
+ * - `actions` — animation table, patched to record the playing clip so
9
+ * multiplayer can publish it;
10
+ * - `viverseCameraBehavior` — the `CharacterCameraBehavior` that owns
11
+ * `rotationYaw` / `rotationPitch`. viverse discards the behavior ref returned
12
+ * by its internal `useCharacterCameraBehavior`, so we run our own and expose
13
+ * it here; it is the only way to programmatically re-orient the player
14
+ * (spawn point, portal teleport). See `characters/character-pose.ts`.
15
+ */
16
+ export type ExploreSimpleCharacterRoot = Group<Object3DEventMap> & {
17
+ actions?: Record<string, AnimationAction | undefined>;
18
+ viverseCameraBehavior?: CharacterCameraBehavior;
19
+ };
20
+ /** Resolved multiplayer options (see `CaveExploreProps.multiplayer`). */
21
+ export interface MultiplayerRuntimeConfig {
22
+ /** Realtime endpoint. Required when multiplayer is enabled. */
23
+ url: string;
24
+ avatarId?: string;
25
+ avatars?: Record<string, AvatarConfig>;
26
+ maxRemoteCharacters?: number;
27
+ }
28
+ export interface ExploreSimpleCharacterProps {
29
+ /** Scene readiness gate — gravity stays at 0 until colliders exist. */
30
+ spaceInited: boolean;
31
+ /** Room key for multiplayer; normally the primary space id. */
32
+ spaceId: string | undefined;
33
+ /** Omit or pass `undefined` to disable multiplayer. */
34
+ multiplayer?: MultiplayerRuntimeConfig;
35
+ localCharacterModel?: LocalCharacterModelProp;
36
+ characterControls?: CharacterControlsConfig;
37
+ }
38
+ /**
39
+ * Memoised so re-renders of the exploration root (active-scene churn,
40
+ * action-prompt updates) don't propagate into `<SimpleCharacter>`. Re-rendering
41
+ * it is expensive and, worse, triggers the viverse action-binding bug described
42
+ * in `hooks/use-action-shortcuts.ts` that drops held movement keys.
43
+ */
44
+ declare const _default: import("react").NamedExoticComponent<ExploreSimpleCharacterProps & import("react").RefAttributes<ExploreSimpleCharacterRoot>>;
45
+ export default _default;
46
+ //# sourceMappingURL=simple-character.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-character.d.ts","sourceRoot":"","sources":["../../explore/simple-character.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AASnE,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAErE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAKL,KAAK,uBAAuB,EAC7B,MAAM,oCAAoC,CAAA;AAgB3C;;;;;;;;;GASG;AACH,MAAM,MAAM,0BAA0B,GAAG,KAAK,CAAC,gBAAgB,CAAC,GAAG;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAA;IACrD,qBAAqB,CAAC,EAAE,uBAAuB,CAAA;CAChD,CAAA;AAgDD,yEAAyE;AACzE,MAAM,WAAW,wBAAwB;IACvC,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACtC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,2BAA2B;IAC1C,uEAAuE;IACvE,WAAW,EAAE,OAAO,CAAA;IACpB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,uDAAuD;IACvD,WAAW,CAAC,EAAE,wBAAwB,CAAA;IACtC,mBAAmB,CAAC,EAAE,uBAAuB,CAAA;IAC7C,iBAAiB,CAAC,EAAE,uBAAuB,CAAA;CAC5C;AAkID;;;;;GAKG;;AACH,wBAA2C"}
@@ -0,0 +1,119 @@
1
+ import { jsxs as R, Fragment as S, jsx as l } from "react/jsx-runtime";
2
+ import { memo as _, forwardRef as O, useRef as I, useImperativeHandle as T, useEffect as A, useMemo as a } from "react";
3
+ import { Vanilla as v, PointerLockRotateZoomActionBindings as x, KeyboardLocomotionActionBindings as N, FirstPersonCharacterCameraBehavior as b, useCharacterCameraBehavior as w, SimpleCharacter as y } from "@react-three/viverse";
4
+ import { useTouchPrimaryDevice as P } from "../space/utils/touch-primary-device.js";
5
+ import { CAVE_WORLD_LOCAL_PLAYER_FLAG as B } from "../space/utils/cave-world-player.js";
6
+ import { resolveLocalCharacterScale as k, resolveLocalCharacterPhysics as F, resolveSimpleCharacterModel as j, resolveUseViverseAvatar as U } from "./characters/local-character-model.js";
7
+ import M from "./characters/remote-character-controller.js";
8
+ import { useCaveExplore as V } from "./stores/explore-context.js";
9
+ const G = -20, g = [
10
+ "idle",
11
+ "walk",
12
+ "run",
13
+ "jumpDown",
14
+ "jumpUp",
15
+ "jumpForward"
16
+ ];
17
+ function K(p) {
18
+ const t = p.current?.actions;
19
+ if (!t) return () => {
20
+ };
21
+ const s = /* @__PURE__ */ new Map();
22
+ for (const o of g) {
23
+ const e = t[o];
24
+ if (!e?.play) continue;
25
+ const n = e.play;
26
+ s.set(o, n), e.play = () => {
27
+ const m = p.current;
28
+ return m && (m.userData.currentAnimation = o), n.bind(e)();
29
+ };
30
+ }
31
+ return () => {
32
+ for (const o of g) {
33
+ const e = s.get(o), n = t[o];
34
+ e && n && (n.play = e);
35
+ }
36
+ };
37
+ }
38
+ const J = [
39
+ v.ScreenJoystickLocomotionActionBindings,
40
+ v.ScreenButtonJumpActionBindings,
41
+ v.PointerCaptureRotateZoomActionBindings
42
+ ], Y = [
43
+ x,
44
+ N
45
+ ], Z = O(
46
+ function({ spaceInited: t, spaceId: s, multiplayer: o, localCharacterModel: e, characterControls: n }, m) {
47
+ const c = P(), u = V((r) => r.viewMode), i = I(null);
48
+ T(m, () => i.current, []), A(() => K(i), []);
49
+ const h = a(() => c ? n?.mobileActionBindings ?? J : n?.desktopActionBindings ?? Y, [
50
+ n?.mobileActionBindings,
51
+ n?.desktopActionBindings,
52
+ c
53
+ ]), C = a(
54
+ () => u === "first-person" ? b : { zoom: { minDistance: c ? 1 : 0.8, maxDistance: c ? 2.5 : 2 } },
55
+ [u, c]
56
+ );
57
+ A(() => {
58
+ const r = i.current;
59
+ if (r)
60
+ return r.userData[B] = !0, () => {
61
+ delete r.userData[B];
62
+ };
63
+ }, [t]);
64
+ const d = w(i, C);
65
+ A(() => {
66
+ const r = i.current;
67
+ r && Object.defineProperty(r, "viverseCameraBehavior", {
68
+ get: () => d.current,
69
+ configurable: !0
70
+ });
71
+ }, [d]);
72
+ const f = a(
73
+ () => k(e),
74
+ [e]
75
+ ), D = a(
76
+ () => F(f, {
77
+ gravity: t ? G : 0
78
+ }),
79
+ [f, t]
80
+ ), E = a(
81
+ () => j(e, u),
82
+ [e, u]
83
+ ), L = a(
84
+ () => U(e),
85
+ [e]
86
+ );
87
+ return /* @__PURE__ */ R(S, { children: [
88
+ /* @__PURE__ */ l(
89
+ y,
90
+ {
91
+ ref: i,
92
+ physics: D,
93
+ scale: f,
94
+ model: E,
95
+ useViverseAvatar: L,
96
+ actionBindings: h,
97
+ actionBindingOptions: n?.actionBindingOptions,
98
+ movement: n?.movement,
99
+ cameraBehavior: !1
100
+ }
101
+ ),
102
+ s && o ? /* @__PURE__ */ l(
103
+ M,
104
+ {
105
+ appId: s,
106
+ websocketUrl: o.url,
107
+ localCharacterRef: i,
108
+ localAvatarId: o.avatarId,
109
+ avatars: o.avatars,
110
+ maxRemoteCharacters: o.maxRemoteCharacters
111
+ }
112
+ ) : null
113
+ ] });
114
+ }
115
+ ), oe = _(Z);
116
+ export {
117
+ oe as default
118
+ };
119
+ //# sourceMappingURL=simple-character.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-character.js","sources":["../../explore/simple-character.tsx"],"sourcesContent":["import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useRef } from 'react'\nimport type { CharacterCameraBehavior } from '@react-three/viverse'\nimport {\n FirstPersonCharacterCameraBehavior,\n KeyboardLocomotionActionBindings,\n PointerLockRotateZoomActionBindings,\n SimpleCharacter,\n useCharacterCameraBehavior,\n Vanilla\n} from '@react-three/viverse'\nimport type { AnimationAction, Group, Object3DEventMap } from 'three'\nimport { CAVE_WORLD_LOCAL_PLAYER_FLAG, useTouchPrimaryDevice } from '../space'\nimport type { AvatarConfig } from './characters/character-configs'\nimport type { CharacterControlsConfig } from './characters/character-controls'\nimport {\n resolveLocalCharacterPhysics,\n resolveLocalCharacterScale,\n resolveSimpleCharacterModel,\n resolveUseViverseAvatar,\n type LocalCharacterModelProp\n} from './characters/local-character-model'\nimport RemoteCharacterController from './characters/remote-character-controller'\nimport { useCaveExplore } from './stores/explore-context'\n\n/** Gravity applied once the scene's colliders exist (m/s²). */\nconst DEFAULT_GRAVITY = -20\n\nconst TRACKED_ANIMATION_NAMES = [\n 'idle',\n 'walk',\n 'run',\n 'jumpDown',\n 'jumpUp',\n 'jumpForward'\n] as const\n\n/**\n * Root ref from viverse's `SimpleCharacter`, augmented at runtime with:\n * - `actions` — animation table, patched to record the playing clip so\n * multiplayer can publish it;\n * - `viverseCameraBehavior` — the `CharacterCameraBehavior` that owns\n * `rotationYaw` / `rotationPitch`. viverse discards the behavior ref returned\n * by its internal `useCharacterCameraBehavior`, so we run our own and expose\n * it here; it is the only way to programmatically re-orient the player\n * (spawn point, portal teleport). See `characters/character-pose.ts`.\n */\nexport type ExploreSimpleCharacterRoot = Group<Object3DEventMap> & {\n actions?: Record<string, AnimationAction | undefined>\n viverseCameraBehavior?: CharacterCameraBehavior\n}\n\n/**\n * Record the currently playing clip name on `userData.currentAnimation`.\n *\n * viverse exposes no \"current animation\" accessor, so we wrap each action's\n * `play()`. Returns a restore function.\n */\nfunction patchAnimationTracking(\n characterRef: React.RefObject<ExploreSimpleCharacterRoot | null>\n): () => void {\n const actions = characterRef.current?.actions\n if (!actions) return () => {}\n\n const originals = new Map<string, AnimationAction['play']>()\n\n for (const name of TRACKED_ANIMATION_NAMES) {\n const action = actions[name]\n if (!action?.play) continue\n const original = action.play\n originals.set(name, original)\n action.play = () => {\n const root = characterRef.current\n if (root) root.userData.currentAnimation = name\n return original.bind(action)()\n }\n }\n\n return () => {\n for (const name of TRACKED_ANIMATION_NAMES) {\n const original = originals.get(name)\n const action = actions[name]\n if (original && action) action.play = original\n }\n }\n}\n\nconst DEFAULT_MOBILE_ACTION_BINDINGS = [\n Vanilla.ScreenJoystickLocomotionActionBindings,\n Vanilla.ScreenButtonJumpActionBindings,\n Vanilla.PointerCaptureRotateZoomActionBindings\n]\n\nconst DEFAULT_DESKTOP_ACTION_BINDINGS = [\n PointerLockRotateZoomActionBindings,\n KeyboardLocomotionActionBindings\n]\n\n/** Resolved multiplayer options (see `CaveExploreProps.multiplayer`). */\nexport interface MultiplayerRuntimeConfig {\n /** Realtime endpoint. Required when multiplayer is enabled. */\n url: string\n avatarId?: string\n avatars?: Record<string, AvatarConfig>\n maxRemoteCharacters?: number\n}\n\nexport interface ExploreSimpleCharacterProps {\n /** Scene readiness gate — gravity stays at 0 until colliders exist. */\n spaceInited: boolean\n /** Room key for multiplayer; normally the primary space id. */\n spaceId: string | undefined\n /** Omit or pass `undefined` to disable multiplayer. */\n multiplayer?: MultiplayerRuntimeConfig\n localCharacterModel?: LocalCharacterModelProp\n characterControls?: CharacterControlsConfig\n}\n\nconst ExploreSimpleCharacter = forwardRef<ExploreSimpleCharacterRoot, ExploreSimpleCharacterProps>(\n function ExploreSimpleCharacter(\n { spaceInited, spaceId, multiplayer, localCharacterModel, characterControls },\n ref\n ) {\n const isMobile = useTouchPrimaryDevice()\n const viewMode = useCaveExplore((s) => s.viewMode)\n const characterRef = useRef<ExploreSimpleCharacterRoot>(null)\n\n useImperativeHandle(ref, () => characterRef.current as ExploreSimpleCharacterRoot, [])\n\n useEffect(() => patchAnimationTracking(characterRef), [])\n\n const characterActionBindings = useMemo(() => {\n if (isMobile) {\n return characterControls?.mobileActionBindings ?? DEFAULT_MOBILE_ACTION_BINDINGS\n }\n return characterControls?.desktopActionBindings ?? DEFAULT_DESKTOP_ACTION_BINDINGS\n }, [\n characterControls?.mobileActionBindings,\n characterControls?.desktopActionBindings,\n isMobile\n ])\n\n const characterCameraBehavior = useMemo(\n () =>\n viewMode === 'first-person'\n ? FirstPersonCharacterCameraBehavior\n : { zoom: { minDistance: isMobile ? 1 : 0.8, maxDistance: isMobile ? 2.5 : 2 } },\n [viewMode, isMobile]\n )\n\n // Tag the physics root so in-scene helpers (boundary visuals, host proximity\n // trackers) can find the local player without a prop drill.\n useEffect(() => {\n const root = characterRef.current\n if (!root) return\n root.userData[CAVE_WORLD_LOCAL_PLAYER_FLAG] = true\n return () => {\n delete root.userData[CAVE_WORLD_LOCAL_PLAYER_FLAG]\n }\n }, [spaceInited])\n\n // Drive the character camera ourselves so we can hold a reference to the\n // `CharacterCameraBehavior` instance (which owns `rotationYaw`/`rotationPitch`).\n //\n // Why this is necessary: viverse's `<SimpleCharacter>` internally calls\n // `useCharacterCameraBehavior(internalRef, cameraBehavior)` and throws away the\n // returned ref. Every frame the behavior writes\n // camera.rotation.set(rotationPitch, rotationYaw, 0, 'YXZ')\n // and `updateSimpleCharacterVelocity` / `updateSimpleCharacterRotation` then\n // derive input direction and model yaw from `state.camera` — the character\n // Group's own quaternion is never read in viverse's orientation pipeline.\n // `rotationYaw` starts at 0 and is only mutated by pointer deltas, so without\n // writing it directly there is no way to set the initial facing or re-orient\n // the player on teleport.\n //\n // `cameraBehavior={false}` below short-circuits viverse's internal copy (its\n // `update()` returns immediately when options === false) so only ours runs.\n const cameraBehaviorRef = useCharacterCameraBehavior(characterRef, characterCameraBehavior)\n\n // Expose the behavior through a getter so the ref always reads the latest\n // instance — `useCharacterCameraBehavior` creates a new one whenever its\n // effect re-runs, and we want to track that without re-running this effect.\n useEffect(() => {\n const root = characterRef.current\n if (!root) return\n Object.defineProperty(root, 'viverseCameraBehavior', {\n get: () => cameraBehaviorRef.current,\n configurable: true\n })\n }, [cameraBehaviorRef])\n\n const characterScale = useMemo(\n () => resolveLocalCharacterScale(localCharacterModel),\n [localCharacterModel]\n )\n\n // Keep the options object identity stable across renders: `SimpleCharacter`\n // and `useSimpleCharacterActionBindings` use dep-less effects that re-run on\n // every render, and a fresh object there costs real work.\n const physicsOptions = useMemo(\n () =>\n resolveLocalCharacterPhysics(characterScale, {\n gravity: spaceInited ? DEFAULT_GRAVITY : 0\n }),\n [characterScale, spaceInited]\n )\n\n const characterModelOptions = useMemo(\n () => resolveSimpleCharacterModel(localCharacterModel, viewMode),\n [localCharacterModel, viewMode]\n )\n\n const useViverseAvatar = useMemo(\n () => resolveUseViverseAvatar(localCharacterModel),\n [localCharacterModel]\n )\n\n return (\n <>\n <SimpleCharacter\n ref={characterRef}\n physics={physicsOptions}\n scale={characterScale}\n model={characterModelOptions}\n useViverseAvatar={useViverseAvatar}\n actionBindings={characterActionBindings}\n actionBindingOptions={characterControls?.actionBindingOptions}\n movement={characterControls?.movement}\n cameraBehavior={false}\n />\n\n {spaceId && multiplayer ? (\n <RemoteCharacterController\n appId={spaceId}\n websocketUrl={multiplayer.url}\n localCharacterRef={characterRef}\n localAvatarId={multiplayer.avatarId}\n avatars={multiplayer.avatars}\n maxRemoteCharacters={multiplayer.maxRemoteCharacters}\n />\n ) : null}\n </>\n )\n }\n)\n\n/**\n * Memoised so re-renders of the exploration root (active-scene churn,\n * action-prompt updates) don't propagate into `<SimpleCharacter>`. Re-rendering\n * it is expensive and, worse, triggers the viverse action-binding bug described\n * in `hooks/use-action-shortcuts.ts` that drops held movement keys.\n */\nexport default memo(ExploreSimpleCharacter)\n"],"names":["DEFAULT_GRAVITY","TRACKED_ANIMATION_NAMES","patchAnimationTracking","characterRef","actions","originals","name","action","original","root","DEFAULT_MOBILE_ACTION_BINDINGS","Vanilla","DEFAULT_DESKTOP_ACTION_BINDINGS","PointerLockRotateZoomActionBindings","KeyboardLocomotionActionBindings","ExploreSimpleCharacter","forwardRef","spaceInited","spaceId","multiplayer","localCharacterModel","characterControls","ref","isMobile","useTouchPrimaryDevice","viewMode","useCaveExplore","s","useRef","useImperativeHandle","useEffect","characterActionBindings","useMemo","characterCameraBehavior","FirstPersonCharacterCameraBehavior","CAVE_WORLD_LOCAL_PLAYER_FLAG","cameraBehaviorRef","useCharacterCameraBehavior","characterScale","resolveLocalCharacterScale","physicsOptions","resolveLocalCharacterPhysics","characterModelOptions","resolveSimpleCharacterModel","useViverseAvatar","resolveUseViverseAvatar","jsxs","Fragment","jsx","SimpleCharacter","RemoteCharacterController","ExploreSimpleCharacter$1","memo"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type StoreApi } from 'zustand';
2
+ import type { Vector3 } from '../../types/index.js';
3
+ /** One selectable action offered to the player (detail, portal entry, …). */
4
+ export interface ActionDef {
5
+ /** Stable identity, used as the React key. */
6
+ id: string;
7
+ label: string;
8
+ /** Single key that triggers `onAction`, e.g. `'F'` or `'1'`. */
9
+ shortcut?: string;
10
+ /** Shown but not selectable (e.g. destination still preloading). */
11
+ disabled?: boolean;
12
+ onAction: () => void;
13
+ }
14
+ /** `bubble` anchors in 3D next to the object; `panel` is a screen-space list. */
15
+ export type ActionPromptStyle = 'bubble' | 'panel';
16
+ export interface ActionPromptState {
17
+ actions: ActionDef[];
18
+ /** World position for `bubble` style; `null` selects the screen panel. */
19
+ anchor: Vector3 | null;
20
+ style: ActionPromptStyle;
21
+ showActions: (actions: ActionDef[], anchor: Vector3 | null, style?: ActionPromptStyle) => void;
22
+ clearActions: () => void;
23
+ }
24
+ export type ActionPromptStoreApi = StoreApi<ActionPromptState>;
25
+ /** Create an action-prompt store. One per `CaveExploreProvider`. */
26
+ export declare function createActionPromptStore(): ActionPromptStoreApi;
27
+ //# sourceMappingURL=action-prompt.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-prompt.store.d.ts","sourceRoot":"","sources":["../../../explore/stores/action-prompt.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,CAAA;AAElD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,0EAA0E;IAC1E,MAAM,EAAE,OAAO,GAAG,IAAI,CAAA;IACtB,KAAK,EAAE,iBAAiB,CAAA;IAExB,WAAW,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAC9F,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAA;AAE9D,oEAAoE;AACpE,wBAAgB,uBAAuB,IAAI,oBAAoB,CAW9D"}
@@ -0,0 +1,14 @@
1
+ import { createStore as r } from "zustand";
2
+ function l() {
3
+ return r((n) => ({
4
+ actions: [],
5
+ anchor: null,
6
+ style: "bubble",
7
+ showActions: (o, t, e = t ? "bubble" : "panel") => n({ actions: o, anchor: t, style: e }),
8
+ clearActions: () => n((o) => o.actions.length === 0 ? o : { actions: [], anchor: null })
9
+ }));
10
+ }
11
+ export {
12
+ l as createActionPromptStore
13
+ };
14
+ //# sourceMappingURL=action-prompt.store.js.map