@thunderclap-engine/engine 0.0.0-stage → 1.1.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 (566) hide show
  1. package/CHANGELOG.md +390 -0
  2. package/LICENSE +21 -0
  3. package/README.md +333 -2
  4. package/dist/analytics/analytics.d.ts +80 -0
  5. package/dist/analytics/analytics.js +129 -0
  6. package/dist/analytics/index.d.ts +1 -0
  7. package/dist/analytics/index.js +1 -0
  8. package/dist/anim/aim.d.ts +43 -0
  9. package/dist/anim/aim.js +157 -0
  10. package/dist/anim/clip.d.ts +98 -0
  11. package/dist/anim/clip.js +282 -0
  12. package/dist/anim/compress.d.ts +65 -0
  13. package/dist/anim/compress.js +339 -0
  14. package/dist/anim/foot-ik.d.ts +74 -0
  15. package/dist/anim/foot-ik.js +241 -0
  16. package/dist/anim/graph.d.ts +153 -0
  17. package/dist/anim/graph.js +532 -0
  18. package/dist/anim/ik.d.ts +105 -0
  19. package/dist/anim/ik.js +435 -0
  20. package/dist/anim/index.d.ts +36 -0
  21. package/dist/anim/index.js +21 -0
  22. package/dist/anim/match.d.ts +66 -0
  23. package/dist/anim/match.js +153 -0
  24. package/dist/anim/mixer.d.ts +113 -0
  25. package/dist/anim/mixer.js +314 -0
  26. package/dist/anim/morph.d.ts +41 -0
  27. package/dist/anim/morph.js +94 -0
  28. package/dist/anim/pose.d.ts +74 -0
  29. package/dist/anim/pose.js +254 -0
  30. package/dist/anim/quat.d.ts +44 -0
  31. package/dist/anim/quat.js +187 -0
  32. package/dist/anim/retarget.d.ts +97 -0
  33. package/dist/anim/retarget.js +366 -0
  34. package/dist/anim/root-motion.d.ts +44 -0
  35. package/dist/anim/root-motion.js +224 -0
  36. package/dist/anim/skin-pose.d.ts +39 -0
  37. package/dist/anim/skin-pose.js +53 -0
  38. package/dist/anim/socket.d.ts +47 -0
  39. package/dist/anim/socket.js +84 -0
  40. package/dist/anim/spring-chain.d.ts +73 -0
  41. package/dist/anim/spring-chain.js +294 -0
  42. package/dist/assets/atlas.d.ts +90 -0
  43. package/dist/assets/atlas.js +212 -0
  44. package/dist/assets/baked.d.ts +33 -0
  45. package/dist/assets/baked.js +38 -0
  46. package/dist/assets/bundle.d.ts +88 -0
  47. package/dist/assets/bundle.js +464 -0
  48. package/dist/assets/cache.d.ts +56 -0
  49. package/dist/assets/cache.js +123 -0
  50. package/dist/assets/gltf-load.d.ts +252 -0
  51. package/dist/assets/gltf-load.js +661 -0
  52. package/dist/assets/gltf-skin.d.ts +36 -0
  53. package/dist/assets/gltf-skin.js +109 -0
  54. package/dist/assets/gltf.d.ts +706 -0
  55. package/dist/assets/gltf.js +1376 -0
  56. package/dist/assets/index.d.ts +20 -0
  57. package/dist/assets/index.js +10 -0
  58. package/dist/assets/ktx2.d.ts +71 -0
  59. package/dist/assets/ktx2.js +213 -0
  60. package/dist/assets/manifest.d.ts +79 -0
  61. package/dist/assets/manifest.js +7 -0
  62. package/dist/assets/meshopt.d.ts +23 -0
  63. package/dist/assets/meshopt.js +403 -0
  64. package/dist/audio/audio.d.ts +733 -0
  65. package/dist/audio/audio.js +2013 -0
  66. package/dist/audio/dsp.d.ts +61 -0
  67. package/dist/audio/dsp.js +159 -0
  68. package/dist/audio/duck.d.ts +44 -0
  69. package/dist/audio/duck.js +101 -0
  70. package/dist/audio/envelope.d.ts +53 -0
  71. package/dist/audio/envelope.js +106 -0
  72. package/dist/audio/index.d.ts +13 -0
  73. package/dist/audio/index.js +14 -0
  74. package/dist/audio/music.d.ts +113 -0
  75. package/dist/audio/music.js +548 -0
  76. package/dist/audio/occlusion.d.ts +55 -0
  77. package/dist/audio/occlusion.js +61 -0
  78. package/dist/audio/persist.d.ts +23 -0
  79. package/dist/audio/persist.js +27 -0
  80. package/dist/audio/recipes.d.ts +55 -0
  81. package/dist/audio/recipes.js +227 -0
  82. package/dist/audio/send.d.ts +41 -0
  83. package/dist/audio/send.js +118 -0
  84. package/dist/audio/sprites.d.ts +59 -0
  85. package/dist/audio/sprites.js +43 -0
  86. package/dist/audio/synth.d.ts +103 -0
  87. package/dist/audio/synth.js +197 -0
  88. package/dist/audio/variations.d.ts +25 -0
  89. package/dist/audio/variations.js +55 -0
  90. package/dist/audio/zones.d.ts +100 -0
  91. package/dist/audio/zones.js +167 -0
  92. package/dist/core/detached-surface.d.ts +44 -0
  93. package/dist/core/detached-surface.js +104 -0
  94. package/dist/core/events.d.ts +24 -0
  95. package/dist/core/events.js +43 -0
  96. package/dist/core/game.d.ts +409 -0
  97. package/dist/core/game.js +530 -0
  98. package/dist/core/hash.d.ts +24 -0
  99. package/dist/core/hash.js +49 -0
  100. package/dist/core/index.d.ts +17 -0
  101. package/dist/core/index.js +9 -0
  102. package/dist/core/loop.d.ts +113 -0
  103. package/dist/core/loop.js +185 -0
  104. package/dist/core/math.d.ts +58 -0
  105. package/dist/core/math.js +210 -0
  106. package/dist/core/noise.d.ts +40 -0
  107. package/dist/core/noise.js +247 -0
  108. package/dist/core/pool.d.ts +42 -0
  109. package/dist/core/pool.js +85 -0
  110. package/dist/core/random.d.ts +61 -0
  111. package/dist/core/random.js +199 -0
  112. package/dist/core/scene.d.ts +79 -0
  113. package/dist/core/scene.js +195 -0
  114. package/dist/core/timer.d.ts +66 -0
  115. package/dist/core/timer.js +286 -0
  116. package/dist/fx/billboard-wgsl.d.ts +29 -0
  117. package/dist/fx/billboard-wgsl.js +158 -0
  118. package/dist/fx/billboard.d.ts +249 -0
  119. package/dist/fx/billboard.js +702 -0
  120. package/dist/fx/debug-draw.d.ts +127 -0
  121. package/dist/fx/debug-draw.js +523 -0
  122. package/dist/fx/debug-wgsl.d.ts +7 -0
  123. package/dist/fx/debug-wgsl.js +32 -0
  124. package/dist/fx/decals-wgsl.d.ts +15 -0
  125. package/dist/fx/decals-wgsl.js +173 -0
  126. package/dist/fx/decals.d.ts +216 -0
  127. package/dist/fx/decals.js +607 -0
  128. package/dist/fx/effect.d.ts +129 -0
  129. package/dist/fx/effect.js +349 -0
  130. package/dist/fx/effects/hit-spark.json +48 -0
  131. package/dist/fx/effects/index.d.ts +8 -0
  132. package/dist/fx/effects/index.js +9 -0
  133. package/dist/fx/effects/magic-aura.json +47 -0
  134. package/dist/fx/effects/smoke-puff.json +34 -0
  135. package/dist/fx/emit-surface.d.ts +40 -0
  136. package/dist/fx/emit-surface.js +124 -0
  137. package/dist/fx/flicker.d.ts +30 -0
  138. package/dist/fx/flicker.js +42 -0
  139. package/dist/fx/index.d.ts +31 -0
  140. package/dist/fx/index.js +20 -0
  141. package/dist/fx/particles-wgsl.d.ts +57 -0
  142. package/dist/fx/particles-wgsl.js +828 -0
  143. package/dist/fx/particles.d.ts +566 -0
  144. package/dist/fx/particles.js +1533 -0
  145. package/dist/fx/random.d.ts +15 -0
  146. package/dist/fx/random.js +20 -0
  147. package/dist/fx/sky-wgsl.d.ts +23 -0
  148. package/dist/fx/sky-wgsl.js +127 -0
  149. package/dist/fx/sky.d.ts +96 -0
  150. package/dist/fx/sky.js +175 -0
  151. package/dist/fx/text-atlas.d.ts +143 -0
  152. package/dist/fx/text-atlas.js +327 -0
  153. package/dist/fx/trail-wgsl.d.ts +11 -0
  154. package/dist/fx/trail-wgsl.js +42 -0
  155. package/dist/fx/trail.d.ts +194 -0
  156. package/dist/fx/trail.js +555 -0
  157. package/dist/fx/water-wgsl.d.ts +34 -0
  158. package/dist/fx/water-wgsl.js +197 -0
  159. package/dist/fx/water.d.ts +176 -0
  160. package/dist/fx/water.js +371 -0
  161. package/dist/geom/collide/bvh.d.ts +151 -0
  162. package/dist/geom/collide/bvh.js +493 -0
  163. package/dist/geom/collide/debug.d.ts +14 -0
  164. package/dist/geom/collide/debug.js +74 -0
  165. package/dist/geom/collide/grid.d.ts +26 -0
  166. package/dist/geom/collide/grid.js +91 -0
  167. package/dist/geom/collide/index.d.ts +8 -0
  168. package/dist/geom/collide/index.js +8 -0
  169. package/dist/geom/collide/queries.d.ts +70 -0
  170. package/dist/geom/collide/queries.js +583 -0
  171. package/dist/geom/collide/serialize.d.ts +14 -0
  172. package/dist/geom/collide/serialize.js +145 -0
  173. package/dist/geom/collide/shapes.d.ts +161 -0
  174. package/dist/geom/collide/shapes.js +686 -0
  175. package/dist/geom/collide/slide.d.ts +66 -0
  176. package/dist/geom/collide/slide.js +375 -0
  177. package/dist/geom/collide/tile-slide.d.ts +88 -0
  178. package/dist/geom/collide/tile-slide.js +255 -0
  179. package/dist/geom/geometry.d.ts +95 -0
  180. package/dist/geom/geometry.js +322 -0
  181. package/dist/geom/heightfield.d.ts +72 -0
  182. package/dist/geom/heightfield.js +295 -0
  183. package/dist/geom/hull.d.ts +27 -0
  184. package/dist/geom/hull.js +279 -0
  185. package/dist/geom/index.d.ts +35 -0
  186. package/dist/geom/index.js +23 -0
  187. package/dist/geom/iso.d.ts +74 -0
  188. package/dist/geom/iso.js +89 -0
  189. package/dist/geom/lod.d.ts +29 -0
  190. package/dist/geom/lod.js +27 -0
  191. package/dist/geom/ops.d.ts +47 -0
  192. package/dist/geom/ops.js +285 -0
  193. package/dist/geom/primitives.d.ts +97 -0
  194. package/dist/geom/primitives.js +359 -0
  195. package/dist/geom/shapes.d.ts +43 -0
  196. package/dist/geom/shapes.js +88 -0
  197. package/dist/geom/simplify.d.ts +38 -0
  198. package/dist/geom/simplify.js +519 -0
  199. package/dist/geom/split.d.ts +37 -0
  200. package/dist/geom/split.js +413 -0
  201. package/dist/geom/sweep.d.ts +83 -0
  202. package/dist/geom/sweep.js +534 -0
  203. package/dist/geom/tangents.d.ts +16 -0
  204. package/dist/geom/tangents.js +124 -0
  205. package/dist/geom/triangulate.d.ts +19 -0
  206. package/dist/geom/triangulate.js +147 -0
  207. package/dist/host/default.d.ts +10 -0
  208. package/dist/host/default.js +10 -0
  209. package/dist/host/index.d.ts +4 -0
  210. package/dist/host/index.js +3 -0
  211. package/dist/host/types.d.ts +144 -0
  212. package/dist/host/types.js +1 -0
  213. package/dist/host/web-links.d.ts +38 -0
  214. package/dist/host/web-links.js +110 -0
  215. package/dist/host/web.d.ts +30 -0
  216. package/dist/host/web.js +216 -0
  217. package/dist/host/xr.d.ts +24 -0
  218. package/dist/host/xr.js +59 -0
  219. package/dist/i18n/i18n.d.ts +59 -0
  220. package/dist/i18n/i18n.js +241 -0
  221. package/dist/i18n/index.d.ts +3 -0
  222. package/dist/i18n/index.js +3 -0
  223. package/dist/i18n/message.d.ts +72 -0
  224. package/dist/i18n/message.js +369 -0
  225. package/dist/i18n/negotiate.d.ts +17 -0
  226. package/dist/i18n/negotiate.js +58 -0
  227. package/dist/index.d.ts +7 -0
  228. package/dist/index.js +1 -0
  229. package/dist/input/bindings.d.ts +31 -0
  230. package/dist/input/bindings.js +141 -0
  231. package/dist/input/clock.d.ts +44 -0
  232. package/dist/input/clock.js +49 -0
  233. package/dist/input/follow.d.ts +133 -0
  234. package/dist/input/follow.js +218 -0
  235. package/dist/input/gestures.d.ts +281 -0
  236. package/dist/input/gestures.js +662 -0
  237. package/dist/input/glyphs.d.ts +35 -0
  238. package/dist/input/glyphs.js +216 -0
  239. package/dist/input/gyro.d.ts +85 -0
  240. package/dist/input/gyro.js +140 -0
  241. package/dist/input/index.d.ts +19 -0
  242. package/dist/input/index.js +16 -0
  243. package/dist/input/input.d.ts +543 -0
  244. package/dist/input/input.js +1492 -0
  245. package/dist/input/look.d.ts +327 -0
  246. package/dist/input/look.js +681 -0
  247. package/dist/input/magnify.d.ts +177 -0
  248. package/dist/input/magnify.js +131 -0
  249. package/dist/input/pointer-dispatch.d.ts +138 -0
  250. package/dist/input/pointer-dispatch.js +180 -0
  251. package/dist/input/pointer-router.d.ts +204 -0
  252. package/dist/input/pointer-router.js +533 -0
  253. package/dist/input/pointer-sources.d.ts +164 -0
  254. package/dist/input/pointer-sources.js +306 -0
  255. package/dist/input/rays.d.ts +138 -0
  256. package/dist/input/rays.js +615 -0
  257. package/dist/input/record.d.ts +209 -0
  258. package/dist/input/record.js +601 -0
  259. package/dist/input/touch-zones.d.ts +147 -0
  260. package/dist/input/touch-zones.js +300 -0
  261. package/dist/input/types.d.ts +158 -0
  262. package/dist/input/types.js +1 -0
  263. package/dist/input/xr-source.d.ts +53 -0
  264. package/dist/input/xr-source.js +164 -0
  265. package/dist/nav/astar.d.ts +45 -0
  266. package/dist/nav/astar.js +182 -0
  267. package/dist/nav/corridor.d.ts +40 -0
  268. package/dist/nav/corridor.js +95 -0
  269. package/dist/nav/crowd.d.ts +94 -0
  270. package/dist/nav/crowd.js +624 -0
  271. package/dist/nav/flow.d.ts +61 -0
  272. package/dist/nav/flow.js +193 -0
  273. package/dist/nav/grid.d.ts +108 -0
  274. package/dist/nav/grid.js +210 -0
  275. package/dist/nav/heap.d.ts +22 -0
  276. package/dist/nav/heap.js +92 -0
  277. package/dist/nav/index.d.ts +37 -0
  278. package/dist/nav/index.js +19 -0
  279. package/dist/nav/mesh/areas.d.ts +44 -0
  280. package/dist/nav/mesh/areas.js +98 -0
  281. package/dist/nav/mesh/bake-options.d.ts +33 -0
  282. package/dist/nav/mesh/bake-options.js +76 -0
  283. package/dist/nav/mesh/contour.d.ts +22 -0
  284. package/dist/nav/mesh/contour.js +323 -0
  285. package/dist/nav/mesh/flow3.d.ts +35 -0
  286. package/dist/nav/mesh/flow3.js +229 -0
  287. package/dist/nav/mesh/links.d.ts +38 -0
  288. package/dist/nav/mesh/links.js +72 -0
  289. package/dist/nav/mesh/mesh-path.d.ts +152 -0
  290. package/dist/nav/mesh/mesh-path.js +643 -0
  291. package/dist/nav/mesh/mesh-reach.d.ts +78 -0
  292. package/dist/nav/mesh/mesh-reach.js +450 -0
  293. package/dist/nav/mesh/navmesh.d.ts +117 -0
  294. package/dist/nav/mesh/navmesh.js +647 -0
  295. package/dist/nav/mesh/polymesh.d.ts +24 -0
  296. package/dist/nav/mesh/polymesh.js +384 -0
  297. package/dist/nav/mesh/regions.d.ts +12 -0
  298. package/dist/nav/mesh/regions.js +367 -0
  299. package/dist/nav/mesh/serialize.d.ts +13 -0
  300. package/dist/nav/mesh/serialize.js +197 -0
  301. package/dist/nav/mesh/voxelize.d.ts +111 -0
  302. package/dist/nav/mesh/voxelize.js +552 -0
  303. package/dist/nav/obstacles.d.ts +75 -0
  304. package/dist/nav/obstacles.js +294 -0
  305. package/dist/nav/path.d.ts +59 -0
  306. package/dist/nav/path.js +177 -0
  307. package/dist/nav/query-queue.d.ts +46 -0
  308. package/dist/nav/query-queue.js +308 -0
  309. package/dist/nav/reach.d.ts +53 -0
  310. package/dist/nav/reach.js +148 -0
  311. package/dist/nav/steer.d.ts +36 -0
  312. package/dist/nav/steer.js +78 -0
  313. package/dist/platform/boot.d.ts +28 -0
  314. package/dist/platform/boot.js +43 -0
  315. package/dist/platform/device-mode.d.ts +40 -0
  316. package/dist/platform/device-mode.js +104 -0
  317. package/dist/platform/device.d.ts +31 -0
  318. package/dist/platform/device.js +91 -0
  319. package/dist/platform/environment.d.ts +42 -0
  320. package/dist/platform/environment.js +82 -0
  321. package/dist/platform/gpu.d.ts +40 -0
  322. package/dist/platform/gpu.js +57 -0
  323. package/dist/platform/index.d.ts +18 -0
  324. package/dist/platform/index.js +10 -0
  325. package/dist/platform/letterbox.d.ts +43 -0
  326. package/dist/platform/letterbox.js +57 -0
  327. package/dist/platform/links.d.ts +20 -0
  328. package/dist/platform/links.js +43 -0
  329. package/dist/platform/screens.d.ts +36 -0
  330. package/dist/platform/screens.js +138 -0
  331. package/dist/platform/surface.d.ts +72 -0
  332. package/dist/platform/surface.js +157 -0
  333. package/dist/platform/xr-fake.d.ts +168 -0
  334. package/dist/platform/xr-fake.js +434 -0
  335. package/dist/platform/xr-surface.d.ts +120 -0
  336. package/dist/platform/xr-surface.js +214 -0
  337. package/dist/platform/xr-types.d.ts +262 -0
  338. package/dist/post/ao.d.ts +12 -0
  339. package/dist/post/ao.js +136 -0
  340. package/dist/post/blend.d.ts +27 -0
  341. package/dist/post/blend.js +129 -0
  342. package/dist/post/depth-pass.d.ts +43 -0
  343. package/dist/post/depth-pass.js +118 -0
  344. package/dist/post/dof.d.ts +1 -0
  345. package/dist/post/dof.js +66 -0
  346. package/dist/post/exposure.d.ts +80 -0
  347. package/dist/post/exposure.js +322 -0
  348. package/dist/post/index.d.ts +12 -0
  349. package/dist/post/index.js +11 -0
  350. package/dist/post/lens-dirt.d.ts +13 -0
  351. package/dist/post/lens-dirt.js +91 -0
  352. package/dist/post/lut.d.ts +19 -0
  353. package/dist/post/lut.js +50 -0
  354. package/dist/post/motion-blur.d.ts +9 -0
  355. package/dist/post/motion-blur.js +78 -0
  356. package/dist/post/post-stack.d.ts +302 -0
  357. package/dist/post/post-stack.js +1137 -0
  358. package/dist/post/settings.d.ts +485 -0
  359. package/dist/post/settings.js +416 -0
  360. package/dist/post/shaders.d.ts +25 -0
  361. package/dist/post/shaders.js +410 -0
  362. package/dist/post/ssr.d.ts +16 -0
  363. package/dist/post/ssr.js +155 -0
  364. package/dist/post/taa.d.ts +74 -0
  365. package/dist/post/taa.js +235 -0
  366. package/dist/post/white-balance.d.ts +25 -0
  367. package/dist/post/white-balance.js +98 -0
  368. package/dist/render/bindings.d.ts +98 -0
  369. package/dist/render/bindings.js +281 -0
  370. package/dist/render/blend.d.ts +13 -0
  371. package/dist/render/blend.js +26 -0
  372. package/dist/render/camera-2d.d.ts +72 -0
  373. package/dist/render/camera-2d.js +92 -0
  374. package/dist/render/camera.d.ts +302 -0
  375. package/dist/render/camera.js +671 -0
  376. package/dist/render/color.d.ts +16 -0
  377. package/dist/render/color.js +41 -0
  378. package/dist/render/compressed.d.ts +104 -0
  379. package/dist/render/compressed.js +248 -0
  380. package/dist/render/diagnostics.d.ts +15 -0
  381. package/dist/render/diagnostics.js +43 -0
  382. package/dist/render/dynamic-resolution.d.ts +70 -0
  383. package/dist/render/dynamic-resolution.js +126 -0
  384. package/dist/render/fake-gpu.d.ts +204 -0
  385. package/dist/render/fake-gpu.js +426 -0
  386. package/dist/render/flipbook.d.ts +56 -0
  387. package/dist/render/flipbook.js +87 -0
  388. package/dist/render/frame.d.ts +278 -0
  389. package/dist/render/frame.js +174 -0
  390. package/dist/render/fullscreen.d.ts +54 -0
  391. package/dist/render/fullscreen.js +91 -0
  392. package/dist/render/gpu-timer.d.ts +73 -0
  393. package/dist/render/gpu-timer.js +186 -0
  394. package/dist/render/index.d.ts +53 -0
  395. package/dist/render/index.js +29 -0
  396. package/dist/render/instance-list.d.ts +185 -0
  397. package/dist/render/instance-list.js +547 -0
  398. package/dist/render/lights.d.ts +181 -0
  399. package/dist/render/lights.js +233 -0
  400. package/dist/render/lod.d.ts +54 -0
  401. package/dist/render/lod.js +52 -0
  402. package/dist/render/material.d.ts +165 -0
  403. package/dist/render/material.js +292 -0
  404. package/dist/render/mesh.d.ts +284 -0
  405. package/dist/render/mesh.js +472 -0
  406. package/dist/render/mipmap.d.ts +16 -0
  407. package/dist/render/mipmap.js +121 -0
  408. package/dist/render/parallax.d.ts +50 -0
  409. package/dist/render/parallax.js +47 -0
  410. package/dist/render/pbr-wgsl.d.ts +31 -0
  411. package/dist/render/pbr-wgsl.js +119 -0
  412. package/dist/render/ping-pong.d.ts +42 -0
  413. package/dist/render/ping-pong.js +74 -0
  414. package/dist/render/renderer.d.ts +741 -0
  415. package/dist/render/renderer.js +2486 -0
  416. package/dist/render/scene-pipelines.d.ts +44 -0
  417. package/dist/render/scene-pipelines.js +92 -0
  418. package/dist/render/scene-target.d.ts +170 -0
  419. package/dist/render/scene-target.js +450 -0
  420. package/dist/render/shadow.d.ts +74 -0
  421. package/dist/render/shadow.js +208 -0
  422. package/dist/render/skin.d.ts +112 -0
  423. package/dist/render/skin.js +240 -0
  424. package/dist/render/snapshot.d.ts +36 -0
  425. package/dist/render/snapshot.js +34 -0
  426. package/dist/render/standard.d.ts +162 -0
  427. package/dist/render/standard.js +263 -0
  428. package/dist/render/texture.d.ts +142 -0
  429. package/dist/render/texture.js +228 -0
  430. package/dist/render/tile-layer.d.ts +110 -0
  431. package/dist/render/tile-layer.js +304 -0
  432. package/dist/render/transform.d.ts +115 -0
  433. package/dist/render/transform.js +318 -0
  434. package/dist/render/wgsl.d.ts +131 -0
  435. package/dist/render/wgsl.js +528 -0
  436. package/dist/save/codec.d.ts +49 -0
  437. package/dist/save/codec.js +169 -0
  438. package/dist/save/index.d.ts +8 -0
  439. package/dist/save/index.js +8 -0
  440. package/dist/save/journal.d.ts +24 -0
  441. package/dist/save/journal.js +102 -0
  442. package/dist/save/migrate.d.ts +15 -0
  443. package/dist/save/migrate.js +37 -0
  444. package/dist/save/schema.d.ts +72 -0
  445. package/dist/save/schema.js +154 -0
  446. package/dist/save/settings.d.ts +28 -0
  447. package/dist/save/settings.js +59 -0
  448. package/dist/save/slots.d.ts +56 -0
  449. package/dist/save/slots.js +200 -0
  450. package/dist/save/storage.d.ts +35 -0
  451. package/dist/save/storage.js +62 -0
  452. package/dist/save/store.d.ts +114 -0
  453. package/dist/save/store.js +269 -0
  454. package/dist/testing/fake-host.d.ts +103 -0
  455. package/dist/testing/fake-host.js +163 -0
  456. package/dist/testing/fixed-clock.d.ts +25 -0
  457. package/dist/testing/fixed-clock.js +30 -0
  458. package/dist/testing/index.d.ts +4 -0
  459. package/dist/testing/index.js +5 -0
  460. package/dist/testing/test-game.d.ts +76 -0
  461. package/dist/testing/test-game.js +92 -0
  462. package/dist/tween/ease.d.ts +77 -0
  463. package/dist/tween/ease.js +192 -0
  464. package/dist/tween/index.d.ts +8 -0
  465. package/dist/tween/index.js +7 -0
  466. package/dist/tween/timeline.d.ts +78 -0
  467. package/dist/tween/timeline.js +269 -0
  468. package/dist/tween/tween.d.ts +168 -0
  469. package/dist/tween/tween.js +320 -0
  470. package/dist/ui/anchor.d.ts +206 -0
  471. package/dist/ui/anchor.js +307 -0
  472. package/dist/ui/caption.d.ts +122 -0
  473. package/dist/ui/caption.js +286 -0
  474. package/dist/ui/cursor.d.ts +105 -0
  475. package/dist/ui/cursor.js +261 -0
  476. package/dist/ui/dom.d.ts +30 -0
  477. package/dist/ui/dom.js +92 -0
  478. package/dist/ui/floats.d.ts +86 -0
  479. package/dist/ui/floats.js +260 -0
  480. package/dist/ui/hud.d.ts +198 -0
  481. package/dist/ui/hud.js +431 -0
  482. package/dist/ui/index.d.ts +37 -0
  483. package/dist/ui/index.js +34 -0
  484. package/dist/ui/inventory-card.d.ts +52 -0
  485. package/dist/ui/inventory-card.js +173 -0
  486. package/dist/ui/inventory-context.d.ts +29 -0
  487. package/dist/ui/inventory-context.js +125 -0
  488. package/dist/ui/inventory-drag.d.ts +63 -0
  489. package/dist/ui/inventory-drag.js +394 -0
  490. package/dist/ui/inventory-grid.d.ts +66 -0
  491. package/dist/ui/inventory-grid.js +625 -0
  492. package/dist/ui/inventory-radial.d.ts +39 -0
  493. package/dist/ui/inventory-radial.js +168 -0
  494. package/dist/ui/inventory.d.ts +128 -0
  495. package/dist/ui/inventory.js +154 -0
  496. package/dist/ui/layout.d.ts +356 -0
  497. package/dist/ui/layout.js +856 -0
  498. package/dist/ui/link.d.ts +64 -0
  499. package/dist/ui/link.js +155 -0
  500. package/dist/ui/loading.d.ts +40 -0
  501. package/dist/ui/loading.js +157 -0
  502. package/dist/ui/loupe.d.ts +74 -0
  503. package/dist/ui/loupe.js +164 -0
  504. package/dist/ui/menu-nav.d.ts +33 -0
  505. package/dist/ui/menu-nav.js +28 -0
  506. package/dist/ui/minimap-canvas.d.ts +145 -0
  507. package/dist/ui/minimap-canvas.js +460 -0
  508. package/dist/ui/notify.d.ts +40 -0
  509. package/dist/ui/notify.js +141 -0
  510. package/dist/ui/orb.d.ts +53 -0
  511. package/dist/ui/orb.js +304 -0
  512. package/dist/ui/overlay.d.ts +213 -0
  513. package/dist/ui/overlay.js +394 -0
  514. package/dist/ui/padnav.d.ts +53 -0
  515. package/dist/ui/padnav.js +146 -0
  516. package/dist/ui/perf.d.ts +130 -0
  517. package/dist/ui/perf.js +329 -0
  518. package/dist/ui/rotate-card.d.ts +54 -0
  519. package/dist/ui/rotate-card.js +97 -0
  520. package/dist/ui/stack.d.ts +128 -0
  521. package/dist/ui/stack.js +312 -0
  522. package/dist/ui/styles.d.ts +13 -0
  523. package/dist/ui/styles.js +200 -0
  524. package/dist/ui/text-scale.d.ts +67 -0
  525. package/dist/ui/text-scale.js +102 -0
  526. package/dist/ui/theme.d.ts +70 -0
  527. package/dist/ui/theme.js +98 -0
  528. package/dist/ui/toast.d.ts +23 -0
  529. package/dist/ui/toast.js +46 -0
  530. package/dist/ui/tooltip.d.ts +89 -0
  531. package/dist/ui/tooltip.js +333 -0
  532. package/dist/ui/widgets-2.d.ts +134 -0
  533. package/dist/ui/widgets-2.js +399 -0
  534. package/dist/ui/widgets-3.d.ts +91 -0
  535. package/dist/ui/widgets-3.js +212 -0
  536. package/dist/ui/widgets.d.ts +34 -0
  537. package/dist/ui/widgets.js +50 -0
  538. package/dist/ui/world-panel/index.d.ts +5 -0
  539. package/dist/ui/world-panel/index.js +5 -0
  540. package/dist/ui/world-panel/layout.d.ts +38 -0
  541. package/dist/ui/world-panel/layout.js +68 -0
  542. package/dist/ui/world-panel/paint.d.ts +96 -0
  543. package/dist/ui/world-panel/paint.js +136 -0
  544. package/dist/ui/world-panel/panel.d.ts +235 -0
  545. package/dist/ui/world-panel/panel.js +762 -0
  546. package/dist/ui/world-panel/wgsl.d.ts +10 -0
  547. package/dist/ui/world-panel/wgsl.js +52 -0
  548. package/dist/ui/world-panel/widgets.d.ts +207 -0
  549. package/dist/ui/world-panel/widgets.js +569 -0
  550. package/dist/voxel/chunks.d.ts +77 -0
  551. package/dist/voxel/chunks.js +149 -0
  552. package/dist/voxel/grid.d.ts +84 -0
  553. package/dist/voxel/grid.js +223 -0
  554. package/dist/voxel/index.d.ts +22 -0
  555. package/dist/voxel/index.js +7 -0
  556. package/dist/voxel/mesher-worker.d.ts +14 -0
  557. package/dist/voxel/mesher-worker.js +47 -0
  558. package/dist/voxel/mesher.d.ts +73 -0
  559. package/dist/voxel/mesher.js +306 -0
  560. package/dist/voxel/ray.d.ts +32 -0
  561. package/dist/voxel/ray.js +73 -0
  562. package/dist/voxel/wgsl.d.ts +16 -0
  563. package/dist/voxel/wgsl.js +28 -0
  564. package/dist/voxel/worker-client.d.ts +79 -0
  565. package/dist/voxel/worker-client.js +122 -0
  566. package/package.json +177 -3
@@ -0,0 +1,762 @@
1
+ import { createHit, createRay, rayAt, transformRayInto, } from '../../input/rays.js';
2
+ import { blendState } from '../../render/blend.js';
3
+ import { auxSuffix, ScenePipelineCache, sceneVariant } from '../../render/scene-pipelines.js';
4
+ import { Transform } from '../../render/transform.js';
5
+ import { createShaderModule } from '../../render/wgsl.js';
6
+ import { flowLayout, rectClampSnap, rectContains, rectUnion } from './layout.js';
7
+ import { makePanelCanvas, Painter, resolvePanelTheme, } from './paint.js';
8
+ import { WORLD_PANEL_UNIFORM_BYTES, WORLD_PANEL_UNIFORM_FLOATS, WORLD_PANEL_WGSL } from './wgsl.js';
9
+ const NO_OFFSET = [0, 0];
10
+ export class WorldPanel {
11
+ transform = new Transform();
12
+ /** Panel size in world units. */
13
+ width;
14
+ height;
15
+ resolution;
16
+ /** Canvas size in px. */
17
+ pxWidth;
18
+ pxHeight;
19
+ texture;
20
+ canvas;
21
+ painter;
22
+ theme;
23
+ stats = { repaints: 0, uploads: 0, bytes: 0 };
24
+ /** Resolves when `document.fonts` is ready (at once without it); the panel repaints then. */
25
+ fontLoaded;
26
+ /** Draw this in the scene: `frame.drawable(panel.drawable)` (it is the panel itself). */
27
+ drawable = this;
28
+ label;
29
+ depthTest;
30
+ /** Widgets in flow order. */
31
+ widgets = [];
32
+ /** The focused widget, or `null`. */
33
+ focused = null;
34
+ /** The widget under the last moved pointer, or `null`. */
35
+ hovered = null;
36
+ /** Draws issued by the last `draw` (0 or 1). */
37
+ draws = 0;
38
+ device;
39
+ background;
40
+ billboard;
41
+ headLocked;
42
+ dirtyRect = { x: 0, y: 0, w: 0, h: 0 };
43
+ layoutDirty = true;
44
+ needsUpload = false;
45
+ disposed = false;
46
+ /** The press: which widget holds it, by pointer id. */
47
+ presses = new Map();
48
+ pressCount = 0;
49
+ tracked = [];
50
+ nextTrackedId = 1;
51
+ uniform;
52
+ uniformData = new Float32Array(WORLD_PANEL_UNIFORM_FLOATS);
53
+ uniformSent = new Float32Array(WORLD_PANEL_UNIFORM_FLOATS);
54
+ uniformDirty = true;
55
+ group;
56
+ renderer;
57
+ pipelineDesc;
58
+ /**
59
+ * Pipelines per (depth format, target aux key) (ws/core-8): a panel drawn into
60
+ * `renderer.target` with aux attachments and into a plain target (an XR eye, a probe) in the
61
+ * same frame binds the variant whose colour targets match each pass.
62
+ */
63
+ pipelines = new ScenePipelineCache();
64
+ localRay = createRay();
65
+ hit = { x: 0, y: 0, widget: null, distance: 0 };
66
+ routerHit;
67
+ routerNormal = [0, 0, 0];
68
+ basis = new Float32Array(12);
69
+ detachFn = null;
70
+ constructor(renderer, opts) {
71
+ this.renderer = renderer;
72
+ this.device = renderer.device;
73
+ this.label = opts.label ?? 'world-panel';
74
+ this.width = opts.width;
75
+ this.height = opts.height;
76
+ this.resolution = opts.resolution ?? 256;
77
+ this.pxWidth = Math.max(1, Math.round(this.width * this.resolution));
78
+ this.pxHeight = Math.max(1, Math.round(this.height * this.resolution));
79
+ this.background = opts.background ?? 'panel';
80
+ this.billboard = opts.billboard === true;
81
+ this.headLocked = opts.headLocked
82
+ ? { distance: opts.headLocked.distance, offset: opts.headLocked.offset ?? NO_OFFSET }
83
+ : null;
84
+ this.depthTest = opts.depthTest ?? this.headLocked === null;
85
+ this.theme = resolvePanelTheme(opts.theme);
86
+ this.canvas = opts.canvas ?? makePanelCanvas(this.pxWidth, this.pxHeight);
87
+ const ctx = this.canvas.getContext('2d', { alpha: true });
88
+ if (!ctx)
89
+ throw new Error('world panel: no 2D context');
90
+ this.painter = new Painter(ctx, this.theme);
91
+ this.routerHit = createHit(this);
92
+ this.texture = renderer.createTexture({
93
+ width: this.pxWidth,
94
+ height: this.pxHeight,
95
+ format: 'rgba8unorm-srgb',
96
+ label: `${this.label}-texture`,
97
+ });
98
+ const device = this.device;
99
+ this.uniform = device.createBuffer({
100
+ label: `${this.label}-uniform`,
101
+ size: WORLD_PANEL_UNIFORM_BYTES,
102
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
103
+ });
104
+ const groupLayout = device.createBindGroupLayout({
105
+ label: `${this.label}-layout`,
106
+ entries: [
107
+ { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
108
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
109
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: {} },
110
+ ],
111
+ });
112
+ this.group = device.createBindGroup({
113
+ label: this.label,
114
+ layout: groupLayout,
115
+ entries: [
116
+ { binding: 0, resource: { buffer: this.uniform } },
117
+ { binding: 1, resource: renderer.samplers['linear-clamp'] },
118
+ { binding: 2, resource: this.texture.view },
119
+ ],
120
+ });
121
+ const mod = createShaderModule(device, WORLD_PANEL_WGSL, this.label);
122
+ this.pipelineDesc = {
123
+ label: this.label,
124
+ layout: device.createPipelineLayout({
125
+ bindGroupLayouts: [renderer.globalsLayout, groupLayout],
126
+ }),
127
+ vertex: { module: mod, entryPoint: 'vs' },
128
+ fragment: {
129
+ module: mod,
130
+ entryPoint: 'fs',
131
+ targets: renderer.sceneTargets(PREMULTIPLIED),
132
+ },
133
+ primitive: { topology: 'triangle-list', cullMode: 'none' },
134
+ };
135
+ this.uniformData[12] = this.width;
136
+ this.uniformData[13] = this.height;
137
+ this.uniformSent.fill(Number.NaN);
138
+ this.markAllDirty();
139
+ const fonts = typeof document !== 'undefined' ? document.fonts : undefined;
140
+ this.fontLoaded = fonts
141
+ ? fonts.ready.then(() => {
142
+ if (this.disposed)
143
+ return;
144
+ this.painter.clearMeasures();
145
+ this.relayout();
146
+ })
147
+ : Promise.resolve();
148
+ }
149
+ /** Whether a repaint or an upload is pending. */
150
+ get dirty() {
151
+ return this.layoutDirty || this.dirtyRect.w > 0 || this.needsUpload;
152
+ }
153
+ // ------------------------------------------------------------------------------------------
154
+ // Widgets
155
+ /** Append a widget to the flow (or place it at its `rect`). */
156
+ add(widget) {
157
+ if (widget.host === this)
158
+ return widget;
159
+ if (widget.host)
160
+ throw new Error('world panel: widget already on a panel');
161
+ widget.attach(this);
162
+ this.widgets.push(widget);
163
+ this.relayout();
164
+ return widget;
165
+ }
166
+ remove(widget) {
167
+ const i = this.widgets.indexOf(widget);
168
+ if (i < 0)
169
+ return;
170
+ this.widgets.splice(i, 1);
171
+ if (this.focused === widget)
172
+ this.focused = null;
173
+ if (this.hovered === widget)
174
+ this.hovered = null;
175
+ for (const [id, w] of this.presses)
176
+ if (w === widget)
177
+ this.presses.delete(id);
178
+ this.pressCount = this.presses.size;
179
+ widget.detach();
180
+ this.relayout();
181
+ }
182
+ /** @internal `WorldWidgetHost` */
183
+ invalidate(widget) {
184
+ if (this.layoutDirty)
185
+ return;
186
+ rectUnion(this.dirtyRect, this.ringRect(widget.layoutRect));
187
+ }
188
+ /** @internal `WorldWidgetHost`: re-run the flow and repaint everything next frame. */
189
+ relayout() {
190
+ this.layoutDirty = true;
191
+ this.markAllDirty();
192
+ }
193
+ markAllDirty() {
194
+ const d = this.dirtyRect;
195
+ d.x = 0;
196
+ d.y = 0;
197
+ d.w = this.pxWidth;
198
+ d.h = this.pxHeight;
199
+ }
200
+ ring = { x: 0, y: 0, w: 0, h: 0 };
201
+ /** `r` grown by the focus ring, so a focus change repaints the ring too. */
202
+ ringRect(r) {
203
+ const g = this.theme.focusRing + 1;
204
+ const o = this.ring;
205
+ o.x = r.x - g;
206
+ o.y = r.y - g;
207
+ o.w = r.w + g * 2;
208
+ o.h = r.h + g * 2;
209
+ return o;
210
+ }
211
+ layout() {
212
+ this.layoutDirty = false;
213
+ flowLayout(this.widgets, {
214
+ width: this.pxWidth,
215
+ padding: this.theme.space3,
216
+ gap: this.theme.space2,
217
+ });
218
+ }
219
+ /** The widget at panel px, or `null`. Explicit-rect widgets later in the list win. */
220
+ widgetAt(x, y) {
221
+ if (this.layoutDirty)
222
+ this.layout();
223
+ const ws = this.widgets;
224
+ for (let i = ws.length - 1; i >= 0; i--) {
225
+ const w = ws[i];
226
+ if (rectContains(w.layoutRect, x, y))
227
+ return w;
228
+ }
229
+ return null;
230
+ }
231
+ // ------------------------------------------------------------------------------------------
232
+ // Painting
233
+ /**
234
+ * Paint what is dirty now (the layout if it changed, then the dirty rect) and queue the upload.
235
+ * `prepare` calls this; call it yourself to paint ahead of the frame.
236
+ */
237
+ repaint() {
238
+ if (this.layoutDirty)
239
+ this.layout();
240
+ const d = this.dirtyRect;
241
+ if (d.w <= 0 || d.h <= 0)
242
+ return;
243
+ rectClampSnap(d, this.pxWidth, this.pxHeight);
244
+ if (d.w <= 0 || d.h <= 0) {
245
+ d.w = 0;
246
+ d.h = 0;
247
+ return;
248
+ }
249
+ const p = this.painter;
250
+ const ctx = p.ctx;
251
+ const t = this.theme;
252
+ ctx.save();
253
+ ctx.beginPath();
254
+ ctx.rect(d.x, d.y, d.w, d.h);
255
+ ctx.clip();
256
+ ctx.clearRect(d.x, d.y, d.w, d.h);
257
+ if (this.background === 'panel') {
258
+ const all = { x: 0, y: 0, w: this.pxWidth, h: this.pxHeight };
259
+ p.fillRoundRect(all, t.radiusM, t.tokens.colorSurface);
260
+ p.strokeRoundRect(all, t.radiusM, t.tokens.colorBorder, t.borderWidth);
261
+ }
262
+ for (const w of this.widgets) {
263
+ const r = w.layoutRect;
264
+ if (r.w <= 0 || r.h <= 0)
265
+ continue;
266
+ const g = t.focusRing + 1;
267
+ if (r.x - g >= d.x + d.w ||
268
+ r.x + r.w + g <= d.x ||
269
+ r.y - g >= d.y + d.h ||
270
+ r.y + r.h + g <= d.y)
271
+ continue;
272
+ ctx.save();
273
+ w.paint(p, r);
274
+ ctx.restore();
275
+ }
276
+ ctx.restore();
277
+ this.stats.repaints++;
278
+ rectUnion(this.uploadRect, d);
279
+ this.needsUpload = true;
280
+ d.w = 0;
281
+ d.h = 0;
282
+ }
283
+ uploadRect = { x: 0, y: 0, w: 0, h: 0 };
284
+ // ------------------------------------------------------------------------------------------
285
+ // Transform helpers
286
+ /**
287
+ * Per frame, before drawing: a head-locked panel moves in front of `camera`, a billboard turns
288
+ * to face it. A plain panel ignores it.
289
+ */
290
+ update(camera) {
291
+ const hl = this.headLocked;
292
+ if (!hl && !this.billboard)
293
+ return;
294
+ const v = camera.view;
295
+ const b = this.basis;
296
+ // The view's rows are the camera's right, up and back axes in world space.
297
+ const rx = v[0];
298
+ const ry = v[4];
299
+ const rz = v[8];
300
+ const ux = v[1];
301
+ const uy = v[5];
302
+ const uz = v[9];
303
+ const bx = v[2];
304
+ const by = v[6];
305
+ const bz = v[10];
306
+ let px;
307
+ let py;
308
+ let pz;
309
+ if (hl) {
310
+ const eye = camera.position;
311
+ const d = hl.distance;
312
+ const ox = hl.offset[0];
313
+ const oy = hl.offset[1];
314
+ px = eye[0] - bx * d + rx * ox + ux * oy;
315
+ py = eye[1] - by * d + ry * ox + uy * oy;
316
+ pz = eye[2] - bz * d + rz * ox + uz * oy;
317
+ }
318
+ else {
319
+ const p = this.transform.position;
320
+ px = p.x;
321
+ py = p.y;
322
+ pz = p.z;
323
+ }
324
+ const s = this.transform.scale;
325
+ b[0] = rx * s.x;
326
+ b[1] = ux * s.y;
327
+ b[2] = bx * s.z;
328
+ b[3] = px;
329
+ b[4] = ry * s.x;
330
+ b[5] = uy * s.y;
331
+ b[6] = by * s.z;
332
+ b[7] = py;
333
+ b[8] = rz * s.x;
334
+ b[9] = uz * s.y;
335
+ b[10] = bz * s.z;
336
+ b[11] = pz;
337
+ this.transform.setMatrix(b, 0);
338
+ }
339
+ // ------------------------------------------------------------------------------------------
340
+ // Hit testing and pointers
341
+ /**
342
+ * Where `ray` (world space) meets the panel's plane: px from the top-left (outside the quad
343
+ * allowed) and the distance along the ray, written to `this.hit`. False when the ray is
344
+ * parallel to the plane, points away from it, or the transform is singular.
345
+ */
346
+ project(ray) {
347
+ const local = this.localRay;
348
+ const scale = transformRayInto(ray, this.transform.world, local);
349
+ if (scale === 0)
350
+ return false;
351
+ const dz = local.dir[2];
352
+ if (Math.abs(dz) < 1e-9)
353
+ return false;
354
+ const t = -local.origin[2] / dz;
355
+ if (t < 0)
356
+ return false;
357
+ const lx = local.origin[0] + local.dir[0] * t;
358
+ const ly = local.origin[1] + local.dir[1] * t;
359
+ const h = this.hit;
360
+ h.x = (lx + this.width / 2) * this.resolution;
361
+ h.y = (this.height / 2 - ly) * this.resolution;
362
+ h.distance = t * scale;
363
+ return true;
364
+ }
365
+ /**
366
+ * Where `ray` (world space) meets the panel: px from the top-left, the widget there and the
367
+ * distance along the ray; `null` when it misses. The result object is reused.
368
+ */
369
+ hitTest(ray) {
370
+ if (!this.project(ray))
371
+ return null;
372
+ const h = this.hit;
373
+ if (h.x < 0 || h.x > this.pxWidth || h.y < 0 || h.y > this.pxHeight)
374
+ return null;
375
+ h.widget = this.widgetAt(h.x, h.y);
376
+ return h;
377
+ }
378
+ /** A `HitTester` for the pointer router whose hit's `target` is this panel. */
379
+ tester() {
380
+ return (ray) => {
381
+ const h = this.hitTest(ray);
382
+ if (!h)
383
+ return null;
384
+ const out = this.routerHit;
385
+ rayAt(ray, h.distance, out.point);
386
+ const m = this.transform.world;
387
+ // The panel's +z in world space, turned to face the ray.
388
+ let nx = m[2];
389
+ let ny = m[6];
390
+ let nz = m[10];
391
+ const len = Math.hypot(nx, ny, nz) || 1;
392
+ nx /= len;
393
+ ny /= len;
394
+ nz /= len;
395
+ const d = ray.dir;
396
+ if (nx * d[0] + ny * d[1] + nz * d[2] > 0) {
397
+ nx = -nx;
398
+ ny = -ny;
399
+ nz = -nz;
400
+ }
401
+ const n = out.normal ?? this.routerNormal;
402
+ out.normal = n;
403
+ n[0] = nx;
404
+ n[1] = ny;
405
+ n[2] = nz;
406
+ out.distance = h.distance;
407
+ return out;
408
+ };
409
+ }
410
+ setHover(widget) {
411
+ const prev = this.hovered;
412
+ if (prev === widget)
413
+ return;
414
+ if (prev) {
415
+ prev.hover = false;
416
+ this.invalidate(prev);
417
+ }
418
+ this.hovered = widget;
419
+ if (widget) {
420
+ widget.hover = true;
421
+ this.invalidate(widget);
422
+ }
423
+ }
424
+ /** A pointer is over panel px (`x`, `y`); `id` tells pointers apart (default 0). */
425
+ pointerMove(x, y, id = 0) {
426
+ const held = this.presses.get(id);
427
+ if (held) {
428
+ held.pointerMove(x, y, true);
429
+ return;
430
+ }
431
+ const w = this.widgetAt(x, y);
432
+ this.setHover(w && !w.disabled ? w : null);
433
+ w?.pointerMove(x, y, false);
434
+ }
435
+ /** The pointer left the panel (no widget is hovered; a held press stays until `pointerUp`). */
436
+ pointerLeave(id = 0) {
437
+ if (this.presses.has(id))
438
+ return;
439
+ this.setHover(null);
440
+ }
441
+ /** A press at panel px: the widget there takes it (and focus when focusable). */
442
+ pointerDown(x, y, id = 0) {
443
+ const w = this.widgetAt(x, y);
444
+ if (!w || w.disabled)
445
+ return;
446
+ if (w.focusable)
447
+ this.focus(w);
448
+ this.presses.set(id, w);
449
+ this.pressCount = this.presses.size;
450
+ if (!w.pressed) {
451
+ w.pressed = true;
452
+ this.invalidate(w);
453
+ }
454
+ w.pointerDown(x, y);
455
+ }
456
+ /**
457
+ * The press `id` ends at panel px (outside the quad allowed); a release over the pressed widget
458
+ * activates it. `NaN` coordinates cancel: the widget hears a release that is nowhere.
459
+ */
460
+ pointerUp(x, y, id = 0) {
461
+ const w = this.presses.get(id);
462
+ if (!w)
463
+ return;
464
+ this.presses.delete(id);
465
+ this.pressCount = this.presses.size;
466
+ let stillHeld = false;
467
+ for (const other of this.presses.values())
468
+ if (other === w)
469
+ stillHeld = true;
470
+ if (!stillHeld && w.pressed) {
471
+ w.pressed = false;
472
+ this.invalidate(w);
473
+ }
474
+ const inside = rectContains(w.layoutRect, x, y);
475
+ w.pointerUp(x, y, inside);
476
+ const under = this.widgetAt(x, y);
477
+ this.setHover(under && !under.disabled ? under : null);
478
+ }
479
+ /** Wheel over panel px: the widget there scrolls. Returns whether something used it. */
480
+ wheel(x, y, dy) {
481
+ const w = this.widgetAt(x, y);
482
+ return w ? w.wheel(dy) : false;
483
+ }
484
+ /**
485
+ * Drive the panel from the router's live pointers once per tick (after `input.update()`): a
486
+ * pointer whose nearest hit is this panel hovers, its `select` edge presses and releases; one
487
+ * that left releases outside. Pass `router.pointers` (or any array of `RoutedPointer`).
488
+ */
489
+ poll(pointers) {
490
+ const tracked = this.tracked;
491
+ for (const t of tracked)
492
+ t.seen = false;
493
+ for (const p of pointers) {
494
+ const onPanel = p.hit !== null && p.hit.target === this;
495
+ let t = this.trackedFor(p);
496
+ if (!onPanel && !t)
497
+ continue;
498
+ if (!t) {
499
+ t = {
500
+ id: this.nextTrackedId++,
501
+ key: p.key,
502
+ source: p.source,
503
+ select: false,
504
+ seen: true,
505
+ x: Number.NaN,
506
+ y: Number.NaN,
507
+ };
508
+ tracked.push(t);
509
+ }
510
+ t.seen = true;
511
+ const id = t.id;
512
+ if (onPanel) {
513
+ const h = this.hitTest(p.ray);
514
+ if (!h)
515
+ continue;
516
+ t.x = h.x;
517
+ t.y = h.y;
518
+ if (p.select && !t.select)
519
+ this.pointerDown(h.x, h.y, id);
520
+ this.pointerMove(h.x, h.y, id);
521
+ if (!p.select && t.select)
522
+ this.pointerUp(h.x, h.y, id);
523
+ }
524
+ else if (t.select) {
525
+ // Held, but the ray left the quad (or something nearer took the hit): the drag goes on
526
+ // over the panel's plane, and the release lands where the ray meets it.
527
+ const on = this.project(p.ray);
528
+ const x = on ? this.hit.x : Number.NaN;
529
+ const y = on ? this.hit.y : Number.NaN;
530
+ t.x = x;
531
+ t.y = y;
532
+ if (p.select)
533
+ this.pointerMove(x, y, id);
534
+ else {
535
+ this.pointerUp(x, y, id);
536
+ this.pointerLeave(id);
537
+ }
538
+ }
539
+ else {
540
+ this.pointerLeave(id);
541
+ t.seen = false;
542
+ }
543
+ t.select = p.select;
544
+ }
545
+ for (let i = tracked.length - 1; i >= 0; i--) {
546
+ const t = tracked[i];
547
+ if (t.seen)
548
+ continue;
549
+ const id = t.id;
550
+ // A pointer that vanished while held (a touch down and up within one tick) releases where
551
+ // it was last seen, so a quick tap still presses.
552
+ if (t.select)
553
+ this.pointerUp(t.x, t.y, id);
554
+ this.pointerLeave(id);
555
+ tracked.splice(i, 1);
556
+ }
557
+ }
558
+ trackedFor(p) {
559
+ for (const t of this.tracked)
560
+ if (t.key === p.key && t.source === p.source)
561
+ return t;
562
+ return null;
563
+ }
564
+ /** `router.addTester(panel.tester())`; returns the remover. */
565
+ attachTo(router) {
566
+ return router.addTester(this.tester());
567
+ }
568
+ /**
569
+ * Drive the panel on the input tick (ws/ui-4): registers the panel's tester with the input's
570
+ * pointer router and, through `input.onUpdated`, calls `poll(router.pointers)` after every
571
+ * `input.update()` and `update(camera)` with the router's camera (the one the rays go through,
572
+ * `renderer.camera` in a game, the head camera while `ctx.xr` is active). `opts.camera`
573
+ * (ws/api-core) names another camera to face, read each tick. Call once; `detach()` (and
574
+ * `dispose()`) undoes it. Manual `poll`/`update` still work for an input without a router.
575
+ */
576
+ attach(input, opts = {}) {
577
+ this.detach();
578
+ const router = input.pointers ?? null;
579
+ if (!router)
580
+ throw new Error('WorldPanel.attach: the input has no pointer router');
581
+ const offTester = this.attachTo(router);
582
+ const offTick = input.onUpdated(() => {
583
+ if (this.disposed)
584
+ return;
585
+ this.poll(router.pointers);
586
+ // The router sees a `RayCamera`; a full `Camera` (a game's `renderer.camera`) has `view`.
587
+ const cam = opts.camera ? opts.camera() : router.camera;
588
+ if (cam && 'view' in cam)
589
+ this.update(cam);
590
+ });
591
+ this.detachFn = () => {
592
+ offTick();
593
+ offTester();
594
+ };
595
+ }
596
+ /** Stop following the input `attach` hooked; nothing without one. */
597
+ detach() {
598
+ const off = this.detachFn;
599
+ this.detachFn = null;
600
+ off?.();
601
+ }
602
+ // ------------------------------------------------------------------------------------------
603
+ // Focus and keys
604
+ /** Focus `widget` (`null` clears); a widget that is not focusable is ignored. */
605
+ focus(widget) {
606
+ if (widget && (!widget.focusable || widget.host !== this))
607
+ return;
608
+ const prev = this.focused;
609
+ if (prev === widget)
610
+ return;
611
+ if (prev) {
612
+ prev.focused = false;
613
+ this.invalidate(prev);
614
+ }
615
+ this.focused = widget;
616
+ if (widget) {
617
+ widget.focused = true;
618
+ this.invalidate(widget);
619
+ }
620
+ }
621
+ focusStep(dir) {
622
+ const ws = this.widgets;
623
+ const n = ws.length;
624
+ if (n === 0)
625
+ return null;
626
+ const start = this.focused ? ws.indexOf(this.focused) : -1;
627
+ for (let k = 1; k <= n; k++) {
628
+ const i = ((((start < 0 ? (dir > 0 ? -1 : 0) : start) + dir * k) % n) + n) % n;
629
+ const w = ws[i];
630
+ if (w.focusable) {
631
+ this.focus(w);
632
+ return w;
633
+ }
634
+ }
635
+ return null;
636
+ }
637
+ /** Focus the next focusable widget (wrapping); the first when none is focused. */
638
+ focusNext() {
639
+ return this.focusStep(1);
640
+ }
641
+ /** Focus the previous focusable widget (wrapping); the last when none is focused. */
642
+ focusPrev() {
643
+ return this.focusStep(-1);
644
+ }
645
+ /** Activate the focused widget (a button presses, a toggle flips). */
646
+ activate() {
647
+ const w = this.focused;
648
+ if (w && !w.disabled)
649
+ w.activate();
650
+ }
651
+ /**
652
+ * A keyboard event: Tab / Shift+Tab move focus, Enter and Space activate, arrows and the rest
653
+ * go to the focused widget. Returns whether the key was consumed.
654
+ */
655
+ key(event) {
656
+ if (event.key === 'Tab') {
657
+ if (event.shiftKey)
658
+ this.focusPrev();
659
+ else
660
+ this.focusNext();
661
+ return true;
662
+ }
663
+ const w = this.focused;
664
+ if (!w)
665
+ return false;
666
+ if (event.key === 'Enter' || event.key === ' ') {
667
+ this.activate();
668
+ return true;
669
+ }
670
+ return w.key(event);
671
+ }
672
+ // ------------------------------------------------------------------------------------------
673
+ // Drawable
674
+ /** Repaint what is dirty and upload it (once) before the pass. */
675
+ prepare(_encoder, _frame) {
676
+ if (this.disposed)
677
+ return;
678
+ this.repaint();
679
+ if (this.needsUpload) {
680
+ this.needsUpload = false;
681
+ const u = this.uploadRect;
682
+ this.device.queue.copyExternalImageToTexture({ source: this.canvas, origin: { x: u.x, y: u.y } }, { texture: this.texture.texture, origin: { x: u.x, y: u.y }, premultipliedAlpha: true }, [u.w, u.h]);
683
+ this.stats.uploads++;
684
+ this.stats.bytes += u.w * u.h * 4;
685
+ u.w = 0;
686
+ u.h = 0;
687
+ }
688
+ const m = this.transform.world;
689
+ const d = this.uniformData;
690
+ for (let i = 0; i < 12; i++)
691
+ d[i] = m[i];
692
+ const sent = this.uniformSent;
693
+ let same = true;
694
+ for (let i = 0; i < WORLD_PANEL_UNIFORM_FLOATS; i++) {
695
+ if (sent[i] !== d[i]) {
696
+ same = false;
697
+ break;
698
+ }
699
+ }
700
+ if (!same || this.uniformDirty) {
701
+ this.uniformDirty = false;
702
+ sent.set(d);
703
+ this.device.queue.writeBuffer(this.uniform, 0, d.buffer, d.byteOffset, d.byteLength);
704
+ }
705
+ }
706
+ /** Draw the quad inside the scene pass, with the pipeline for its depth format and aux key. */
707
+ draw(pass, frame) {
708
+ this.draws = 0;
709
+ if (this.disposed)
710
+ return;
711
+ const fmt = frame?.depthFormat ?? null;
712
+ const aux = frame ? (frame.auxKey ?? 0) : this.renderer.target.auxKey;
713
+ pass.setBindGroup(1, this.group);
714
+ pass.setPipeline(this.pipelineFor(fmt, aux));
715
+ pass.draw(6, 1);
716
+ this.draws = 1;
717
+ }
718
+ pipelineFor(format, aux) {
719
+ const p = this.pipelines.get(format, aux);
720
+ if (p)
721
+ return p;
722
+ const key = format ? `${format}:${this.depthTest ? 'test' : 'always'}` : '';
723
+ const label = `${this.label}${key ? `:${key}` : ''}${auxSuffix(aux)}`;
724
+ return this.pipelines.set(format, aux, this.device.createRenderPipeline(sceneVariant(this.pipelineDesc, this.renderer.sceneTargets(PREMULTIPLIED, aux), label, format
725
+ ? {
726
+ format,
727
+ depthWriteEnabled: false,
728
+ depthCompare: this.depthTest ? 'less-equal' : 'always',
729
+ }
730
+ : undefined)));
731
+ }
732
+ /** Release the texture and buffers; the panel draws nothing after. */
733
+ dispose() {
734
+ if (this.disposed)
735
+ return;
736
+ this.disposed = true;
737
+ this.detach();
738
+ for (const w of this.widgets)
739
+ w.detach();
740
+ this.widgets.length = 0;
741
+ this.focused = null;
742
+ this.hovered = null;
743
+ this.presses.clear();
744
+ this.pressCount = 0;
745
+ this.texture.destroy();
746
+ this.uniform.destroy();
747
+ }
748
+ /** Whether a press is held on some widget. */
749
+ get pressing() {
750
+ return this.pressCount > 0;
751
+ }
752
+ }
753
+ /** The panel's blend (one object, so `sceneTargets` caches one list per aux key). */
754
+ const PREMULTIPLIED = blendState('premultiplied');
755
+ /** `new WorldPanel(renderer, opts)`. */
756
+ export function createWorldPanel(renderer, opts) {
757
+ return new WorldPanel(renderer, opts);
758
+ }
759
+ /** The pointer router's `HitTester` for `panel`: `router.addTester(worldPanelTarget(panel))`. */
760
+ export function worldPanelTarget(panel) {
761
+ return panel.tester();
762
+ }