@vizor-vr/player 0.2.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 (344) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/__tests__/adapter-factory.test.d.ts +2 -0
  4. package/dist/__tests__/adapter-factory.test.d.ts.map +1 -0
  5. package/dist/__tests__/analytics-collector.test.d.ts +2 -0
  6. package/dist/__tests__/analytics-collector.test.d.ts.map +1 -0
  7. package/dist/__tests__/annotation-manager.test.d.ts +2 -0
  8. package/dist/__tests__/annotation-manager.test.d.ts.map +1 -0
  9. package/dist/__tests__/annotation-popup.test.d.ts +2 -0
  10. package/dist/__tests__/annotation-popup.test.d.ts.map +1 -0
  11. package/dist/__tests__/annotation-sprite.test.d.ts +2 -0
  12. package/dist/__tests__/annotation-sprite.test.d.ts.map +1 -0
  13. package/dist/__tests__/audio-manager.test.d.ts +2 -0
  14. package/dist/__tests__/audio-manager.test.d.ts.map +1 -0
  15. package/dist/__tests__/base-element-attrs.test.d.ts +2 -0
  16. package/dist/__tests__/base-element-attrs.test.d.ts.map +1 -0
  17. package/dist/__tests__/camera-controller.test.d.ts +2 -0
  18. package/dist/__tests__/camera-controller.test.d.ts.map +1 -0
  19. package/dist/__tests__/caption-renderer.test.d.ts +2 -0
  20. package/dist/__tests__/caption-renderer.test.d.ts.map +1 -0
  21. package/dist/__tests__/cc-button.test.d.ts +2 -0
  22. package/dist/__tests__/cc-button.test.d.ts.map +1 -0
  23. package/dist/__tests__/chat-button.test.d.ts +2 -0
  24. package/dist/__tests__/chat-button.test.d.ts.map +1 -0
  25. package/dist/__tests__/chat-panel.test.d.ts +2 -0
  26. package/dist/__tests__/chat-panel.test.d.ts.map +1 -0
  27. package/dist/__tests__/cinema-projection.test.d.ts +2 -0
  28. package/dist/__tests__/cinema-projection.test.d.ts.map +1 -0
  29. package/dist/__tests__/collab-client.test.d.ts +2 -0
  30. package/dist/__tests__/collab-client.test.d.ts.map +1 -0
  31. package/dist/__tests__/compass.test.d.ts +2 -0
  32. package/dist/__tests__/compass.test.d.ts.map +1 -0
  33. package/dist/__tests__/controls-overlay.test.d.ts +2 -0
  34. package/dist/__tests__/controls-overlay.test.d.ts.map +1 -0
  35. package/dist/__tests__/cubemap-projection.test.d.ts +2 -0
  36. package/dist/__tests__/cubemap-projection.test.d.ts.map +1 -0
  37. package/dist/__tests__/dash-adapter.test.d.ts +2 -0
  38. package/dist/__tests__/dash-adapter.test.d.ts.map +1 -0
  39. package/dist/__tests__/eac-projection.test.d.ts +2 -0
  40. package/dist/__tests__/eac-projection.test.d.ts.map +1 -0
  41. package/dist/__tests__/equirect-projection.test.d.ts +2 -0
  42. package/dist/__tests__/equirect-projection.test.d.ts.map +1 -0
  43. package/dist/__tests__/event-emitter.test.d.ts +2 -0
  44. package/dist/__tests__/event-emitter.test.d.ts.map +1 -0
  45. package/dist/__tests__/feature-gates-branding.test.d.ts +2 -0
  46. package/dist/__tests__/feature-gates-branding.test.d.ts.map +1 -0
  47. package/dist/__tests__/feature-gates.test.d.ts +2 -0
  48. package/dist/__tests__/feature-gates.test.d.ts.map +1 -0
  49. package/dist/__tests__/fisheye-projection.test.d.ts +2 -0
  50. package/dist/__tests__/fisheye-projection.test.d.ts.map +1 -0
  51. package/dist/__tests__/flat-projection.test.d.ts +2 -0
  52. package/dist/__tests__/flat-projection.test.d.ts.map +1 -0
  53. package/dist/__tests__/flat-video-integration.test.d.ts +2 -0
  54. package/dist/__tests__/flat-video-integration.test.d.ts.map +1 -0
  55. package/dist/__tests__/fullscreen-button.test.d.ts +2 -0
  56. package/dist/__tests__/fullscreen-button.test.d.ts.map +1 -0
  57. package/dist/__tests__/gaze-cursor-manager.test.d.ts +2 -0
  58. package/dist/__tests__/gaze-cursor-manager.test.d.ts.map +1 -0
  59. package/dist/__tests__/gaze-sender.test.d.ts +2 -0
  60. package/dist/__tests__/gaze-sender.test.d.ts.map +1 -0
  61. package/dist/__tests__/gaze-tracker.test.d.ts +2 -0
  62. package/dist/__tests__/gaze-tracker.test.d.ts.map +1 -0
  63. package/dist/__tests__/hls-adapter.test.d.ts +2 -0
  64. package/dist/__tests__/hls-adapter.test.d.ts.map +1 -0
  65. package/dist/__tests__/hotspot-interaction.test.d.ts +2 -0
  66. package/dist/__tests__/hotspot-interaction.test.d.ts.map +1 -0
  67. package/dist/__tests__/hotspot-manager.test.d.ts +2 -0
  68. package/dist/__tests__/hotspot-manager.test.d.ts.map +1 -0
  69. package/dist/__tests__/hotspot-renderer.test.d.ts +2 -0
  70. package/dist/__tests__/hotspot-renderer.test.d.ts.map +1 -0
  71. package/dist/__tests__/integrity.test.d.ts +2 -0
  72. package/dist/__tests__/integrity.test.d.ts.map +1 -0
  73. package/dist/__tests__/keyboard-shortcuts.test.d.ts +2 -0
  74. package/dist/__tests__/keyboard-shortcuts.test.d.ts.map +1 -0
  75. package/dist/__tests__/license-checker.test.d.ts +2 -0
  76. package/dist/__tests__/license-checker.test.d.ts.map +1 -0
  77. package/dist/__tests__/live-indicator.test.d.ts +2 -0
  78. package/dist/__tests__/live-indicator.test.d.ts.map +1 -0
  79. package/dist/__tests__/live.test.d.ts +2 -0
  80. package/dist/__tests__/live.test.d.ts.map +1 -0
  81. package/dist/__tests__/master-key.test.d.ts +2 -0
  82. package/dist/__tests__/master-key.test.d.ts.map +1 -0
  83. package/dist/__tests__/media-element.test.d.ts +2 -0
  84. package/dist/__tests__/media-element.test.d.ts.map +1 -0
  85. package/dist/__tests__/meta-config.test.d.ts +2 -0
  86. package/dist/__tests__/meta-config.test.d.ts.map +1 -0
  87. package/dist/__tests__/play-button.test.d.ts +2 -0
  88. package/dist/__tests__/play-button.test.d.ts.map +1 -0
  89. package/dist/__tests__/player-exports.test.d.ts +2 -0
  90. package/dist/__tests__/player-exports.test.d.ts.map +1 -0
  91. package/dist/__tests__/player-state.test.d.ts +2 -0
  92. package/dist/__tests__/player-state.test.d.ts.map +1 -0
  93. package/dist/__tests__/playlist-controls.test.d.ts +2 -0
  94. package/dist/__tests__/playlist-controls.test.d.ts.map +1 -0
  95. package/dist/__tests__/playlist-panel.test.d.ts +2 -0
  96. package/dist/__tests__/playlist-panel.test.d.ts.map +1 -0
  97. package/dist/__tests__/playlist.test.d.ts +2 -0
  98. package/dist/__tests__/playlist.test.d.ts.map +1 -0
  99. package/dist/__tests__/progressive-adapter.test.d.ts +2 -0
  100. package/dist/__tests__/progressive-adapter.test.d.ts.map +1 -0
  101. package/dist/__tests__/quality-selector.test.d.ts +2 -0
  102. package/dist/__tests__/quality-selector.test.d.ts.map +1 -0
  103. package/dist/__tests__/renderer.test.d.ts +2 -0
  104. package/dist/__tests__/renderer.test.d.ts.map +1 -0
  105. package/dist/__tests__/security/license-key-exposure.test.d.ts +2 -0
  106. package/dist/__tests__/security/license-key-exposure.test.d.ts.map +1 -0
  107. package/dist/__tests__/security/sanitize-xss.test.d.ts +2 -0
  108. package/dist/__tests__/security/sanitize-xss.test.d.ts.map +1 -0
  109. package/dist/__tests__/security/sri-generation.test.d.ts +2 -0
  110. package/dist/__tests__/security/sri-generation.test.d.ts.map +1 -0
  111. package/dist/__tests__/security/xss-annotations.test.d.ts +2 -0
  112. package/dist/__tests__/security/xss-annotations.test.d.ts.map +1 -0
  113. package/dist/__tests__/security/xss-captions.test.d.ts +2 -0
  114. package/dist/__tests__/security/xss-captions.test.d.ts.map +1 -0
  115. package/dist/__tests__/seek-bar.test.d.ts +2 -0
  116. package/dist/__tests__/seek-bar.test.d.ts.map +1 -0
  117. package/dist/__tests__/source-manager.test.d.ts +2 -0
  118. package/dist/__tests__/source-manager.test.d.ts.map +1 -0
  119. package/dist/__tests__/sprint1-memory-disposal.test.d.ts +10 -0
  120. package/dist/__tests__/sprint1-memory-disposal.test.d.ts.map +1 -0
  121. package/dist/__tests__/sprint3-frustum-adaptive.test.d.ts +9 -0
  122. package/dist/__tests__/sprint3-frustum-adaptive.test.d.ts.map +1 -0
  123. package/dist/__tests__/sprint5-bundle-memory.test.d.ts +18 -0
  124. package/dist/__tests__/sprint5-bundle-memory.test.d.ts.map +1 -0
  125. package/dist/__tests__/voice-button.test.d.ts +2 -0
  126. package/dist/__tests__/voice-button.test.d.ts.map +1 -0
  127. package/dist/__tests__/voice-manager.test.d.ts +2 -0
  128. package/dist/__tests__/voice-manager.test.d.ts.map +1 -0
  129. package/dist/__tests__/volume-control.test.d.ts +2 -0
  130. package/dist/__tests__/volume-control.test.d.ts.map +1 -0
  131. package/dist/__tests__/vr-button.test.d.ts +2 -0
  132. package/dist/__tests__/vr-button.test.d.ts.map +1 -0
  133. package/dist/__tests__/vz-cinema-element.test.d.ts +2 -0
  134. package/dist/__tests__/vz-cinema-element.test.d.ts.map +1 -0
  135. package/dist/__tests__/vz-img-element.test.d.ts +2 -0
  136. package/dist/__tests__/vz-img-element.test.d.ts.map +1 -0
  137. package/dist/__tests__/vz-playlist-element.test.d.ts +2 -0
  138. package/dist/__tests__/vz-playlist-element.test.d.ts.map +1 -0
  139. package/dist/__tests__/vz-tour-element.test.d.ts +2 -0
  140. package/dist/__tests__/vz-tour-element.test.d.ts.map +1 -0
  141. package/dist/__tests__/vz-tour-img.test.d.ts +2 -0
  142. package/dist/__tests__/vz-tour-img.test.d.ts.map +1 -0
  143. package/dist/__tests__/vz-tour-portal.test.d.ts +2 -0
  144. package/dist/__tests__/vz-tour-portal.test.d.ts.map +1 -0
  145. package/dist/__tests__/vz-video-element.test.d.ts +2 -0
  146. package/dist/__tests__/vz-video-element.test.d.ts.map +1 -0
  147. package/dist/__tests__/watermark-guard.test.d.ts +2 -0
  148. package/dist/__tests__/watermark-guard.test.d.ts.map +1 -0
  149. package/dist/__tests__/watermark.test.d.ts +2 -0
  150. package/dist/__tests__/watermark.test.d.ts.map +1 -0
  151. package/dist/__tests__/webvtt-parser.test.d.ts +2 -0
  152. package/dist/__tests__/webvtt-parser.test.d.ts.map +1 -0
  153. package/dist/__tests__/xr-controller.test.d.ts +2 -0
  154. package/dist/__tests__/xr-controller.test.d.ts.map +1 -0
  155. package/dist/__tests__/xr-manager.test.d.ts +2 -0
  156. package/dist/__tests__/xr-manager.test.d.ts.map +1 -0
  157. package/dist/analytics/analytics-collector.d.ts +29 -0
  158. package/dist/analytics/analytics-collector.d.ts.map +1 -0
  159. package/dist/analytics/gaze-tracker.d.ts +44 -0
  160. package/dist/analytics/gaze-tracker.d.ts.map +1 -0
  161. package/dist/analytics/index.d.ts +32 -0
  162. package/dist/analytics/index.d.ts.map +1 -0
  163. package/dist/annotations/annotation-manager.d.ts +31 -0
  164. package/dist/annotations/annotation-manager.d.ts.map +1 -0
  165. package/dist/annotations/annotation-popup.d.ts +21 -0
  166. package/dist/annotations/annotation-popup.d.ts.map +1 -0
  167. package/dist/annotations/annotation-sprite.d.ts +10 -0
  168. package/dist/annotations/annotation-sprite.d.ts.map +1 -0
  169. package/dist/annotations/index.d.ts +4 -0
  170. package/dist/annotations/index.d.ts.map +1 -0
  171. package/dist/annotations-C0ugfCn4.js +2158 -0
  172. package/dist/annotations-C0ugfCn4.js.map +1 -0
  173. package/dist/audio/ambisonic-renderer.d.ts +36 -0
  174. package/dist/audio/ambisonic-renderer.d.ts.map +1 -0
  175. package/dist/audio/audio-manager.d.ts +44 -0
  176. package/dist/audio/audio-manager.d.ts.map +1 -0
  177. package/dist/captions/caption-renderer.d.ts +57 -0
  178. package/dist/captions/caption-renderer.d.ts.map +1 -0
  179. package/dist/captions/index.d.ts +3 -0
  180. package/dist/captions/index.d.ts.map +1 -0
  181. package/dist/captions/webvtt-parser.d.ts +31 -0
  182. package/dist/captions/webvtt-parser.d.ts.map +1 -0
  183. package/dist/captions-BP0H2E03.js +274 -0
  184. package/dist/captions-BP0H2E03.js.map +1 -0
  185. package/dist/collab-BXPomrS0.js +978 -0
  186. package/dist/collab-BXPomrS0.js.map +1 -0
  187. package/dist/collaborative/chat-button.d.ts +22 -0
  188. package/dist/collaborative/chat-button.d.ts.map +1 -0
  189. package/dist/collaborative/chat-panel.d.ts +46 -0
  190. package/dist/collaborative/chat-panel.d.ts.map +1 -0
  191. package/dist/collaborative/collab-client.d.ts +73 -0
  192. package/dist/collaborative/collab-client.d.ts.map +1 -0
  193. package/dist/collaborative/gaze-cursor-manager.d.ts +29 -0
  194. package/dist/collaborative/gaze-cursor-manager.d.ts.map +1 -0
  195. package/dist/collaborative/gaze-sender.d.ts +29 -0
  196. package/dist/collaborative/gaze-sender.d.ts.map +1 -0
  197. package/dist/collaborative/voice-button.d.ts +25 -0
  198. package/dist/collaborative/voice-button.d.ts.map +1 -0
  199. package/dist/collaborative/voice-manager.d.ts +45 -0
  200. package/dist/collaborative/voice-manager.d.ts.map +1 -0
  201. package/dist/config/format-registry.d.ts +2 -0
  202. package/dist/config/format-registry.d.ts.map +1 -0
  203. package/dist/config/meta-config.d.ts +14 -0
  204. package/dist/config/meta-config.d.ts.map +1 -0
  205. package/dist/controls/cc-button.d.ts +24 -0
  206. package/dist/controls/cc-button.d.ts.map +1 -0
  207. package/dist/controls/compass.d.ts +15 -0
  208. package/dist/controls/compass.d.ts.map +1 -0
  209. package/dist/controls/controls-overlay.d.ts +46 -0
  210. package/dist/controls/controls-overlay.d.ts.map +1 -0
  211. package/dist/controls/fullscreen-button.d.ts +16 -0
  212. package/dist/controls/fullscreen-button.d.ts.map +1 -0
  213. package/dist/controls/icons.d.ts +23 -0
  214. package/dist/controls/icons.d.ts.map +1 -0
  215. package/dist/controls/keyboard-shortcuts.d.ts +21 -0
  216. package/dist/controls/keyboard-shortcuts.d.ts.map +1 -0
  217. package/dist/controls/live-indicator.d.ts +17 -0
  218. package/dist/controls/live-indicator.d.ts.map +1 -0
  219. package/dist/controls/play-button.d.ts +14 -0
  220. package/dist/controls/play-button.d.ts.map +1 -0
  221. package/dist/controls/playlist-controls.d.ts +18 -0
  222. package/dist/controls/playlist-controls.d.ts.map +1 -0
  223. package/dist/controls/playlist-panel.d.ts +27 -0
  224. package/dist/controls/playlist-panel.d.ts.map +1 -0
  225. package/dist/controls/quality-menu.d.ts +17 -0
  226. package/dist/controls/quality-menu.d.ts.map +1 -0
  227. package/dist/controls/seek-bar.d.ts +23 -0
  228. package/dist/controls/seek-bar.d.ts.map +1 -0
  229. package/dist/controls/volume-control.d.ts +14 -0
  230. package/dist/controls/volume-control.d.ts.map +1 -0
  231. package/dist/controls/vr-button.d.ts +14 -0
  232. package/dist/controls/vr-button.d.ts.map +1 -0
  233. package/dist/core/base-element.d.ts +53 -0
  234. package/dist/core/base-element.d.ts.map +1 -0
  235. package/dist/core/event-emitter.d.ts +23 -0
  236. package/dist/core/event-emitter.d.ts.map +1 -0
  237. package/dist/core/html-element.d.ts +13 -0
  238. package/dist/core/html-element.d.ts.map +1 -0
  239. package/dist/core/media-element.d.ts +86 -0
  240. package/dist/core/media-element.d.ts.map +1 -0
  241. package/dist/core/player-state.d.ts +63 -0
  242. package/dist/core/player-state.d.ts.map +1 -0
  243. package/dist/dash-adapter-tid9ZyhO.js +75 -0
  244. package/dist/dash-adapter-tid9ZyhO.js.map +1 -0
  245. package/dist/elements/vz-annotation.d.ts +26 -0
  246. package/dist/elements/vz-annotation.d.ts.map +1 -0
  247. package/dist/elements/vz-cinema.d.ts +28 -0
  248. package/dist/elements/vz-cinema.d.ts.map +1 -0
  249. package/dist/elements/vz-img.d.ts +27 -0
  250. package/dist/elements/vz-img.d.ts.map +1 -0
  251. package/dist/elements/vz-live.d.ts +36 -0
  252. package/dist/elements/vz-live.d.ts.map +1 -0
  253. package/dist/elements/vz-playlist.d.ts +74 -0
  254. package/dist/elements/vz-playlist.d.ts.map +1 -0
  255. package/dist/elements/vz-tour-img.d.ts +21 -0
  256. package/dist/elements/vz-tour-img.d.ts.map +1 -0
  257. package/dist/elements/vz-tour-portal.d.ts +19 -0
  258. package/dist/elements/vz-tour-portal.d.ts.map +1 -0
  259. package/dist/elements/vz-tour.d.ts +49 -0
  260. package/dist/elements/vz-tour.d.ts.map +1 -0
  261. package/dist/elements/vz-video.d.ts +21 -0
  262. package/dist/elements/vz-video.d.ts.map +1 -0
  263. package/dist/hls-adapter-BivH46L_.js +97 -0
  264. package/dist/hls-adapter-BivH46L_.js.map +1 -0
  265. package/dist/hotspots/hotspot-interaction.d.ts +23 -0
  266. package/dist/hotspots/hotspot-interaction.d.ts.map +1 -0
  267. package/dist/hotspots/hotspot-manager.d.ts +18 -0
  268. package/dist/hotspots/hotspot-manager.d.ts.map +1 -0
  269. package/dist/hotspots/hotspot-renderer.d.ts +26 -0
  270. package/dist/hotspots/hotspot-renderer.d.ts.map +1 -0
  271. package/dist/index.d.ts +48 -0
  272. package/dist/index.d.ts.map +1 -0
  273. package/dist/license/feature-gates.d.ts +6 -0
  274. package/dist/license/feature-gates.d.ts.map +1 -0
  275. package/dist/license/integrity.d.ts +33 -0
  276. package/dist/license/integrity.d.ts.map +1 -0
  277. package/dist/license/license-checker.d.ts +18 -0
  278. package/dist/license/license-checker.d.ts.map +1 -0
  279. package/dist/license/master-key.d.ts +14 -0
  280. package/dist/license/master-key.d.ts.map +1 -0
  281. package/dist/license/watermark-guard.d.ts +24 -0
  282. package/dist/license/watermark-guard.d.ts.map +1 -0
  283. package/dist/license/watermark.d.ts +19 -0
  284. package/dist/license/watermark.d.ts.map +1 -0
  285. package/dist/register-CwnmiGEs.js +5740 -0
  286. package/dist/register-CwnmiGEs.js.map +1 -0
  287. package/dist/register.d.ts +6 -0
  288. package/dist/register.d.ts.map +1 -0
  289. package/dist/register.js +5 -0
  290. package/dist/register.js.map +1 -0
  291. package/dist/renderer/camera-controller.d.ts +75 -0
  292. package/dist/renderer/camera-controller.d.ts.map +1 -0
  293. package/dist/renderer/projections/cinema-projection.d.ts +32 -0
  294. package/dist/renderer/projections/cinema-projection.d.ts.map +1 -0
  295. package/dist/renderer/projections/cubemap-projection.d.ts +34 -0
  296. package/dist/renderer/projections/cubemap-projection.d.ts.map +1 -0
  297. package/dist/renderer/projections/eac-projection.d.ts +35 -0
  298. package/dist/renderer/projections/eac-projection.d.ts.map +1 -0
  299. package/dist/renderer/projections/equirect-projection.d.ts +27 -0
  300. package/dist/renderer/projections/equirect-projection.d.ts.map +1 -0
  301. package/dist/renderer/projections/fisheye-projection.d.ts +28 -0
  302. package/dist/renderer/projections/fisheye-projection.d.ts.map +1 -0
  303. package/dist/renderer/projections/flat-projection.d.ts +32 -0
  304. package/dist/renderer/projections/flat-projection.d.ts.map +1 -0
  305. package/dist/renderer/projections/projection.d.ts +18 -0
  306. package/dist/renderer/projections/projection.d.ts.map +1 -0
  307. package/dist/renderer/renderer.d.ts +72 -0
  308. package/dist/renderer/renderer.d.ts.map +1 -0
  309. package/dist/renderer/shaders/eac.glsl.d.ts +12 -0
  310. package/dist/renderer/shaders/eac.glsl.d.ts.map +1 -0
  311. package/dist/renderer/shaders/fisheye.glsl.d.ts +22 -0
  312. package/dist/renderer/shaders/fisheye.glsl.d.ts.map +1 -0
  313. package/dist/spatial-BeadwNJA.js +146 -0
  314. package/dist/spatial-BeadwNJA.js.map +1 -0
  315. package/dist/sri.json +12 -0
  316. package/dist/streaming/adapter-factory.d.ts +8 -0
  317. package/dist/streaming/adapter-factory.d.ts.map +1 -0
  318. package/dist/streaming/dash-adapter.d.ts +21 -0
  319. package/dist/streaming/dash-adapter.d.ts.map +1 -0
  320. package/dist/streaming/hls-adapter.d.ts +26 -0
  321. package/dist/streaming/hls-adapter.d.ts.map +1 -0
  322. package/dist/streaming/progressive-adapter.d.ts +18 -0
  323. package/dist/streaming/progressive-adapter.d.ts.map +1 -0
  324. package/dist/streaming/quality-selector.d.ts +25 -0
  325. package/dist/streaming/quality-selector.d.ts.map +1 -0
  326. package/dist/streaming/source-manager.d.ts +46 -0
  327. package/dist/streaming/source-manager.d.ts.map +1 -0
  328. package/dist/streaming/types.d.ts +25 -0
  329. package/dist/streaming/types.d.ts.map +1 -0
  330. package/dist/styles/controls.d.ts +15 -0
  331. package/dist/styles/controls.d.ts.map +1 -0
  332. package/dist/three-Bci7aSeI.js +20078 -0
  333. package/dist/three-Bci7aSeI.js.map +1 -0
  334. package/dist/utils/fullscreen.d.ts +6 -0
  335. package/dist/utils/fullscreen.d.ts.map +1 -0
  336. package/dist/utils/sanitize.d.ts +19 -0
  337. package/dist/utils/sanitize.d.ts.map +1 -0
  338. package/dist/vizor.js +113 -0
  339. package/dist/vizor.js.map +1 -0
  340. package/dist/xr/xr-controller.d.ts +27 -0
  341. package/dist/xr/xr-controller.d.ts.map +1 -0
  342. package/dist/xr/xr-manager.d.ts +43 -0
  343. package/dist/xr/xr-manager.d.ts.map +1 -0
  344. package/package.json +94 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collab-BXPomrS0.js","sources":["../src/controls/icons.ts","../src/collaborative/collab-client.ts","../src/collaborative/gaze-cursor-manager.ts","../src/collaborative/gaze-sender.ts","../src/collaborative/chat-panel.ts","../src/collaborative/chat-button.ts","../src/collaborative/voice-manager.ts","../src/collaborative/voice-button.ts"],"sourcesContent":["/**\n * SVG icon strings for controls.\n * Uses stroke-based icons with 1.5px weight for a refined, Vimeo-inspired look.\n * Play/pause remain filled for quick recognition.\n */\n\nexport const ICON_PLAY = `<svg viewBox=\"0 0 24 24\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\nexport const ICON_PAUSE = `<svg viewBox=\"0 0 24 24\"><path d=\"M6 19h4V5H6v14zm8-14v14h4V5h-4z\"/></svg>`;\n\nexport const ICON_VOLUME_HIGH = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\"/><path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/></svg>`;\n\nexport const ICON_VOLUME_LOW = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/></svg>`;\n\nexport const ICON_VOLUME_MUTED = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" fill=\"currentColor\" stroke=\"none\"/><line x1=\"23\" y1=\"9\" x2=\"17\" y2=\"15\"/><line x1=\"17\" y1=\"9\" x2=\"23\" y2=\"15\"/></svg>`;\n\nexport const ICON_FULLSCREEN = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nexport const ICON_FULLSCREEN_EXIT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/></svg>`;\n\nexport const ICON_VR = `<svg viewBox=\"0 0 24 24\"><path d=\"M20.74 6H3.21C2.55 6 2 6.57 2 7.28v10.44c0 .7.55 1.28 1.23 1.28h4.79c.52 0 .96-.3 1.19-.77l1.58-3.15c.28-.58.84-.94 1.43-.94h1.56c.59 0 1.15.36 1.43.94l1.58 3.15c.23.47.67.77 1.19.77h4.79c.68 0 1.23-.57 1.23-1.28V7.28C22 6.57 21.43 6 20.74 6zM7.5 14.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zm9 0c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z\"/></svg>`;\n\nexport const ICON_COMPASS = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polygon points=\"16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76\" fill=\"currentColor\"/></svg>`;\n\nexport const ICON_SETTINGS = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`;\n\n// Playlist & Live icons (for future steps)\nexport const ICON_PLAYLIST_NEXT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"5 4 15 12 5 20 5 4\" fill=\"currentColor\"/><line x1=\"19\" y1=\"5\" x2=\"19\" y2=\"19\"/></svg>`;\n\nexport const ICON_PLAYLIST_PREV = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polygon points=\"19 20 9 12 19 4 19 20\" fill=\"currentColor\"/><line x1=\"5\" y1=\"19\" x2=\"5\" y2=\"5\"/></svg>`;\n\nexport const ICON_LIVE_DOT = `<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"6\" fill=\"currentColor\"/></svg>`;\n\nexport const ICON_CC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" ry=\"2\"/><path d=\"M7 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M7 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/><path d=\"M14 10.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5\"/><path d=\"M14 13.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5\"/></svg>`;\n\nexport const ICON_CHAT = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>`;\n\nexport const ICON_MIC = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>`;\n\nexport const ICON_MIC_MUTED = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/><path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"/><path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2c0 .64-.09 1.26-.26 1.85\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>`;\n","import type { PlayerState } from '../core/player-state.js';\nimport type { ClientMessage, ServerMessage, CollabParticipant } from '@vizor-vr/shared';\n\n/** Drift threshold in seconds — viewer only seeks if drift exceeds this */\nconst DRIFT_THRESHOLD = 1.0;\n\n/** Reconnect delay in milliseconds */\nconst RECONNECT_DELAY = 3000;\n\n/** Throttle interval for playback_state messages (ms) */\nconst PLAYBACK_THROTTLE = 250;\n\nexport interface CollabClientOptions {\n serverUrl: string;\n roomCode: string;\n role: 'host' | 'viewer';\n userId: string;\n displayName: string;\n state: PlayerState;\n /** The media element for play/pause/seek control */\n mediaElement: {\n play(): void | Promise<void>;\n pause(): void;\n seek(time: number): void;\n currentTime: number;\n };\n /** Optional callback when participants change */\n onParticipantsChange?: (users: CollabParticipant[]) => void;\n /** Callback when a peer's gaze position is received */\n onPeerGaze?: (userId: string, lat: number, lon: number) => void;\n /** Callback when a user joins the room */\n onUserJoined?: (user: CollabParticipant) => void;\n /** Callback when a user leaves the room */\n onUserLeft?: (userId: string) => void;\n /** Callback when a chat message is received */\n onChatMessage?: (userId: string, displayName: string, text: string, timestamp: number) => void;\n /** Callback when a voice signal (SDP/ICE) is received from a peer */\n onVoiceSignal?: (fromUserId: string, sdp?: string, candidate?: string) => void;\n /** Room password (host sets, viewers must match) */\n password?: string;\n}\n\n/**\n * Browser-side WebSocket client for collaborative viewing.\n *\n * - Host: subscribes to local state changes → sends playback_state/seek to server\n * - Viewer: receives sync messages → applies play/pause/seek locally\n * - Auto-reconnects on unexpected close\n */\nexport class CollaborativeClient {\n private ws: WebSocket | null = null;\n private options: CollabClientOptions;\n private unsubscribes: Array<() => void> = [];\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private disposed = false;\n private lastPlaybackSend = 0;\n private connected = false;\n\n constructor(options: CollabClientOptions) {\n this.options = options;\n }\n\n /** Connect to the collaborative server */\n connect(): void {\n if (this.disposed) return;\n\n try {\n this.ws = new WebSocket(this.options.serverUrl);\n } catch {\n this.scheduleReconnect();\n return;\n }\n\n this.ws.onopen = () => {\n this.connected = true;\n // Send join message\n this.send({\n type: 'join',\n roomCode: this.options.roomCode,\n userId: this.options.userId,\n displayName: this.options.displayName,\n password: this.options.password,\n });\n\n // If host, subscribe to state changes to broadcast\n if (this.options.role === 'host') {\n this.subscribeHostState();\n }\n };\n\n this.ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data as string) as ServerMessage;\n this.handleMessage(msg);\n } catch {\n // Ignore invalid messages\n }\n };\n\n this.ws.onclose = () => {\n this.connected = false;\n this.cleanupSubscriptions();\n if (!this.disposed) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n // onclose will fire after onerror\n };\n }\n\n /** Whether the client is currently connected */\n isConnected(): boolean {\n return this.connected;\n }\n\n /** Gracefully disconnect and clean up */\n dispose(): void {\n this.disposed = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n this.cleanupSubscriptions();\n\n if (this.ws) {\n // Send leave before closing\n if (this.ws.readyState === WebSocket.OPEN) {\n this.send({ type: 'leave' });\n }\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n }\n\n // --- Private ---\n\n private handleMessage(msg: ServerMessage): void {\n switch (msg.type) {\n case 'room_state':\n this.handleRoomState(msg.users, msg.playing, msg.currentTime);\n break;\n\n case 'sync':\n this.handleSync(msg.playing, msg.currentTime);\n break;\n\n case 'user_joined':\n this.options.onUserJoined?.(msg.user);\n this.options.onParticipantsChange?.([]); // Signal change; full list comes with room_state\n break;\n\n case 'user_left':\n this.options.onUserLeft?.(msg.userId);\n this.options.onParticipantsChange?.([]); // Signal change\n break;\n\n case 'error':\n console.warn(`[Vizor Collab] Server error: ${msg.code} — ${msg.message}`);\n break;\n\n case 'peer_gaze':\n this.options.onPeerGaze?.(msg.userId, msg.lat, msg.lon);\n break;\n\n case 'chat_message':\n this.options.onChatMessage?.(msg.userId, msg.displayName, msg.text, msg.timestamp);\n break;\n\n case 'voice_signal':\n this.options.onVoiceSignal?.(msg.fromUserId, msg.sdp, msg.candidate);\n break;\n }\n }\n\n private handleRoomState(\n users: CollabParticipant[],\n playing: boolean,\n currentTime: number,\n ): void {\n this.options.onParticipantsChange?.(users);\n\n // Viewer: sync to room state on join\n if (this.options.role === 'viewer') {\n this.applySync(playing, currentTime);\n }\n }\n\n private handleSync(playing: boolean, currentTime: number): void {\n // Only viewers apply sync\n if (this.options.role !== 'viewer') return;\n this.applySync(playing, currentTime);\n }\n\n private applySync(playing: boolean, currentTime: number): void {\n const { state, mediaElement } = this.options;\n const localTime = mediaElement.currentTime;\n const drift = Math.abs(currentTime - localTime);\n\n // Seek if drift exceeds threshold\n if (drift > DRIFT_THRESHOLD) {\n mediaElement.seek(currentTime);\n }\n\n // Sync play/pause\n const localPlaying = state.get('playing');\n if (playing && !localPlaying) {\n Promise.resolve(mediaElement.play()).catch(() => {});\n } else if (!playing && localPlaying) {\n mediaElement.pause();\n }\n }\n\n /** Host: subscribe to local state changes and broadcast them */\n private subscribeHostState(): void {\n const { state } = this.options;\n\n // Subscribe to playing state changes (play/pause)\n const unsubPlaying = state.subscribe('playing', (playing) => {\n this.sendPlaybackState(playing, state.get('currentTime'));\n });\n this.unsubscribes.push(unsubPlaying);\n\n // Subscribe to seeking (user seeks)\n const unsubSeeking = state.subscribe('seeking', (seeking, prevSeeking) => {\n // Send seek when seeking ends (user released seek bar)\n if (!seeking && prevSeeking) {\n this.send({\n type: 'seek',\n currentTime: state.get('currentTime'),\n });\n }\n });\n this.unsubscribes.push(unsubSeeking);\n }\n\n /** Throttled playback state sender */\n private sendPlaybackState(playing: boolean, currentTime: number): void {\n const now = Date.now();\n if (now - this.lastPlaybackSend < PLAYBACK_THROTTLE) return;\n this.lastPlaybackSend = now;\n\n this.send({\n type: 'playback_state',\n playing,\n currentTime,\n timestamp: now,\n });\n }\n\n /** Send a chat message */\n sendChat(text: string): void {\n this.send({ type: 'chat', text });\n }\n\n /** Send a voice signal (SDP offer/answer or ICE candidate) to a specific peer */\n sendVoiceSignal(targetUserId: string, sdp?: string, candidate?: string): void {\n this.send({ type: 'voice_signal', targetUserId, sdp, candidate });\n }\n\n /** Send a message to the server */\n send(msg: ClientMessage): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(msg));\n }\n }\n\n private scheduleReconnect(): void {\n if (this.disposed || this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, RECONNECT_DELAY);\n }\n\n /** Register a cleanup function to run on dispose */\n addCleanup(fn: () => void): void {\n this.unsubscribes.push(fn);\n }\n\n private cleanupSubscriptions(): void {\n for (const unsub of this.unsubscribes) unsub();\n this.unsubscribes = [];\n }\n}\n","import {\n Sprite,\n SpriteMaterial,\n CanvasTexture,\n LinearFilter,\n} from 'three';\nimport type { Scene } from 'three';\nimport { latLonToSpherical, COLLAB_GAZE_LERP_FACTOR } from '@vizor-vr/shared';\n\n/** Tracked state for a single peer's gaze cursor */\ninterface PeerCursor {\n sprite: Sprite;\n nameLabel: Sprite;\n targetLat: number;\n targetLon: number;\n currentLat: number;\n currentLon: number;\n displayName: string;\n color: string;\n}\n\n/** Color palette for peer cursors — assigned by join order */\nconst PEER_COLORS = [\n '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',\n '#F7DC6F', '#BB8FCE', '#85C1E9', '#F1948A', '#82E0AA',\n];\n\n/** Distance from center for cursor sprites (in front of sphere at 200) */\nconst CURSOR_DISTANCE = 195;\nconst CURSOR_SCALE = 6;\nconst LABEL_SCALE_X = 14;\nconst LABEL_SCALE_Y = 5;\nconst CURSOR_CANVAS_SIZE = 64;\nconst LABEL_CANVAS_WIDTH = 256;\nconst LABEL_CANVAS_HEIGHT = 64;\n\n/**\n * Manages 3D sprite cursors for all remote peers.\n * Each peer gets a colored dot on the sphere at their camera orientation.\n * Positions are smoothly interpolated each frame via lerp.\n */\nexport class GazeCursorManager {\n private scene: Scene;\n private cursors = new Map<string, PeerCursor>();\n private colorIndex = 0;\n\n constructor(scene: Scene) {\n this.scene = scene;\n }\n\n /** Add a cursor for a new peer */\n addPeer(userId: string, displayName: string): void {\n if (this.cursors.has(userId)) return;\n\n const color = PEER_COLORS[this.colorIndex % PEER_COLORS.length]!;\n this.colorIndex++;\n\n const sprite = this.createCursorSprite(color);\n const nameLabel = this.createLabelSprite(displayName, color);\n nameLabel.visible = true;\n\n this.scene.add(sprite);\n this.scene.add(nameLabel);\n\n this.cursors.set(userId, {\n sprite,\n nameLabel,\n targetLat: 0,\n targetLon: 0,\n currentLat: 0,\n currentLon: 0,\n displayName,\n color: color,\n });\n }\n\n /** Remove a peer's cursor */\n removePeer(userId: string): void {\n const cursor = this.cursors.get(userId);\n if (!cursor) return;\n\n this.scene.remove(cursor.sprite);\n this.scene.remove(cursor.nameLabel);\n cursor.sprite.material.map?.dispose();\n cursor.sprite.material.dispose();\n cursor.nameLabel.material.map?.dispose();\n cursor.nameLabel.material.dispose();\n this.cursors.delete(userId);\n }\n\n /** Update the target gaze position for a peer */\n updateGaze(userId: string, lat: number, lon: number): void {\n const cursor = this.cursors.get(userId);\n if (!cursor) return;\n cursor.targetLat = lat;\n cursor.targetLon = lon;\n }\n\n /** Called each animation frame. Lerps all cursors toward their target positions. */\n update(): void {\n for (const [, cursor] of this.cursors) {\n cursor.currentLat += (cursor.targetLat - cursor.currentLat) * COLLAB_GAZE_LERP_FACTOR;\n cursor.currentLon += (cursor.targetLon - cursor.currentLon) * COLLAB_GAZE_LERP_FACTOR;\n\n const { phi, theta } = latLonToSpherical(cursor.currentLat, cursor.currentLon);\n const x = CURSOR_DISTANCE * Math.sin(phi) * Math.cos(theta);\n const y = CURSOR_DISTANCE * Math.cos(phi);\n const z = CURSOR_DISTANCE * Math.sin(phi) * Math.sin(theta);\n\n cursor.sprite.position.set(x, y, z);\n\n // Name label sits above the cursor\n cursor.nameLabel.position.set(x, y + CURSOR_SCALE * 0.8, z);\n }\n }\n\n /** Get the number of tracked peers */\n getPeerCount(): number {\n return this.cursors.size;\n }\n\n /** Clean up all cursors */\n dispose(): void {\n for (const [userId] of this.cursors) {\n this.removePeer(userId);\n }\n }\n\n /** Create a colored circle sprite for the cursor dot */\n private createCursorSprite(color: string): Sprite {\n const canvas = document.createElement('canvas');\n canvas.width = CURSOR_CANVAS_SIZE;\n canvas.height = CURSOR_CANVAS_SIZE;\n const ctx = canvas.getContext('2d')!;\n\n const cx = CURSOR_CANVAS_SIZE / 2;\n const cy = CURSOR_CANVAS_SIZE / 2;\n const radius = CURSOR_CANVAS_SIZE / 2 - 4;\n\n // Colored circle\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(cx, cy, radius, 0, Math.PI * 2);\n ctx.fill();\n\n // White ring border\n ctx.strokeStyle = '#ffffff';\n ctx.lineWidth = 3;\n ctx.stroke();\n\n const texture = new CanvasTexture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n\n const material = new SpriteMaterial({\n map: texture,\n sizeAttenuation: true,\n depthTest: false,\n transparent: true,\n });\n\n const sprite = new Sprite(material);\n sprite.scale.set(CURSOR_SCALE, CURSOR_SCALE, 1);\n return sprite;\n }\n\n /** Create a text label sprite showing the peer's display name */\n private createLabelSprite(name: string, color: string): Sprite {\n const canvas = document.createElement('canvas');\n canvas.width = LABEL_CANVAS_WIDTH;\n canvas.height = LABEL_CANVAS_HEIGHT;\n const ctx = canvas.getContext('2d')!;\n\n // Semi-transparent background bar\n const padding = 10;\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';\n ctx.beginPath();\n ctx.roundRect(padding, padding, LABEL_CANVAS_WIDTH - padding * 2, LABEL_CANVAS_HEIGHT - padding * 2, 8);\n ctx.fill();\n\n // Name text\n ctx.fillStyle = color;\n ctx.font = 'bold 24px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(name, LABEL_CANVAS_WIDTH / 2, LABEL_CANVAS_HEIGHT / 2);\n\n const texture = new CanvasTexture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n\n const material = new SpriteMaterial({\n map: texture,\n sizeAttenuation: true,\n depthTest: false,\n transparent: true,\n });\n\n const sprite = new Sprite(material);\n sprite.scale.set(LABEL_SCALE_X, LABEL_SCALE_Y, 1);\n return sprite;\n }\n}\n","import type { ClientMessage } from '@vizor-vr/shared';\nimport { COLLAB_GAZE_INTERVAL, COLLAB_GAZE_THRESHOLD } from '@vizor-vr/shared';\n\n/** Orientation provider callback (matches CameraController.getOrientation) */\nexport interface OrientationProvider {\n getOrientation(): { lat: number; lon: number; fov: number };\n}\n\n/**\n * Samples local camera orientation at ~5Hz and sends throttled `gaze` messages.\n * Only sends when orientation changes by more than COLLAB_GAZE_THRESHOLD degrees.\n */\nexport class GazeSender {\n private timer: ReturnType<typeof setInterval> | null = null;\n private lastSentLat = NaN;\n private lastSentLon = NaN;\n private orientationProvider: OrientationProvider;\n private sendFn: (msg: ClientMessage) => void;\n\n constructor(orientationProvider: OrientationProvider, sendFn: (msg: ClientMessage) => void) {\n this.orientationProvider = orientationProvider;\n this.sendFn = sendFn;\n }\n\n /** Start sampling and sending gaze messages */\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => this.sample(), COLLAB_GAZE_INTERVAL);\n }\n\n /** Stop sampling */\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n /** Clean up */\n dispose(): void {\n this.stop();\n }\n\n private sample(): void {\n const { lat, lon } = this.orientationProvider.getOrientation();\n const dLat = Math.abs(lat - this.lastSentLat);\n const dLon = Math.abs(lon - this.lastSentLon);\n\n if (dLat > COLLAB_GAZE_THRESHOLD || dLon > COLLAB_GAZE_THRESHOLD || isNaN(this.lastSentLat)) {\n this.lastSentLat = lat;\n this.lastSentLon = lon;\n this.sendFn({ type: 'gaze', lat, lon });\n }\n }\n}\n","/** A single chat message displayed in the panel */\nexport interface ChatMessage {\n userId: string;\n displayName: string;\n text: string;\n timestamp: number;\n isLocal: boolean;\n}\n\n/** Color palette matching gaze cursor colors */\nconst PEER_COLORS = [\n '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8',\n '#F7DC6F', '#BB8FCE', '#85C1E9', '#F1948A', '#82E0AA',\n];\n\nconst CHAT_CSS = `\n.vz-chat-panel {\n position: absolute;\n right: 0;\n top: 0;\n bottom: 0;\n width: 300px;\n max-width: 70%;\n background: rgba(15, 15, 25, 0.95);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n z-index: 25;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n.vz-chat-panel.open {\n transform: translateX(0);\n}\n.vz-chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n flex-shrink: 0;\n}\n.vz-chat-title {\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n}\n.vz-chat-close {\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n font-size: 18px;\n cursor: pointer;\n padding: 0 4px;\n line-height: 1;\n}\n.vz-chat-close:hover {\n color: #fff;\n}\n.vz-chat-messages {\n flex: 1;\n overflow-y: auto;\n padding: 8px 12px;\n scrollbar-width: thin;\n scrollbar-color: rgba(255,255,255,0.2) transparent;\n}\n.vz-chat-messages::-webkit-scrollbar {\n width: 4px;\n}\n.vz-chat-messages::-webkit-scrollbar-thumb {\n background: rgba(255,255,255,0.2);\n border-radius: 2px;\n}\n.vz-chat-message {\n margin: 4px 0;\n padding: 4px 0;\n}\n.vz-chat-msg-header {\n display: flex;\n align-items: baseline;\n gap: 6px;\n}\n.vz-chat-msg-name {\n font-weight: 600;\n font-size: 12px;\n}\n.vz-chat-msg-time {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n}\n.vz-chat-msg-text {\n font-size: 13px;\n color: rgba(255, 255, 255, 0.9);\n word-break: break-word;\n margin-top: 2px;\n line-height: 1.4;\n}\n.vz-chat-input-row {\n display: flex;\n gap: 6px;\n padding: 8px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n flex-shrink: 0;\n}\n.vz-chat-input {\n flex: 1;\n height: 32px;\n border-radius: 6px;\n border: none;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n padding: 0 10px;\n font-size: 13px;\n outline: none;\n}\n.vz-chat-input::placeholder {\n color: rgba(255, 255, 255, 0.3);\n}\n.vz-chat-input:focus {\n background: rgba(255, 255, 255, 0.15);\n}\n.vz-chat-send {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n border: none;\n background: var(--vz-primary, #f43f5e);\n color: #fff;\n font-size: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.vz-chat-send:hover {\n opacity: 0.85;\n}\n.vz-chat-empty {\n color: rgba(255, 255, 255, 0.3);\n font-size: 13px;\n text-align: center;\n padding: 24px 16px;\n}\n`;\n\n/**\n * Side panel overlay for collaborative chat.\n * Slides in from the right with frosted glass styling.\n */\nexport class ChatPanel {\n private panel: HTMLDivElement;\n private messagesEl: HTMLDivElement;\n private inputEl: HTMLInputElement;\n private emptyEl: HTMLDivElement;\n private styleEl: HTMLStyleElement;\n private isOpen = false;\n private messages: ChatMessage[] = [];\n private colorMap = new Map<string, string>();\n private colorIndex = 0;\n private onSend: (text: string) => void;\n private shadowRoot: ShadowRoot;\n\n constructor(shadowRoot: ShadowRoot, onSend: (text: string) => void) {\n this.shadowRoot = shadowRoot;\n this.onSend = onSend;\n\n // Inject CSS\n this.styleEl = document.createElement('style');\n this.styleEl.textContent = CHAT_CSS;\n shadowRoot.appendChild(this.styleEl);\n\n // Build panel DOM\n this.panel = document.createElement('div');\n this.panel.className = 'vz-chat-panel';\n\n // Header\n const header = document.createElement('div');\n header.className = 'vz-chat-header';\n const title = document.createElement('span');\n title.className = 'vz-chat-title';\n title.textContent = 'Chat';\n const closeBtn = document.createElement('button');\n closeBtn.className = 'vz-chat-close';\n closeBtn.textContent = '\\u2715';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(title);\n header.appendChild(closeBtn);\n this.panel.appendChild(header);\n\n // Messages area\n this.messagesEl = document.createElement('div');\n this.messagesEl.className = 'vz-chat-messages';\n this.emptyEl = document.createElement('div');\n this.emptyEl.className = 'vz-chat-empty';\n this.emptyEl.textContent = 'No messages yet';\n this.messagesEl.appendChild(this.emptyEl);\n this.panel.appendChild(this.messagesEl);\n\n // Input row\n const inputRow = document.createElement('div');\n inputRow.className = 'vz-chat-input-row';\n this.inputEl = document.createElement('input');\n this.inputEl.className = 'vz-chat-input';\n this.inputEl.type = 'text';\n this.inputEl.placeholder = 'Type a message...';\n this.inputEl.maxLength = 500;\n this.inputEl.addEventListener('keydown', (e) => {\n e.stopPropagation(); // Prevent keyboard shortcuts from firing\n if (e.key === 'Enter') {\n this.handleSend();\n }\n });\n const sendBtn = document.createElement('button');\n sendBtn.className = 'vz-chat-send';\n sendBtn.innerHTML = '\\u27A4'; // Right arrow\n sendBtn.addEventListener('click', () => this.handleSend());\n inputRow.appendChild(this.inputEl);\n inputRow.appendChild(sendBtn);\n this.panel.appendChild(inputRow);\n\n shadowRoot.appendChild(this.panel);\n }\n\n /** Add a chat message to the panel */\n addMessage(msg: ChatMessage): void {\n this.messages.push(msg);\n if (this.emptyEl.parentNode) {\n this.emptyEl.remove();\n }\n this.renderMessage(msg);\n this.scrollToBottom();\n }\n\n /** Toggle panel open/closed */\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /** Open the panel */\n open(): void {\n this.isOpen = true;\n this.panel.classList.add('open');\n this.inputEl.focus();\n }\n\n /** Close the panel */\n close(): void {\n this.isOpen = false;\n this.panel.classList.remove('open');\n }\n\n /** Whether the panel is currently visible */\n isVisible(): boolean {\n return this.isOpen;\n }\n\n /** Get message count */\n getMessageCount(): number {\n return this.messages.length;\n }\n\n /** Clean up */\n dispose(): void {\n this.panel.remove();\n this.styleEl.remove();\n }\n\n private handleSend(): void {\n const text = this.inputEl.value.trim();\n if (!text) return;\n this.inputEl.value = '';\n this.onSend(text);\n }\n\n private renderMessage(msg: ChatMessage): void {\n const el = document.createElement('div');\n el.className = 'vz-chat-message';\n\n const headerEl = document.createElement('div');\n headerEl.className = 'vz-chat-msg-header';\n\n const nameEl = document.createElement('span');\n nameEl.className = 'vz-chat-msg-name';\n nameEl.style.color = this.getColorForUser(msg.userId);\n nameEl.textContent = msg.isLocal ? 'You' : msg.displayName;\n\n const timeEl = document.createElement('span');\n timeEl.className = 'vz-chat-msg-time';\n timeEl.textContent = this.formatTime(msg.timestamp);\n\n headerEl.appendChild(nameEl);\n headerEl.appendChild(timeEl);\n\n const textEl = document.createElement('div');\n textEl.className = 'vz-chat-msg-text';\n textEl.textContent = msg.text; // textContent auto-escapes HTML\n\n el.appendChild(headerEl);\n el.appendChild(textEl);\n this.messagesEl.appendChild(el);\n }\n\n private scrollToBottom(): void {\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n private getColorForUser(userId: string): string {\n if (!this.colorMap.has(userId)) {\n this.colorMap.set(userId, PEER_COLORS[this.colorIndex % PEER_COLORS.length]!);\n this.colorIndex++;\n }\n return this.colorMap.get(userId)!;\n }\n\n private formatTime(ts: number): string {\n const d = new Date(ts);\n const h = d.getHours().toString().padStart(2, '0');\n const m = d.getMinutes().toString().padStart(2, '0');\n return `${h}:${m}`;\n }\n}\n","import { ICON_CHAT } from '../controls/icons.js';\nimport type { ChatPanel } from './chat-panel.js';\n\n/**\n * Chat toggle button with unread message badge.\n * Placed in the controls bar right section.\n */\nexport class ChatButton {\n private container: HTMLDivElement;\n private badge: HTMLSpanElement;\n private unreadCount = 0;\n private chatPanel: ChatPanel;\n\n constructor(chatPanel: ChatPanel) {\n this.chatPanel = chatPanel;\n\n this.container = document.createElement('div');\n this.container.style.position = 'relative';\n this.container.style.display = 'inline-flex';\n\n const btn = document.createElement('button');\n btn.className = 'vz-btn vz-chat-btn';\n btn.innerHTML = ICON_CHAT;\n btn.title = 'Chat (T)';\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.chatPanel.toggle();\n if (this.chatPanel.isVisible()) {\n this.resetUnread();\n }\n });\n\n this.badge = document.createElement('span');\n this.badge.className = 'vz-chat-badge';\n this.badge.style.display = 'none';\n\n this.container.appendChild(btn);\n this.container.appendChild(this.badge);\n }\n\n /** Increment unread count and show badge */\n incrementUnread(): void {\n this.unreadCount++;\n this.updateBadge();\n }\n\n /** Reset unread count and hide badge */\n resetUnread(): void {\n this.unreadCount = 0;\n this.updateBadge();\n }\n\n /** Get the DOM element to insert into controls */\n getElement(): HTMLDivElement {\n return this.container;\n }\n\n /** Clean up */\n dispose(): void {\n this.container.remove();\n }\n\n private updateBadge(): void {\n if (this.unreadCount > 0) {\n this.badge.textContent = this.unreadCount > 99 ? '99+' : String(this.unreadCount);\n this.badge.style.display = 'flex';\n } else {\n this.badge.textContent = '';\n this.badge.style.display = 'none';\n }\n }\n}\n","/** STUN servers for ICE connectivity */\nconst STUN_SERVERS: RTCIceServer[] = [\n { urls: 'stun:stun.l.google.com:19302' },\n { urls: 'stun:stun1.l.google.com:19302' },\n];\n\n/** State of the voice manager */\nexport type VoiceState = 'inactive' | 'active' | 'muted';\n\n/** Per-peer connection info */\ninterface PeerConnection {\n pc: RTCPeerConnection;\n audioEl: HTMLAudioElement;\n}\n\n/**\n * WebRTC mesh voice manager.\n *\n * Handles microphone capture, peer-to-peer audio connections,\n * and SDP/ICE signaling relay. Mesh topology — each participant\n * connects directly to every other participant (suitable for <8 peers).\n */\nexport class VoiceManager {\n private localStream: MediaStream | null = null;\n private peers = new Map<string, PeerConnection>();\n private state: VoiceState = 'inactive';\n private sendSignal: (targetUserId: string, sdp?: string, candidate?: string) => void;\n\n constructor(\n sendSignal: (targetUserId: string, sdp?: string, candidate?: string) => void,\n ) {\n this.sendSignal = sendSignal;\n }\n\n /** Get current voice state */\n getState(): VoiceState {\n return this.state;\n }\n\n /** Start voice — request microphone and begin connections */\n async start(): Promise<void> {\n if (this.state !== 'inactive') return;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n this.state = 'active';\n } catch (err) {\n console.warn('[Vizor Voice] getUserMedia failed:', err);\n throw err;\n }\n }\n\n /** Toggle mute on/off */\n toggleMute(): void {\n if (!this.localStream) return;\n\n if (this.state === 'active') {\n this.localStream.getAudioTracks().forEach((t) => (t.enabled = false));\n this.state = 'muted';\n } else if (this.state === 'muted') {\n this.localStream.getAudioTracks().forEach((t) => (t.enabled = true));\n this.state = 'active';\n }\n }\n\n /** Whether voice is currently active (active or muted) */\n isActive(): boolean {\n return this.state !== 'inactive';\n }\n\n /** Whether mic is currently muted */\n isMuted(): boolean {\n return this.state === 'muted';\n }\n\n /**\n * Initiate a WebRTC connection to a peer (caller side).\n * Creates an offer and sends it via signaling.\n */\n async connectToPeer(peerId: string): Promise<void> {\n if (!this.localStream || this.peers.has(peerId)) return;\n\n const pc = this.createPeerConnection(peerId);\n\n // Add local audio tracks\n this.localStream.getTracks().forEach((track) => {\n pc.addTrack(track, this.localStream!);\n });\n\n // Create and send SDP offer\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n\n this.sendSignal(peerId, JSON.stringify(offer));\n }\n\n /**\n * Handle an incoming voice signal (SDP offer/answer or ICE candidate).\n */\n async handleSignal(fromUserId: string, sdp?: string, candidate?: string): Promise<void> {\n if (!this.localStream) return;\n\n if (sdp) {\n const desc = JSON.parse(sdp) as RTCSessionDescriptionInit;\n\n if (desc.type === 'offer') {\n // Incoming offer — create answer\n const pc = this.createPeerConnection(fromUserId);\n\n // Add local tracks\n this.localStream.getTracks().forEach((track) => {\n pc.addTrack(track, this.localStream!);\n });\n\n await pc.setRemoteDescription(new RTCSessionDescription(desc));\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n this.sendSignal(fromUserId, JSON.stringify(answer));\n } else if (desc.type === 'answer') {\n // Answer to our offer\n const peerConn = this.peers.get(fromUserId);\n if (peerConn) {\n await peerConn.pc.setRemoteDescription(new RTCSessionDescription(desc));\n }\n }\n } else if (candidate) {\n // ICE candidate\n const peerConn = this.peers.get(fromUserId);\n if (peerConn) {\n const iceCandidate = new RTCIceCandidate(JSON.parse(candidate));\n await peerConn.pc.addIceCandidate(iceCandidate);\n }\n }\n }\n\n /** Remove a peer connection (when peer leaves) */\n removePeer(peerId: string): void {\n const peerConn = this.peers.get(peerId);\n if (!peerConn) return;\n\n peerConn.pc.close();\n peerConn.audioEl.srcObject = null;\n peerConn.audioEl.remove();\n this.peers.delete(peerId);\n }\n\n /** Stop voice — release microphone and close all connections */\n stop(): void {\n // Close all peer connections\n this.peers.forEach((peerConn, peerId) => {\n peerConn.pc.close();\n peerConn.audioEl.srcObject = null;\n peerConn.audioEl.remove();\n });\n this.peers.clear();\n\n // Release local microphone\n if (this.localStream) {\n this.localStream.getTracks().forEach((t) => t.stop());\n this.localStream = null;\n }\n\n this.state = 'inactive';\n }\n\n /** Get the number of active peer connections */\n getPeerCount(): number {\n return this.peers.size;\n }\n\n /** Clean up everything */\n dispose(): void {\n this.stop();\n }\n\n // --- Private ---\n\n private createPeerConnection(peerId: string): RTCPeerConnection {\n // If a connection already exists, close it first\n if (this.peers.has(peerId)) {\n this.removePeer(peerId);\n }\n\n const pc = new RTCPeerConnection({ iceServers: STUN_SERVERS });\n\n // Create audio element for remote stream\n const audioEl = document.createElement('audio');\n audioEl.autoplay = true;\n\n // Handle incoming remote track\n pc.ontrack = (event) => {\n audioEl.srcObject = event.streams[0] ?? new MediaStream([event.track]);\n };\n\n // Relay ICE candidates to the peer\n pc.onicecandidate = (event) => {\n if (event.candidate) {\n this.sendSignal(peerId, undefined, JSON.stringify(event.candidate));\n }\n };\n\n // Clean up on connection failure\n pc.onconnectionstatechange = () => {\n if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {\n this.removePeer(peerId);\n }\n };\n\n this.peers.set(peerId, { pc, audioEl });\n return pc;\n }\n}\n","import { ICON_MIC, ICON_MIC_MUTED } from '../controls/icons.js';\nimport type { VoiceManager } from './voice-manager.js';\n\n/**\n * Microphone toggle button for collaborative voice chat.\n *\n * First click starts voice (requests microphone).\n * Subsequent clicks toggle mute.\n * Shows mic icon (active) or mic-muted icon (muted).\n */\nexport class VoiceButton {\n private container: HTMLDivElement;\n private btn: HTMLButtonElement;\n private voiceManager: VoiceManager;\n private onVoiceStarted?: () => void;\n\n constructor(\n voiceManager: VoiceManager,\n onVoiceStarted?: () => void,\n ) {\n this.voiceManager = voiceManager;\n this.onVoiceStarted = onVoiceStarted;\n\n this.container = document.createElement('div');\n this.container.style.position = 'relative';\n this.container.style.display = 'inline-flex';\n\n this.btn = document.createElement('button');\n this.btn.className = 'vz-btn vz-voice-btn';\n this.btn.innerHTML = ICON_MIC;\n this.btn.title = 'Voice Chat (V)';\n this.btn.style.opacity = '0.5'; // Dimmed when inactive\n this.btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.handleClick();\n });\n\n this.container.appendChild(this.btn);\n }\n\n /** Get the DOM element to insert into controls */\n getElement(): HTMLDivElement {\n return this.container;\n }\n\n /** Update button icon based on current voice state */\n updateState(): void {\n const state = this.voiceManager.getState();\n switch (state) {\n case 'inactive':\n this.btn.innerHTML = ICON_MIC;\n this.btn.style.opacity = '0.5';\n this.btn.title = 'Start Voice Chat (V)';\n break;\n case 'active':\n this.btn.innerHTML = ICON_MIC;\n this.btn.style.opacity = '1';\n this.btn.title = 'Mute (V)';\n break;\n case 'muted':\n this.btn.innerHTML = ICON_MIC_MUTED;\n this.btn.style.opacity = '1';\n this.btn.title = 'Unmute (V)';\n break;\n }\n }\n\n /** Handle toggle via keyboard shortcut */\n toggle(): void {\n this.handleClick();\n }\n\n /** Clean up */\n dispose(): void {\n this.container.remove();\n }\n\n // --- Private ---\n\n private handleClick(): void {\n if (!this.voiceManager.isActive()) {\n // First click — start voice\n this.voiceManager.start().then(() => {\n this.updateState();\n this.onVoiceStarted?.();\n }).catch((err) => {\n console.warn('[Vizor Voice] Failed to start:', err);\n });\n } else {\n // Toggle mute\n this.voiceManager.toggleMute();\n this.updateState();\n }\n }\n}\n"],"names":["PEER_COLORS"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ChatPanel } from './chat-panel.js';
2
+ /**
3
+ * Chat toggle button with unread message badge.
4
+ * Placed in the controls bar right section.
5
+ */
6
+ export declare class ChatButton {
7
+ private container;
8
+ private badge;
9
+ private unreadCount;
10
+ private chatPanel;
11
+ constructor(chatPanel: ChatPanel);
12
+ /** Increment unread count and show badge */
13
+ incrementUnread(): void;
14
+ /** Reset unread count and hide badge */
15
+ resetUnread(): void;
16
+ /** Get the DOM element to insert into controls */
17
+ getElement(): HTMLDivElement;
18
+ /** Clean up */
19
+ dispose(): void;
20
+ private updateBadge;
21
+ }
22
+ //# sourceMappingURL=chat-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/chat-button.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAY;gBAEjB,SAAS,EAAE,SAAS;IA2BhC,4CAA4C;IAC5C,eAAe,IAAI,IAAI;IAKvB,wCAAwC;IACxC,WAAW,IAAI,IAAI;IAKnB,kDAAkD;IAClD,UAAU,IAAI,cAAc;IAI5B,eAAe;IACf,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,WAAW;CASpB"}
@@ -0,0 +1,46 @@
1
+ /** A single chat message displayed in the panel */
2
+ export interface ChatMessage {
3
+ userId: string;
4
+ displayName: string;
5
+ text: string;
6
+ timestamp: number;
7
+ isLocal: boolean;
8
+ }
9
+ /**
10
+ * Side panel overlay for collaborative chat.
11
+ * Slides in from the right with frosted glass styling.
12
+ */
13
+ export declare class ChatPanel {
14
+ private panel;
15
+ private messagesEl;
16
+ private inputEl;
17
+ private emptyEl;
18
+ private styleEl;
19
+ private isOpen;
20
+ private messages;
21
+ private colorMap;
22
+ private colorIndex;
23
+ private onSend;
24
+ private shadowRoot;
25
+ constructor(shadowRoot: ShadowRoot, onSend: (text: string) => void);
26
+ /** Add a chat message to the panel */
27
+ addMessage(msg: ChatMessage): void;
28
+ /** Toggle panel open/closed */
29
+ toggle(): void;
30
+ /** Open the panel */
31
+ open(): void;
32
+ /** Close the panel */
33
+ close(): void;
34
+ /** Whether the panel is currently visible */
35
+ isVisible(): boolean;
36
+ /** Get message count */
37
+ getMessageCount(): number;
38
+ /** Clean up */
39
+ dispose(): void;
40
+ private handleSend;
41
+ private renderMessage;
42
+ private scrollToBottom;
43
+ private getColorForUser;
44
+ private formatTime;
45
+ }
46
+ //# sourceMappingURL=chat-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-panel.d.ts","sourceRoot":"","sources":["../../src/collaborative/chat-panel.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AA6ID;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,UAAU,CAAa;gBAEnB,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;IA6DlE,sCAAsC;IACtC,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IASlC,+BAA+B;IAC/B,MAAM,IAAI,IAAI;IAQd,qBAAqB;IACrB,IAAI,IAAI,IAAI;IAMZ,sBAAsB;IACtB,KAAK,IAAI,IAAI;IAKb,6CAA6C;IAC7C,SAAS,IAAI,OAAO;IAIpB,wBAAwB;IACxB,eAAe,IAAI,MAAM;IAIzB,eAAe;IACf,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,UAAU;CAMnB"}
@@ -0,0 +1,73 @@
1
+ import type { PlayerState } from '../core/player-state.js';
2
+ import type { ClientMessage, CollabParticipant } from '@vizor-vr/shared';
3
+ export interface CollabClientOptions {
4
+ serverUrl: string;
5
+ roomCode: string;
6
+ role: 'host' | 'viewer';
7
+ userId: string;
8
+ displayName: string;
9
+ state: PlayerState;
10
+ /** The media element for play/pause/seek control */
11
+ mediaElement: {
12
+ play(): void | Promise<void>;
13
+ pause(): void;
14
+ seek(time: number): void;
15
+ currentTime: number;
16
+ };
17
+ /** Optional callback when participants change */
18
+ onParticipantsChange?: (users: CollabParticipant[]) => void;
19
+ /** Callback when a peer's gaze position is received */
20
+ onPeerGaze?: (userId: string, lat: number, lon: number) => void;
21
+ /** Callback when a user joins the room */
22
+ onUserJoined?: (user: CollabParticipant) => void;
23
+ /** Callback when a user leaves the room */
24
+ onUserLeft?: (userId: string) => void;
25
+ /** Callback when a chat message is received */
26
+ onChatMessage?: (userId: string, displayName: string, text: string, timestamp: number) => void;
27
+ /** Callback when a voice signal (SDP/ICE) is received from a peer */
28
+ onVoiceSignal?: (fromUserId: string, sdp?: string, candidate?: string) => void;
29
+ /** Room password (host sets, viewers must match) */
30
+ password?: string;
31
+ }
32
+ /**
33
+ * Browser-side WebSocket client for collaborative viewing.
34
+ *
35
+ * - Host: subscribes to local state changes → sends playback_state/seek to server
36
+ * - Viewer: receives sync messages → applies play/pause/seek locally
37
+ * - Auto-reconnects on unexpected close
38
+ */
39
+ export declare class CollaborativeClient {
40
+ private ws;
41
+ private options;
42
+ private unsubscribes;
43
+ private reconnectTimer;
44
+ private disposed;
45
+ private lastPlaybackSend;
46
+ private connected;
47
+ constructor(options: CollabClientOptions);
48
+ /** Connect to the collaborative server */
49
+ connect(): void;
50
+ /** Whether the client is currently connected */
51
+ isConnected(): boolean;
52
+ /** Gracefully disconnect and clean up */
53
+ dispose(): void;
54
+ private handleMessage;
55
+ private handleRoomState;
56
+ private handleSync;
57
+ private applySync;
58
+ /** Host: subscribe to local state changes and broadcast them */
59
+ private subscribeHostState;
60
+ /** Throttled playback state sender */
61
+ private sendPlaybackState;
62
+ /** Send a chat message */
63
+ sendChat(text: string): void;
64
+ /** Send a voice signal (SDP offer/answer or ICE candidate) to a specific peer */
65
+ sendVoiceSignal(targetUserId: string, sdp?: string, candidate?: string): void;
66
+ /** Send a message to the server */
67
+ send(msg: ClientMessage): void;
68
+ private scheduleReconnect;
69
+ /** Register a cleanup function to run on dispose */
70
+ addCleanup(fn: () => void): void;
71
+ private cleanupSubscriptions;
72
+ }
73
+ //# sourceMappingURL=collab-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collab-client.d.ts","sourceRoot":"","sources":["../../src/collaborative/collab-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAiB,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAWxF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,oDAAoD;IACpD,YAAY,EAAE;QACZ,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAC;IAC5D,uDAAuD;IACvD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,0CAA0C;IAC1C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,2CAA2C;IAC3C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,+CAA+C;IAC/C,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/F,qEAAqE;IACrE,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/E,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,mBAAmB;IAIxC,0CAA0C;IAC1C,OAAO,IAAI,IAAI;IAiDf,gDAAgD;IAChD,WAAW,IAAI,OAAO;IAItB,yCAAyC;IACzC,OAAO,IAAI,IAAI;IAwBf,OAAO,CAAC,aAAa;IAsCrB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,SAAS;IAmBjB,gEAAgE;IAChE,OAAO,CAAC,kBAAkB;IAsB1B,sCAAsC;IACtC,OAAO,CAAC,iBAAiB;IAazB,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI5B,iFAAiF;IACjF,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAI7E,mCAAmC;IACnC,IAAI,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAM9B,OAAO,CAAC,iBAAiB;IAQzB,oDAAoD;IACpD,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAIhC,OAAO,CAAC,oBAAoB;CAI7B"}
@@ -0,0 +1,29 @@
1
+ import type { Scene } from 'three';
2
+ /**
3
+ * Manages 3D sprite cursors for all remote peers.
4
+ * Each peer gets a colored dot on the sphere at their camera orientation.
5
+ * Positions are smoothly interpolated each frame via lerp.
6
+ */
7
+ export declare class GazeCursorManager {
8
+ private scene;
9
+ private cursors;
10
+ private colorIndex;
11
+ constructor(scene: Scene);
12
+ /** Add a cursor for a new peer */
13
+ addPeer(userId: string, displayName: string): void;
14
+ /** Remove a peer's cursor */
15
+ removePeer(userId: string): void;
16
+ /** Update the target gaze position for a peer */
17
+ updateGaze(userId: string, lat: number, lon: number): void;
18
+ /** Called each animation frame. Lerps all cursors toward their target positions. */
19
+ update(): void;
20
+ /** Get the number of tracked peers */
21
+ getPeerCount(): number;
22
+ /** Clean up all cursors */
23
+ dispose(): void;
24
+ /** Create a colored circle sprite for the cursor dot */
25
+ private createCursorSprite;
26
+ /** Create a text label sprite showing the peer's display name */
27
+ private createLabelSprite;
28
+ }
29
+ //# sourceMappingURL=gaze-cursor-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaze-cursor-manager.d.ts","sourceRoot":"","sources":["../../src/collaborative/gaze-cursor-manager.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AA8BnC;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,UAAU,CAAK;gBAEX,KAAK,EAAE,KAAK;IAIxB,kCAAkC;IAClC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAyBlD,6BAA6B;IAC7B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAahC,iDAAiD;IACjD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAO1D,oFAAoF;IACpF,MAAM,IAAI,IAAI;IAiBd,sCAAsC;IACtC,YAAY,IAAI,MAAM;IAItB,2BAA2B;IAC3B,OAAO,IAAI,IAAI;IAMf,wDAAwD;IACxD,OAAO,CAAC,kBAAkB;IAqC1B,iEAAiE;IACjE,OAAO,CAAC,iBAAiB;CAmC1B"}
@@ -0,0 +1,29 @@
1
+ import type { ClientMessage } from '@vizor-vr/shared';
2
+ /** Orientation provider callback (matches CameraController.getOrientation) */
3
+ export interface OrientationProvider {
4
+ getOrientation(): {
5
+ lat: number;
6
+ lon: number;
7
+ fov: number;
8
+ };
9
+ }
10
+ /**
11
+ * Samples local camera orientation at ~5Hz and sends throttled `gaze` messages.
12
+ * Only sends when orientation changes by more than COLLAB_GAZE_THRESHOLD degrees.
13
+ */
14
+ export declare class GazeSender {
15
+ private timer;
16
+ private lastSentLat;
17
+ private lastSentLon;
18
+ private orientationProvider;
19
+ private sendFn;
20
+ constructor(orientationProvider: OrientationProvider, sendFn: (msg: ClientMessage) => void);
21
+ /** Start sampling and sending gaze messages */
22
+ start(): void;
23
+ /** Stop sampling */
24
+ stop(): void;
25
+ /** Clean up */
26
+ dispose(): void;
27
+ private sample;
28
+ }
29
+ //# sourceMappingURL=gaze-sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gaze-sender.d.ts","sourceRoot":"","sources":["../../src/collaborative/gaze-sender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,cAAc,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,MAAM,CAA+B;gBAEjC,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI;IAK1F,+CAA+C;IAC/C,KAAK,IAAI,IAAI;IAKb,oBAAoB;IACpB,IAAI,IAAI,IAAI;IAOZ,eAAe;IACf,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,MAAM;CAWf"}
@@ -0,0 +1,25 @@
1
+ import type { VoiceManager } from './voice-manager.js';
2
+ /**
3
+ * Microphone toggle button for collaborative voice chat.
4
+ *
5
+ * First click starts voice (requests microphone).
6
+ * Subsequent clicks toggle mute.
7
+ * Shows mic icon (active) or mic-muted icon (muted).
8
+ */
9
+ export declare class VoiceButton {
10
+ private container;
11
+ private btn;
12
+ private voiceManager;
13
+ private onVoiceStarted?;
14
+ constructor(voiceManager: VoiceManager, onVoiceStarted?: () => void);
15
+ /** Get the DOM element to insert into controls */
16
+ getElement(): HTMLDivElement;
17
+ /** Update button icon based on current voice state */
18
+ updateState(): void;
19
+ /** Handle toggle via keyboard shortcut */
20
+ toggle(): void;
21
+ /** Clean up */
22
+ dispose(): void;
23
+ private handleClick;
24
+ }
25
+ //# sourceMappingURL=voice-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-button.d.ts","sourceRoot":"","sources":["../../src/collaborative/voice-button.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAC,CAAa;gBAGlC,YAAY,EAAE,YAAY,EAC1B,cAAc,CAAC,EAAE,MAAM,IAAI;IAsB7B,kDAAkD;IAClD,UAAU,IAAI,cAAc;IAI5B,sDAAsD;IACtD,WAAW,IAAI,IAAI;IAqBnB,0CAA0C;IAC1C,MAAM,IAAI,IAAI;IAId,eAAe;IACf,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;CAepB"}
@@ -0,0 +1,45 @@
1
+ /** State of the voice manager */
2
+ export type VoiceState = 'inactive' | 'active' | 'muted';
3
+ /**
4
+ * WebRTC mesh voice manager.
5
+ *
6
+ * Handles microphone capture, peer-to-peer audio connections,
7
+ * and SDP/ICE signaling relay. Mesh topology — each participant
8
+ * connects directly to every other participant (suitable for <8 peers).
9
+ */
10
+ export declare class VoiceManager {
11
+ private localStream;
12
+ private peers;
13
+ private state;
14
+ private sendSignal;
15
+ constructor(sendSignal: (targetUserId: string, sdp?: string, candidate?: string) => void);
16
+ /** Get current voice state */
17
+ getState(): VoiceState;
18
+ /** Start voice — request microphone and begin connections */
19
+ start(): Promise<void>;
20
+ /** Toggle mute on/off */
21
+ toggleMute(): void;
22
+ /** Whether voice is currently active (active or muted) */
23
+ isActive(): boolean;
24
+ /** Whether mic is currently muted */
25
+ isMuted(): boolean;
26
+ /**
27
+ * Initiate a WebRTC connection to a peer (caller side).
28
+ * Creates an offer and sends it via signaling.
29
+ */
30
+ connectToPeer(peerId: string): Promise<void>;
31
+ /**
32
+ * Handle an incoming voice signal (SDP offer/answer or ICE candidate).
33
+ */
34
+ handleSignal(fromUserId: string, sdp?: string, candidate?: string): Promise<void>;
35
+ /** Remove a peer connection (when peer leaves) */
36
+ removePeer(peerId: string): void;
37
+ /** Stop voice — release microphone and close all connections */
38
+ stop(): void;
39
+ /** Get the number of active peer connections */
40
+ getPeerCount(): number;
41
+ /** Clean up everything */
42
+ dispose(): void;
43
+ private createPeerConnection;
44
+ }
45
+ //# sourceMappingURL=voice-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-manager.d.ts","sourceRoot":"","sources":["../../src/collaborative/voice-manager.ts"],"names":[],"mappings":"AAMA,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AAQzD;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,UAAU,CAAmE;gBAGnF,UAAU,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI;IAK9E,8BAA8B;IAC9B,QAAQ,IAAI,UAAU;IAItB,6DAA6D;IACvD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,yBAAyB;IACzB,UAAU,IAAI,IAAI;IAYlB,0DAA0D;IAC1D,QAAQ,IAAI,OAAO;IAInB,qCAAqC;IACrC,OAAO,IAAI,OAAO;IAIlB;;;OAGG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCvF,kDAAkD;IAClD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAUhC,gEAAgE;IAChE,IAAI,IAAI,IAAI;IAkBZ,gDAAgD;IAChD,YAAY,IAAI,MAAM;IAItB,0BAA0B;IAC1B,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,oBAAoB;CAkC7B"}
@@ -0,0 +1,2 @@
1
+ export { FORMAT_REGISTRY, getFormatMeta, parseFormat } from '@vizor-vr/shared';
2
+ //# sourceMappingURL=format-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-registry.d.ts","sourceRoot":"","sources":["../../src/config/format-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { PlayerConfig } from '@vizor-vr/shared';
2
+ /**
3
+ * Read all <meta name="vz:*"> tags from the document head
4
+ * and return partial config overrides.
5
+ */
6
+ export declare function readMetaConfig(): Partial<PlayerConfig>;
7
+ /**
8
+ * Resolve the full player config by merging:
9
+ * 1. Defaults
10
+ * 2. Meta tag overrides
11
+ * 3. Element attribute overrides
12
+ */
13
+ export declare function resolveConfig(elementAttrs: Partial<PlayerConfig>, metaOverrides?: Partial<PlayerConfig>): PlayerConfig;
14
+ //# sourceMappingURL=meta-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-config.d.ts","sourceRoot":"","sources":["../../src/config/meta-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAqCrD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CAsBtD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,EACnC,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACpC,YAAY,CAOd"}
@@ -0,0 +1,24 @@
1
+ import type { PlayerState } from '../core/player-state.js';
2
+ import type { CaptionRenderer } from '../captions/caption-renderer.js';
3
+ /**
4
+ * Closed-caption toggle button with language dropdown.
5
+ *
6
+ * UI pattern matches QualityMenu: a button that toggles a
7
+ * dropdown of options (Off + one per loaded track).
8
+ */
9
+ export declare class CcButton {
10
+ private container;
11
+ private dropdown;
12
+ private btn;
13
+ private captionRenderer;
14
+ private unsubscribes;
15
+ private isOpen;
16
+ constructor(state: PlayerState, captionRenderer: CaptionRenderer);
17
+ getElement(): HTMLDivElement;
18
+ /** Show or hide the CC button based on whether tracks are loaded */
19
+ updateVisibility(): void;
20
+ dispose(): void;
21
+ private updateButtonState;
22
+ private renderOptions;
23
+ }
24
+ //# sourceMappingURL=cc-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cc-button.d.ts","sourceRoot":"","sources":["../../src/controls/cc-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGvE;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe;IAuChE,UAAU,IAAI,cAAc;IAI5B,oEAAoE;IACpE,gBAAgB,IAAI,IAAI;IAKxB,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,aAAa;CAuCtB"}
@@ -0,0 +1,15 @@
1
+ import type { PlayerState } from '../core/player-state.js';
2
+ import type { VzRenderer } from '../renderer/renderer.js';
3
+ /**
4
+ * Compass indicator for 360 content.
5
+ * Rotates to show the current viewing direction.
6
+ * Click to reset to north (lon=0).
7
+ */
8
+ export declare class Compass {
9
+ private button;
10
+ private unsubscribes;
11
+ constructor(state: PlayerState, renderer: VzRenderer);
12
+ getElement(): HTMLButtonElement;
13
+ dispose(): void;
14
+ }
15
+ //# sourceMappingURL=compass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compass.d.ts","sourceRoot":"","sources":["../../src/controls/compass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU;IAoBpD,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,46 @@
1
+ import type { PlayerConfig, LicenseResult } from '@vizor-vr/shared';
2
+ import type { PlayerState } from '../core/player-state.js';
3
+ import type { VzEventEmitter } from '../core/event-emitter.js';
4
+ /**
5
+ * Controls overlay container rendered in shadow DOM.
6
+ * Vimeo-inspired layout: seek bar above button row, smooth slide-up.
7
+ *
8
+ * Layout:
9
+ * .vz-controls-wrapper (outer — animated show/hide)
10
+ * .vz-seek-row (progress bar — full width)
11
+ * .vz-controls (button bar — gradient background)
12
+ * .vz-controls-left (play, time)
13
+ * .vz-controls-center (spacer)
14
+ * .vz-controls-right (volume, quality, compass, vr, fullscreen)
15
+ */
16
+ export declare class ControlsOverlay {
17
+ private wrapper;
18
+ private seekRow;
19
+ private container;
20
+ private leftSection;
21
+ private centerSection;
22
+ private rightSection;
23
+ private loadingEl;
24
+ private hideTimer;
25
+ private state;
26
+ private cleanups;
27
+ constructor(shadowRoot: ShadowRoot, containerEl: HTMLElement, state: PlayerState, config: PlayerConfig, _events: VzEventEmitter);
28
+ /** Show controls and reset the auto-hide timer */
29
+ show(): void;
30
+ /** Hide controls */
31
+ hide(): void;
32
+ /** Add a control element to the overlay */
33
+ addControl(el: HTMLElement, section: 'left' | 'center' | 'right' | 'seek'): void;
34
+ /**
35
+ * Update theme colors after license validation.
36
+ *
37
+ * Color customisation is always respected — the `primary-color` attribute
38
+ * is the element's accent color regardless of license tier. Tier gating
39
+ * for color pickers lives in the dashboard embed builder UI, not here.
40
+ */
41
+ updateTheme(config: PlayerConfig, _license: LicenseResult): void;
42
+ /** Clean up all event listeners and timers */
43
+ dispose(): void;
44
+ private scheduleHide;
45
+ }
46
+ //# sourceMappingURL=controls-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controls-overlay.d.ts","sourceRoot":"","sources":["../../src/controls/controls-overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAK/D;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAyB;gBAGvC,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,cAAc;IAkGzB,kDAAkD;IAClD,IAAI,IAAI,IAAI;IAMZ,oBAAoB;IACpB,IAAI,IAAI,IAAI;IAMZ,2CAA2C;IAC3C,UAAU,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI;IAiBhF;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAWhE,8CAA8C;IAC9C,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,YAAY;CAIrB"}
@@ -0,0 +1,16 @@
1
+ import type { PlayerState } from '../core/player-state.js';
2
+ interface FullscreenTarget {
3
+ toggleFullscreen(): void;
4
+ }
5
+ /**
6
+ * Fullscreen toggle button.
7
+ */
8
+ export declare class FullscreenButton {
9
+ private button;
10
+ private unsubscribes;
11
+ constructor(state: PlayerState, mediaElement: FullscreenTarget);
12
+ getElement(): HTMLButtonElement;
13
+ dispose(): void;
14
+ }
15
+ export {};
16
+ //# sourceMappingURL=fullscreen-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fullscreen-button.d.ts","sourceRoot":"","sources":["../../src/controls/fullscreen-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,UAAU,gBAAgB;IACxB,gBAAgB,IAAI,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAyB;gBAEjC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB;IAiB9D,UAAU,IAAI,iBAAiB;IAI/B,OAAO,IAAI,IAAI;CAGhB"}