@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,702 @@
1
+ import { auxSuffix, motionVariant, ScenePipelineCache, sceneVariant, velocityLocation, } from '../render/scene-pipelines.js';
2
+ import { createShaderModule } from '../render/wgsl.js';
3
+ import { BB_FLAG_BAR, BB_FLAG_PX, BB_FLAG_TEXTURED, BB_FLAG_YAW, BILLBOARD_BYTES, BILLBOARD_FLOATS, BILLBOARD_WGSL, billboardWgsl, } from './billboard-wgsl.js';
4
+ import { TextAtlas } from './text-atlas.js';
5
+ const WHITE = [1, 1, 1, 1];
6
+ const ZERO3 = [0, 0, 0];
7
+ const F = BILLBOARD_FLOATS;
8
+ /** Added to the sort key of `depth: 'always'` quads so they draw after every `'test'` one. */
9
+ const ALWAYS_KEY = 1e9;
10
+ const ALPHA_BLEND = {
11
+ color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
12
+ alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
13
+ };
14
+ /**
15
+ * World units a span of `px` logical px covers at `viewDistance` from a camera whose projection
16
+ * is `projection` (column-major; `projection[5]` is the vertical scale) on a viewport
17
+ * `viewportPx` logical px tall. The shader applies the same ratio in clip space for `{ px }`
18
+ * sizes; use this on the CPU to size something in world units to match a px plate.
19
+ */
20
+ export function pxToWorld(px, viewDistance, projection, viewportPx) {
21
+ const scale = projection[5] ?? 1;
22
+ const w = Math.abs(projection[11] ?? 0) > 0 ? viewDistance : 1;
23
+ return ((px / viewportPx) * 2 * w) / scale;
24
+ }
25
+ /**
26
+ * One billboard, returned by `Billboards.add`. Setters change it in place; it is `alive` until
27
+ * `remove` or its `life` runs out, after which the setters do nothing.
28
+ */
29
+ export class BillboardHandle {
30
+ owner;
31
+ /** @internal slot in the owner's arrays, -1 when dead. */
32
+ slot = -1;
33
+ constructor(owner) {
34
+ this.owner = owner;
35
+ }
36
+ get alive() {
37
+ return this.slot >= 0;
38
+ }
39
+ set position(p) {
40
+ if (this.slot >= 0)
41
+ this.owner.setPosition(this.slot, p);
42
+ }
43
+ set offset(o) {
44
+ if (this.slot >= 0)
45
+ this.owner.setOffset(this.slot, o);
46
+ }
47
+ set color(c) {
48
+ if (this.slot >= 0)
49
+ this.owner.setColor(this.slot, c);
50
+ }
51
+ set size(s) {
52
+ if (this.slot >= 0)
53
+ this.owner.setSize(this.slot, s);
54
+ }
55
+ set region(r) {
56
+ if (this.slot >= 0)
57
+ this.owner.setRegion(this.slot, r);
58
+ }
59
+ /** The text plate's text (`desc.text`, `setText`); null when not a plate. */
60
+ get text() {
61
+ return this.slot >= 0 ? this.owner.plateText(this.slot) : null;
62
+ }
63
+ /**
64
+ * Change a text plate's text (ws/fx-4). Re-rasterised into the plate's own atlas cell when it
65
+ * fits (no new region, no new texture), else into a wider cell: the quad's height stays and
66
+ * its width grows with the cell, so the glyphs keep their scale. A handle that is not a plate
67
+ * becomes one, in the default style, at its current size.
68
+ */
69
+ setText(text) {
70
+ if (this.slot >= 0)
71
+ this.owner.setText(this.slot, text);
72
+ }
73
+ /** The filled share of a bar quad, 0..1. */
74
+ set fraction(f) {
75
+ if (this.slot >= 0)
76
+ this.owner.setFraction(this.slot, f);
77
+ }
78
+ }
79
+ /**
80
+ * World-anchored, camera-facing quads in one batch: name plates, damage numbers, health bars,
81
+ * markers. Each shows a region of the shared text atlas or a solid colour, is sized in world
82
+ * units or in screen px, optionally fades out over `life` and drifts by `velocity`. Alpha
83
+ * blended, depth tested without writing (or drawn over everything with `depth: 'always'`),
84
+ * sorted back to front each `update`. Draw with `frame.drawable(billboards)`.
85
+ *
86
+ * ```ts
87
+ * const bb = createBillboards(renderer);
88
+ * const plate = bb.add({ position: hero.position, offset: [0, 2, 0], size: { px: [160, 40] },
89
+ * region: bb.text('Hero', { size: 28, stroke: '#000', strokeWidth: 4 }) });
90
+ * bb.add({ position: hero.position, offset: [0, 2.3, 0], size: [1, 0.12], life: 0.9,
91
+ * velocity: [0, 1.2, 0], region: bb.text('-37', { color: '#f44' }) });
92
+ * bb.update(dt, camera); // ages, drifts, sorts
93
+ * frame.drawable(bb); // inside the scene's render
94
+ * ```
95
+ *
96
+ * Nothing allocates per frame once the buffers are big enough; `add` past `capacity` doubles
97
+ * them.
98
+ */
99
+ export class Billboards {
100
+ /** The atlas canvas as a texture, uploaded when the atlas changed (once per frame at most). */
101
+ atlasTexture;
102
+ /** The text atlas behind `text()`. */
103
+ atlas;
104
+ /** Draw calls the last `draw` issued (0, 1 or 2: one per depth mode in use). */
105
+ draws = 0;
106
+ renderer;
107
+ device;
108
+ label;
109
+ capacity;
110
+ n = 0;
111
+ // Per slot, CPU side.
112
+ anchor;
113
+ tracked;
114
+ offset;
115
+ velocity;
116
+ /** age, life (life <= 0: immortal). */
117
+ life;
118
+ rgba;
119
+ mode;
120
+ regions;
121
+ /** A text plate's text (its region an owned atlas cell); null when not a plate. */
122
+ plates;
123
+ handles;
124
+ /** Instance data per slot, in `BILLBOARD_WGSL`'s layout. */
125
+ inst;
126
+ // Per frame.
127
+ order;
128
+ keys;
129
+ upload;
130
+ /**
131
+ * Motion (ws/render-11): per slot the anchor its quad was last drawn at (`xyz`, `w` = 1 once
132
+ * drawn), and the previous anchors in sorted order for `prevBuffer` (binding 3), which the
133
+ * velocity build of the shader reads. Kept only once a view with a velocity attachment drew
134
+ * the batch (`motion`); until then the buffer holds zeros, read as "unknown" (no motion).
135
+ */
136
+ drawn;
137
+ prevUpload;
138
+ prevBuffer;
139
+ motion = false;
140
+ /** The velocity builds of the shader, by fragment location (2 or 3), made on first use. */
141
+ motionModules = [];
142
+ testCount = 0;
143
+ alwaysCount = 0;
144
+ uploadDirty = false;
145
+ buffer;
146
+ group;
147
+ groupLayout;
148
+ pipelineDesc;
149
+ /**
150
+ * Pipelines per depth format (null: none) × the view target's aux key, made on first use
151
+ * from `renderer.sceneTargets` (ws/render-10): `testPipelines` depth-test (and hold the
152
+ * depthless one), `alwaysPipelines` ignore depth.
153
+ */
154
+ testPipelines = new ScenePipelineCache();
155
+ alwaysPipelines = new ScenePipelineCache();
156
+ constructor(renderer, opts = {}) {
157
+ const device = renderer.device;
158
+ this.renderer = renderer;
159
+ this.device = device;
160
+ this.label = opts.label ?? 'billboards';
161
+ const cap = Math.max(16, Math.floor(opts.capacity ?? 1024));
162
+ this.capacity = cap;
163
+ this.anchor = new Float32Array(cap * 3);
164
+ this.tracked = new Array(cap).fill(null);
165
+ this.offset = new Float32Array(cap * 3);
166
+ this.velocity = new Float32Array(cap * 3);
167
+ this.life = new Float32Array(cap * 2);
168
+ this.rgba = new Float32Array(cap * 4);
169
+ this.mode = new Uint8Array(cap);
170
+ this.regions = new Array(cap).fill(null);
171
+ this.plates = new Array(cap).fill(null);
172
+ this.handles = new Array(cap);
173
+ this.inst = new Float32Array(cap * F);
174
+ this.order = new Uint32Array(cap);
175
+ this.keys = new Float32Array(cap);
176
+ this.upload = new Float32Array(cap * F);
177
+ this.drawn = new Float32Array(cap * 4);
178
+ this.prevUpload = new Float32Array(cap * 4);
179
+ this.motion = (renderer.target.auxKey & 2) !== 0;
180
+ this.atlas = new TextAtlas(opts.atlas);
181
+ this.atlasTexture = renderer.createTexture({
182
+ width: this.atlas.size,
183
+ height: this.atlas.size,
184
+ format: 'rgba8unorm-srgb',
185
+ label: `${this.label}-atlas`,
186
+ });
187
+ this.groupLayout = device.createBindGroupLayout({
188
+ label: `${this.label}-layout`,
189
+ entries: [
190
+ { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'read-only-storage' } },
191
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
192
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: {} },
193
+ { binding: 3, visibility: GPUShaderStage.VERTEX, buffer: { type: 'read-only-storage' } },
194
+ ],
195
+ });
196
+ this.buffer = this.makeBuffer(cap);
197
+ this.prevBuffer = this.makePrevBuffer(cap);
198
+ this.group = this.makeGroup();
199
+ const mod = createShaderModule(device, BILLBOARD_WGSL, this.label);
200
+ this.pipelineDesc = {
201
+ label: this.label,
202
+ layout: device.createPipelineLayout({
203
+ bindGroupLayouts: [renderer.globalsLayout, this.groupLayout],
204
+ }),
205
+ vertex: { module: mod, entryPoint: 'vs' },
206
+ fragment: {
207
+ module: mod,
208
+ entryPoint: 'fs',
209
+ targets: renderer.sceneTargets(ALPHA_BLEND),
210
+ },
211
+ primitive: { topology: 'triangle-list' },
212
+ };
213
+ this.pipelineFor(null, renderer.target.auxKey, false);
214
+ }
215
+ /** Live billboards. */
216
+ get count() {
217
+ return this.n;
218
+ }
219
+ /** Share of the atlas canvas in use, 0..1. */
220
+ get atlasUsed() {
221
+ return this.atlas.used;
222
+ }
223
+ makeBuffer(cap) {
224
+ return this.device.createBuffer({
225
+ label: this.label,
226
+ size: cap * BILLBOARD_BYTES,
227
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
228
+ });
229
+ }
230
+ makePrevBuffer(cap) {
231
+ return this.device.createBuffer({
232
+ label: `${this.label}-prev`,
233
+ size: cap * 16,
234
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
235
+ });
236
+ }
237
+ makeGroup() {
238
+ return this.device.createBindGroup({
239
+ label: this.label,
240
+ layout: this.groupLayout,
241
+ entries: [
242
+ { binding: 0, resource: { buffer: this.buffer } },
243
+ { binding: 1, resource: this.renderer.samplers['linear-clamp'] },
244
+ { binding: 2, resource: this.atlasTexture.view },
245
+ { binding: 3, resource: { buffer: this.prevBuffer } },
246
+ ],
247
+ });
248
+ }
249
+ /** Double every array and the GPU buffer (only when `add` finds the batch full). */
250
+ grow() {
251
+ const cap = this.capacity * 2;
252
+ const copy = (old, per) => {
253
+ const out = new old.constructor(cap * per);
254
+ out.set(old);
255
+ return out;
256
+ };
257
+ this.anchor = copy(this.anchor, 3);
258
+ this.offset = copy(this.offset, 3);
259
+ this.velocity = copy(this.velocity, 3);
260
+ this.life = copy(this.life, 2);
261
+ this.rgba = copy(this.rgba, 4);
262
+ this.mode = copy(this.mode, 1);
263
+ this.inst = copy(this.inst, F);
264
+ this.order = copy(this.order, 1);
265
+ this.keys = copy(this.keys, 1);
266
+ this.upload = new Float32Array(cap * F);
267
+ this.drawn = copy(this.drawn, 4);
268
+ this.prevUpload = new Float32Array(cap * 4);
269
+ this.tracked.length = cap;
270
+ this.regions.length = cap;
271
+ this.plates.length = cap;
272
+ this.handles.length = cap;
273
+ for (let i = this.capacity; i < cap; i++) {
274
+ this.tracked[i] = null;
275
+ this.regions[i] = null;
276
+ this.plates[i] = null;
277
+ }
278
+ this.capacity = cap;
279
+ this.buffer.destroy();
280
+ this.buffer = this.makeBuffer(cap);
281
+ this.prevBuffer.destroy();
282
+ this.prevBuffer = this.makePrevBuffer(cap);
283
+ this.group = this.makeGroup();
284
+ }
285
+ /** Add a billboard; the handle changes or removes it later. */
286
+ add(desc) {
287
+ if (this.n === this.capacity)
288
+ this.grow();
289
+ const i = this.n++;
290
+ const h = new BillboardHandle(this);
291
+ h.slot = i;
292
+ this.handles[i] = h;
293
+ this.setPosition(i, desc.position);
294
+ this.setOffset(i, desc.offset ?? ZERO3);
295
+ const v = desc.velocity ?? ZERO3;
296
+ this.velocity[i * 3] = v[0];
297
+ this.velocity[i * 3 + 1] = v[1];
298
+ this.velocity[i * 3 + 2] = v[2];
299
+ this.life[i * 2] = 0;
300
+ this.life[i * 2 + 1] = desc.life ?? 0;
301
+ this.drawn[i * 4 + 3] = 0;
302
+ this.mode[i] = desc.depth === 'always' ? 1 : 0;
303
+ const o = i * F;
304
+ const inst = this.inst;
305
+ inst.fill(0, o, o + F);
306
+ inst[o + 3] = desc.facing === 'cameraY' ? BB_FLAG_YAW : 0;
307
+ this.setSize(i, desc.size);
308
+ this.plates[i] = null;
309
+ this.regions[i] = null;
310
+ if (desc.text !== undefined)
311
+ this.makePlate(i, desc.text, desc.textStyle);
312
+ else
313
+ this.setRegion(i, desc.region ?? null);
314
+ this.setColor(i, desc.color ?? WHITE);
315
+ const bar = desc.bar;
316
+ if (bar) {
317
+ inst[o + 3] = (inst[o + 3] | BB_FLAG_BAR) >>> 0;
318
+ inst[o + 6] = bar.fraction;
319
+ inst[o + 16] = bar.bg[0];
320
+ inst[o + 17] = bar.bg[1];
321
+ inst[o + 18] = bar.bg[2];
322
+ inst[o + 19] = bar.bg[3] ?? 1;
323
+ }
324
+ return h;
325
+ }
326
+ /** Remove a billboard now (a no-op for one already gone). */
327
+ remove(handle) {
328
+ const i = handle.slot;
329
+ if (i < 0 || this.handles[i] !== handle)
330
+ return;
331
+ this.removeAt(i);
332
+ }
333
+ /** Remove every billboard. Atlas text stays cached; text plates give their cells back. */
334
+ clear() {
335
+ for (let i = 0; i < this.n; i++) {
336
+ this.handles[i].slot = -1;
337
+ this.releasePlate(i);
338
+ this.tracked[i] = null;
339
+ this.regions[i] = null;
340
+ }
341
+ this.n = 0;
342
+ this.testCount = 0;
343
+ this.alwaysCount = 0;
344
+ this.uploadDirty = true;
345
+ }
346
+ /** Swap-remove slot `i`: the last slot moves into it. */
347
+ removeAt(i) {
348
+ const last = --this.n;
349
+ this.handles[i].slot = -1;
350
+ this.releasePlate(i);
351
+ if (i !== last) {
352
+ const h = this.handles[last];
353
+ h.slot = i;
354
+ this.handles[i] = h;
355
+ this.tracked[i] = this.tracked[last];
356
+ this.regions[i] = this.regions[last];
357
+ this.plates[i] = this.plates[last];
358
+ this.mode[i] = this.mode[last];
359
+ this.anchor.copyWithin(i * 3, last * 3, last * 3 + 3);
360
+ this.offset.copyWithin(i * 3, last * 3, last * 3 + 3);
361
+ this.velocity.copyWithin(i * 3, last * 3, last * 3 + 3);
362
+ this.life.copyWithin(i * 2, last * 2, last * 2 + 2);
363
+ this.rgba.copyWithin(i * 4, last * 4, last * 4 + 4);
364
+ this.inst.copyWithin(i * F, last * F, last * F + F);
365
+ this.drawn.copyWithin(i * 4, last * 4, last * 4 + 4);
366
+ }
367
+ this.drawn[last * 4 + 3] = 0;
368
+ this.tracked[last] = null;
369
+ this.regions[last] = null;
370
+ this.plates[last] = null;
371
+ }
372
+ /**
373
+ * The atlas region for `text` in `style`, rasterised on first use and cached (text + style).
374
+ * Throws when the string is larger than the whole atlas canvas.
375
+ */
376
+ text(text, style) {
377
+ const r = this.atlas.text(text, style);
378
+ if (!r)
379
+ throw new Error(`billboards: "${text}" does not fit a ${this.atlas.size}px atlas`);
380
+ return r;
381
+ }
382
+ /**
383
+ * A health bar in one quad, `fraction` (0..1) of its width in `fg` and the rest in `bg`:
384
+ * spread it into `add` with a `position`, then set `handle.fraction`.
385
+ */
386
+ bar(fraction, size, fg, bg) {
387
+ return { size, color: fg, region: null, bar: { fraction, bg } };
388
+ }
389
+ /** @internal */
390
+ setPosition(i, p) {
391
+ if (p instanceof Float32Array) {
392
+ this.tracked[i] = p;
393
+ }
394
+ else {
395
+ this.tracked[i] = null;
396
+ this.anchor[i * 3] = p[0];
397
+ this.anchor[i * 3 + 1] = p[1];
398
+ this.anchor[i * 3 + 2] = p[2];
399
+ }
400
+ }
401
+ /** @internal */
402
+ setOffset(i, o) {
403
+ this.offset[i * 3] = o[0];
404
+ this.offset[i * 3 + 1] = o[1];
405
+ this.offset[i * 3 + 2] = o[2];
406
+ }
407
+ /** @internal */
408
+ setColor(i, c) {
409
+ const o = i * 4;
410
+ this.rgba[o] = c[0];
411
+ this.rgba[o + 1] = c[1];
412
+ this.rgba[o + 2] = c[2];
413
+ this.rgba[o + 3] = c[3] ?? 1;
414
+ }
415
+ /** @internal */
416
+ setSize(i, s) {
417
+ const o = i * F;
418
+ const inst = this.inst;
419
+ const flags = inst[o + 3] & ~BB_FLAG_PX;
420
+ if ('px' in s) {
421
+ inst[o + 3] = flags | BB_FLAG_PX;
422
+ inst[o + 4] = s.px[0];
423
+ inst[o + 5] = s.px[1];
424
+ }
425
+ else {
426
+ inst[o + 3] = flags;
427
+ inst[o + 4] = s[0];
428
+ inst[o + 5] = s[1];
429
+ }
430
+ }
431
+ /**
432
+ * The width and height, in atlas px, a text plate of `text` in `style` gets (its cell): size
433
+ * a plate's quad to this aspect.
434
+ */
435
+ measure(text, style) {
436
+ return this.atlas.cellSize(text, style);
437
+ }
438
+ /** @internal */
439
+ plateText(i) {
440
+ return this.plates[i] ?? null;
441
+ }
442
+ /** @internal */
443
+ setText(i, text) {
444
+ const old = this.regions[i];
445
+ if (this.plates[i] === null || !old) {
446
+ this.makePlate(i, text);
447
+ return;
448
+ }
449
+ const r = this.atlas.rewrite(old, text);
450
+ if (!r)
451
+ throw new Error(`billboards: "${text}" does not fit a ${this.atlas.size}px atlas`);
452
+ if (r !== old) {
453
+ // A wider cell: keep the height and the glyph scale.
454
+ this.inst[i * F + 4] *= r.width / old.width;
455
+ this.regions[i] = null;
456
+ this.writeRegion(i, r);
457
+ }
458
+ this.plates[i] = text;
459
+ }
460
+ makePlate(i, text, style) {
461
+ const r = this.atlas.cell(text, style);
462
+ if (!r)
463
+ throw new Error(`billboards: "${text}" does not fit a ${this.atlas.size}px atlas`);
464
+ this.setRegion(i, r);
465
+ this.plates[i] = text;
466
+ }
467
+ releasePlate(i) {
468
+ if (this.plates[i] === null)
469
+ return;
470
+ const r = this.regions[i];
471
+ if (r)
472
+ this.atlas.release(r);
473
+ this.plates[i] = null;
474
+ }
475
+ /** @internal */
476
+ setRegion(i, r) {
477
+ if (this.regions[i] !== r)
478
+ this.releasePlate(i);
479
+ this.writeRegion(i, r);
480
+ }
481
+ writeRegion(i, r) {
482
+ const o = i * F;
483
+ const inst = this.inst;
484
+ this.regions[i] = r;
485
+ const flags = inst[o + 3] & ~BB_FLAG_TEXTURED;
486
+ if (r) {
487
+ inst[o + 3] = flags | BB_FLAG_TEXTURED;
488
+ inst[o + 8] = r.u0;
489
+ inst[o + 9] = r.v0;
490
+ inst[o + 10] = r.u1;
491
+ inst[o + 11] = r.v1;
492
+ }
493
+ else {
494
+ inst[o + 3] = flags;
495
+ }
496
+ }
497
+ /** @internal */
498
+ setFraction(i, f) {
499
+ this.inst[i * F + 6] = f;
500
+ }
501
+ /**
502
+ * Age and drift every billboard, remove the ones past their `life`, resolve anchors and fades
503
+ * into the instance data and sort back to front for `camera` (without one, submission order).
504
+ * Call once per update or frame; allocation-free.
505
+ */
506
+ update(dt, camera) {
507
+ const life = this.life;
508
+ const vel = this.velocity;
509
+ const anchor = this.anchor;
510
+ const offset = this.offset;
511
+ const tracked = this.tracked;
512
+ const inst = this.inst;
513
+ const rgba = this.rgba;
514
+ const keys = this.keys;
515
+ const order = this.order;
516
+ const atlas = this.atlas;
517
+ const view = camera ? camera.view : null;
518
+ // Expire from the end so swap-removes never skip a slot.
519
+ for (let i = this.n - 1; i >= 0; i--) {
520
+ const total = life[i * 2 + 1];
521
+ if (total <= 0)
522
+ continue;
523
+ const age = life[i * 2] + dt;
524
+ life[i * 2] = age;
525
+ if (age >= total)
526
+ this.removeAt(i);
527
+ }
528
+ const n = this.n;
529
+ let test = 0;
530
+ for (let i = 0; i < n; i++) {
531
+ const i3 = i * 3;
532
+ const t = tracked[i];
533
+ // Velocity moves the copied anchor, or the offset of a tracked one.
534
+ const dst = t ? offset : anchor;
535
+ dst[i3] = dst[i3] + vel[i3] * dt;
536
+ dst[i3 + 1] = dst[i3 + 1] + vel[i3 + 1] * dt;
537
+ dst[i3 + 2] = dst[i3 + 2] + vel[i3 + 2] * dt;
538
+ const x = (t ? t[0] : anchor[i3]) + offset[i3];
539
+ const y = (t ? t[1] : anchor[i3 + 1]) + offset[i3 + 1];
540
+ const z = (t ? t[2] : anchor[i3 + 2]) + offset[i3 + 2];
541
+ const o = i * F;
542
+ inst[o] = x;
543
+ inst[o + 1] = y;
544
+ inst[o + 2] = z;
545
+ const total = life[i * 2 + 1];
546
+ let fade = 1;
547
+ if (total > 0) {
548
+ const left = 1 - life[i * 2] / total;
549
+ fade = left < 0.5 ? left * 2 : 1;
550
+ }
551
+ inst[o + 12] = rgba[i * 4];
552
+ inst[o + 13] = rgba[i * 4 + 1];
553
+ inst[o + 14] = rgba[i * 4 + 2];
554
+ inst[o + 15] = rgba[i * 4 + 3] * fade;
555
+ const r = this.regions[i];
556
+ if (r)
557
+ atlas.touch(r);
558
+ const z_view = view ? view[2] * x + view[6] * y + view[10] * z + view[14] : 0;
559
+ const always = this.mode[i] === 1;
560
+ if (!always)
561
+ test++;
562
+ keys[i] = (always ? ALWAYS_KEY : 0) + z_view;
563
+ order[i] = i;
564
+ }
565
+ this.testCount = test;
566
+ this.alwaysCount = n - test;
567
+ // Insertion sort by key ascending (farther view z is more negative, so back to front).
568
+ // Frame-to-frame coherence keeps it near linear.
569
+ for (let i = 1; i < n; i++) {
570
+ const idx = order[i];
571
+ const k = keys[idx];
572
+ let j = i - 1;
573
+ while (j >= 0 && keys[order[j]] > k) {
574
+ order[j + 1] = order[j];
575
+ j--;
576
+ }
577
+ order[j + 1] = idx;
578
+ }
579
+ const upload = this.upload;
580
+ for (let i = 0; i < n; i++) {
581
+ const src = order[i] * F;
582
+ upload.set(inst.subarray(src, src + F), i * F);
583
+ }
584
+ this.uploadDirty = true;
585
+ }
586
+ /**
587
+ * Upload the instance data, last frame's drawn anchors when the view has velocity and, when
588
+ * the atlas changed, its canvas. Runs before the pass.
589
+ */
590
+ prepare(_encoder, _frame) {
591
+ if (_frame && (_frame.auxKey & 2) !== 0)
592
+ this.motion = true;
593
+ if (this.motion)
594
+ this.writePrevious();
595
+ if (this.uploadDirty) {
596
+ this.uploadDirty = false;
597
+ if (this.n > 0) {
598
+ this.device.queue.writeBuffer(this.buffer, 0, this.upload.buffer, 0, this.n * BILLBOARD_BYTES);
599
+ }
600
+ }
601
+ const atlas = this.atlas;
602
+ if (atlas.dirty) {
603
+ atlas.markUploaded();
604
+ this.device.queue.copyExternalImageToTexture({ source: atlas.canvas }, { texture: this.atlasTexture.texture }, [atlas.size, atlas.size]);
605
+ }
606
+ }
607
+ /**
608
+ * Once per frame with `motion` on: each drawn quad's previous anchor (where it was drawn last
609
+ * frame, or its current one the first time) into `prevBuffer` in draw order, then remember
610
+ * the current anchors. Without an `update` since, current equals previous (no motion).
611
+ */
612
+ writePrevious() {
613
+ const n = this.n;
614
+ if (n === 0)
615
+ return;
616
+ const order = this.order;
617
+ const upload = this.upload;
618
+ const drawn = this.drawn;
619
+ const prev = this.prevUpload;
620
+ for (let i = 0; i < n; i++) {
621
+ const s = order[i];
622
+ const u = i * F;
623
+ const p = i * 4;
624
+ const d = s * 4;
625
+ const known = s < n && drawn[d + 3] === 1;
626
+ prev[p] = known ? drawn[d] : upload[u];
627
+ prev[p + 1] = known ? drawn[d + 1] : upload[u + 1];
628
+ prev[p + 2] = known ? drawn[d + 2] : upload[u + 2];
629
+ prev[p + 3] = 1;
630
+ if (s < n) {
631
+ drawn[d] = upload[u];
632
+ drawn[d + 1] = upload[u + 1];
633
+ drawn[d + 2] = upload[u + 2];
634
+ drawn[d + 3] = 1;
635
+ }
636
+ }
637
+ this.device.queue.writeBuffer(this.prevBuffer, 0, prev.buffer, 0, n * 16);
638
+ }
639
+ /** Draw inside the scene pass: the `'test'` quads, then the `'always'` ones. */
640
+ draw(pass, frame) {
641
+ this.draws = 0;
642
+ if (this.n === 0)
643
+ return;
644
+ const fmt = frame?.depthFormat ?? null;
645
+ const aux = frame ? frame.auxKey : this.renderer.target.auxKey;
646
+ // A first velocity view: its prev buffer is still zeros (no motion) until the next prepare.
647
+ if ((aux & 2) !== 0)
648
+ this.motion = true;
649
+ pass.setBindGroup(1, this.group);
650
+ if (!fmt) {
651
+ pass.setPipeline(this.pipelineFor(null, aux, false));
652
+ pass.draw(6, this.n);
653
+ this.draws = 1;
654
+ return;
655
+ }
656
+ if (this.testCount > 0) {
657
+ pass.setPipeline(this.pipelineFor(fmt, aux, false));
658
+ pass.draw(6, this.testCount, 0, 0);
659
+ this.draws++;
660
+ }
661
+ if (this.alwaysCount > 0) {
662
+ pass.setPipeline(this.pipelineFor(fmt, aux, true));
663
+ pass.draw(6, this.alwaysCount, 0, this.testCount);
664
+ this.draws++;
665
+ }
666
+ }
667
+ pipelineFor(format, aux, always) {
668
+ const cache = always ? this.alwaysPipelines : this.testPipelines;
669
+ const p = cache.get(format, aux);
670
+ if (p)
671
+ return p;
672
+ const label = `${this.label}${format ? `:${format}` : ''}${always ? ':always' : ''}`;
673
+ const depth = format
674
+ ? { format, depthWriteEnabled: false, depthCompare: always ? 'always' : 'less-equal' }
675
+ : undefined;
676
+ const targets = this.renderer.sceneTargets(ALPHA_BLEND, aux);
677
+ const at = velocityLocation(aux);
678
+ // With a velocity attachment the quads write their own motion (ws/render-11).
679
+ const desc = at === 0
680
+ ? sceneVariant(this.pipelineDesc, targets, `${label}${auxSuffix(aux)}`, depth)
681
+ : motionVariant(this.pipelineDesc, this.motionModule(at), targets, aux, `${label}${auxSuffix(aux)}:motion`, depth);
682
+ return cache.set(format, aux, this.device.createRenderPipeline(desc));
683
+ }
684
+ motionModule(at) {
685
+ let m = this.motionModules[at];
686
+ if (!m) {
687
+ m = createShaderModule(this.device, billboardWgsl(at), `${this.label}-motion`);
688
+ this.motionModules[at] = m;
689
+ }
690
+ return m;
691
+ }
692
+ destroy() {
693
+ this.clear();
694
+ this.buffer.destroy();
695
+ this.prevBuffer.destroy();
696
+ this.atlasTexture.destroy();
697
+ }
698
+ }
699
+ /** `new Billboards(renderer, opts)`. */
700
+ export function createBillboards(renderer, opts) {
701
+ return new Billboards(renderer, opts);
702
+ }