@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,79 @@
1
+ import type { Camera } from '../render/camera.js';
2
+ /**
3
+ * Scene stack (C7 draft).
4
+ *
5
+ * - Only the top scene receives `update`.
6
+ * - `render(frame, camera, alpha)` hands scenes the camera the game draws with (`ctx.camera` in
7
+ * `createGame`), so a scene never reaches for `renderer.camera`.
8
+ * - Rendering starts at the highest scene that is not `transparent` and goes up, so a
9
+ * transparent scene (pause menu, modal) draws over the scene beneath it.
10
+ * - push/pop/replace called during `update` or `render` are deferred until that call returns,
11
+ * so a scene can safely replace itself mid-update.
12
+ * - Covered scenes get `pause()` and `resume()` when they lose and regain the top.
13
+ * - Preload (ws/core-2): a pushed or replacing scene with `preload(ctx)` is awaited before it
14
+ * enters; until then the stack is unchanged, so the old top keeps updating and rendering, and
15
+ * `transitioning` is true. Later stack ops wait behind it, in order. `push` and `replace`
16
+ * return a promise that resolves once the scene has entered (a scene without `preload` enters
17
+ * at once, or when the current `update`/`render` returns, and its promise resolves on the next
18
+ * microtask). A rejected `preload` rejects that promise and leaves the stack as it was.
19
+ * - `onTransition(fn)` reports `'preload'` (before `preload` starts), `'exit'` (after a scene's
20
+ * `exit`, with the scene it gives way to) and `'enter'` (after a scene's `enter`, with the scene
21
+ * it covered or replaced), so a game drives a loading screen or a fade from one hook.
22
+ */
23
+ export interface Scene<Ctx = unknown, Frame = unknown, Cam = Camera> {
24
+ /** Debug name. */
25
+ readonly name?: string;
26
+ /** If true, the scene below keeps rendering underneath this one. */
27
+ readonly transparent?: boolean;
28
+ /**
29
+ * Load what the scene needs before it enters; awaited by `push`/`replace` while the previous
30
+ * top keeps running. A rejection cancels the push and leaves the stack unchanged.
31
+ */
32
+ preload?(ctx: Ctx): Promise<void>;
33
+ enter?(ctx: Ctx): void;
34
+ exit?(): void;
35
+ /** Another scene was pushed on top of this one. */
36
+ pause?(): void;
37
+ /** This scene became the top again. */
38
+ resume?(): void;
39
+ update?(dt: number): void;
40
+ /** Record this scene's draws into `frame` as seen by `camera`; `alpha` interpolates between fixed steps. */
41
+ render?(frame: Frame, camera: Cam, alpha: number): void;
42
+ }
43
+ export type TransitionPhase = 'preload' | 'enter' | 'exit';
44
+ /** `from` is the scene leaving or being covered, `to` the one arriving or revealed (or undefined). */
45
+ export type TransitionListener<Ctx = unknown, Frame = unknown, Cam = Camera> = (from: Scene<Ctx, Frame, Cam> | undefined, to: Scene<Ctx, Frame, Cam> | undefined, phase: TransitionPhase) => void;
46
+ export declare class SceneStack<Ctx = unknown, Frame = unknown, Cam = Camera> {
47
+ private readonly ctx;
48
+ private readonly items;
49
+ private readonly pending;
50
+ private busy;
51
+ /** The op whose scene is preloading; the queue waits behind it. */
52
+ private loading;
53
+ private listeners;
54
+ constructor(ctx: Ctx);
55
+ get size(): number;
56
+ get top(): Scene<Ctx, Frame, Cam> | undefined;
57
+ /** True while a pushed or replacing scene's `preload` is pending. */
58
+ get transitioning(): boolean;
59
+ /** The scenes on the stack, bottom first: the live array (read it, copy it to keep it). */
60
+ get scenes(): readonly Scene<Ctx, Frame, Cam>[];
61
+ /** Push `scene` (after its `preload`, if any); resolves once it has entered. */
62
+ push(scene: Scene<Ctx, Frame, Cam>): Promise<void>;
63
+ pop(): void;
64
+ /** Replace the top with `scene` (after its `preload`, if any); resolves once it has entered. */
65
+ replace(scene: Scene<Ctx, Frame, Cam>): Promise<void>;
66
+ /** Exit every scene, top first. */
67
+ clear(): void;
68
+ /** Observe transitions; returns the unsubscribe function. Listeners are copy-on-write. */
69
+ onTransition(fn: TransitionListener<Ctx, Frame, Cam>): () => void;
70
+ update(dt: number): void;
71
+ /** Render every visible scene (highest opaque one upward) into `frame` through `camera`. */
72
+ render(frame: Frame, camera: Cam, alpha?: number): void;
73
+ private queueScene;
74
+ private queue;
75
+ private flush;
76
+ private startPreload;
77
+ private emit;
78
+ private apply;
79
+ }
@@ -0,0 +1,195 @@
1
+ const noop = () => { };
2
+ export class SceneStack {
3
+ ctx;
4
+ items = [];
5
+ pending = [];
6
+ busy = 0;
7
+ /** The op whose scene is preloading; the queue waits behind it. */
8
+ loading = null;
9
+ listeners = [];
10
+ constructor(ctx) {
11
+ this.ctx = ctx;
12
+ }
13
+ get size() {
14
+ return this.items.length;
15
+ }
16
+ get top() {
17
+ return this.items[this.items.length - 1];
18
+ }
19
+ /** True while a pushed or replacing scene's `preload` is pending. */
20
+ get transitioning() {
21
+ return this.loading !== null;
22
+ }
23
+ /** The scenes on the stack, bottom first: the live array (read it, copy it to keep it). */
24
+ get scenes() {
25
+ return this.items;
26
+ }
27
+ /** Push `scene` (after its `preload`, if any); resolves once it has entered. */
28
+ push(scene) {
29
+ return this.queueScene('push', scene);
30
+ }
31
+ pop() {
32
+ this.queue(bare('pop'));
33
+ }
34
+ /** Replace the top with `scene` (after its `preload`, if any); resolves once it has entered. */
35
+ replace(scene) {
36
+ return this.queueScene('replace', scene);
37
+ }
38
+ /** Exit every scene, top first. */
39
+ clear() {
40
+ this.queue(bare('clear'));
41
+ }
42
+ /** Observe transitions; returns the unsubscribe function. Listeners are copy-on-write. */
43
+ onTransition(fn) {
44
+ this.listeners = [...this.listeners, fn];
45
+ return () => {
46
+ this.listeners = this.listeners.filter((l) => l !== fn);
47
+ };
48
+ }
49
+ update(dt) {
50
+ const top = this.top;
51
+ if (!top?.update)
52
+ return;
53
+ this.busy++;
54
+ try {
55
+ top.update(dt);
56
+ }
57
+ finally {
58
+ this.busy--;
59
+ this.flush();
60
+ }
61
+ }
62
+ /** Render every visible scene (highest opaque one upward) into `frame` through `camera`. */
63
+ render(frame, camera, alpha = 0) {
64
+ const n = this.items.length;
65
+ if (n === 0)
66
+ return;
67
+ let start = n - 1;
68
+ while (start > 0 && this.items[start].transparent)
69
+ start--;
70
+ this.busy++;
71
+ try {
72
+ for (let i = start; i < n; i++)
73
+ this.items[i].render?.(frame, camera, alpha);
74
+ }
75
+ finally {
76
+ this.busy--;
77
+ this.flush();
78
+ }
79
+ }
80
+ queueScene(kind, scene) {
81
+ const op = {
82
+ kind,
83
+ scene,
84
+ loaded: false,
85
+ promise: null,
86
+ resolve: null,
87
+ reject: null,
88
+ };
89
+ op.promise = new Promise((resolve, reject) => {
90
+ op.resolve = resolve;
91
+ op.reject = reject;
92
+ });
93
+ // Outside the executor, so a throwing `enter` still throws out of `push`, as before.
94
+ this.queue(op);
95
+ return op.promise;
96
+ }
97
+ queue(op) {
98
+ this.pending.push(op);
99
+ if (this.busy === 0)
100
+ this.flush();
101
+ }
102
+ flush() {
103
+ while (this.busy === 0 && this.loading === null && this.pending.length > 0) {
104
+ const op = this.pending.shift();
105
+ const scene = op.scene;
106
+ if (!op.loaded && scene?.preload) {
107
+ this.startPreload(op, scene);
108
+ continue;
109
+ }
110
+ try {
111
+ this.apply(op);
112
+ }
113
+ catch (err) {
114
+ // The error throws out of the call that applied the op; the promise rejects too, marked
115
+ // handled so a caller that ignored it is not told twice.
116
+ op.promise?.catch(noop);
117
+ op.reject?.(err);
118
+ throw err;
119
+ }
120
+ op.resolve?.();
121
+ }
122
+ }
123
+ startPreload(op, scene) {
124
+ this.loading = op;
125
+ this.emit(this.top, scene, 'preload');
126
+ let p;
127
+ try {
128
+ p = Promise.resolve(scene.preload(this.ctx));
129
+ }
130
+ catch (err) {
131
+ p = Promise.reject(err);
132
+ }
133
+ p.then(() => {
134
+ this.loading = null;
135
+ op.loaded = true;
136
+ this.pending.unshift(op);
137
+ if (this.busy === 0)
138
+ this.flush();
139
+ }, (err) => {
140
+ this.loading = null;
141
+ op.reject?.(err);
142
+ if (this.busy === 0)
143
+ this.flush();
144
+ });
145
+ }
146
+ emit(from, to, phase) {
147
+ const ls = this.listeners;
148
+ for (let i = 0; i < ls.length; i++)
149
+ ls[i](from, to, phase);
150
+ }
151
+ apply(op) {
152
+ switch (op.kind) {
153
+ case 'push': {
154
+ const scene = op.scene;
155
+ const below = this.top;
156
+ below?.pause?.();
157
+ this.items.push(scene);
158
+ scene.enter?.(this.ctx);
159
+ this.emit(below, scene, 'enter');
160
+ break;
161
+ }
162
+ case 'pop': {
163
+ const s = this.items.pop();
164
+ s?.exit?.();
165
+ if (s) {
166
+ this.top?.resume?.();
167
+ this.emit(s, this.top, 'exit');
168
+ }
169
+ break;
170
+ }
171
+ case 'replace': {
172
+ const scene = op.scene;
173
+ const s = this.items.pop();
174
+ s?.exit?.();
175
+ if (s)
176
+ this.emit(s, scene, 'exit');
177
+ this.items.push(scene);
178
+ scene.enter?.(this.ctx);
179
+ this.emit(s, scene, 'enter');
180
+ break;
181
+ }
182
+ case 'clear': {
183
+ while (this.items.length) {
184
+ const s = this.items.pop();
185
+ s.exit?.();
186
+ this.emit(s, this.top, 'exit');
187
+ }
188
+ break;
189
+ }
190
+ }
191
+ }
192
+ }
193
+ function bare(kind) {
194
+ return { kind, scene: null, loaded: false, promise: null, resolve: null, reject: null };
195
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Delayed and repeating calls on the game's own clock (ws/core-2).
3
+ *
4
+ * The scheduler owns the bookkeeping, not time (the `tween` convention): it advances only when the
5
+ * game calls `update(dt)`, normally from a fixed step or a scene's `update`, so a paused loop, a
6
+ * replay or a test steps it exactly. A timer fires on the first `update` at which the scheduler's
7
+ * time reaches its due time (within 1e-9 s, so `after(1, fn)` under 60 steps of 1/60 fires on the
8
+ * 60th). Fires within one `update` run in due order (ties in scheduling order); an `every` that
9
+ * fell several periods behind in one long `dt` fires once per period, in order with the rest.
10
+ * A timer scheduled from inside a callback waits for the next `update`, even with 0 seconds.
11
+ *
12
+ * Handles are integers: a slot in a reused table plus a generation, so a stale handle (a timer
13
+ * that fired or was cancelled, its slot since reused) never touches the new occupant. The slot
14
+ * table and the heap grow to the peak number of live timers and are reused, and `update` creates
15
+ * no closures, so steady-state scheduling allocates nothing beyond the callbacks a game passes.
16
+ */
17
+ /** A timer handle; 0 is never a live handle. */
18
+ export type TimerHandle = number;
19
+ export interface EveryOptions {
20
+ /** Fire this many times, then end. Default: until cancelled. */
21
+ count?: number;
22
+ }
23
+ export interface Cooldown {
24
+ readonly name: string;
25
+ /** Seconds a `use()` blocks for. */
26
+ readonly duration: number;
27
+ /** True when `use()` would succeed. */
28
+ readonly ready: boolean;
29
+ /** Seconds until ready, 0 when ready. */
30
+ readonly remaining: number;
31
+ /** 0 just used .. 1 ready (for a cooldown bar). */
32
+ readonly progress: number;
33
+ /** If ready, start the cooldown and return true; otherwise false. */
34
+ use(): boolean;
35
+ /** Ready now. */
36
+ reset(): void;
37
+ }
38
+ export interface Scheduler {
39
+ /** Seconds this scheduler has advanced (paused updates do not count). */
40
+ readonly time: number;
41
+ /** Live timers (cooldowns not counted). */
42
+ readonly active: number;
43
+ readonly paused: boolean;
44
+ /** Call `fn` once after `seconds`. */
45
+ after(seconds: number, fn: () => void): TimerHandle;
46
+ /** Call `fn` every `seconds` (the first after one period); `count` ends it after that many. */
47
+ every(seconds: number, fn: () => void, opts?: EveryOptions): TimerHandle;
48
+ /**
49
+ * The cooldown called `name`, created ready on first use; later calls return the same object
50
+ * (and set its duration to `seconds`), so calling it per frame allocates nothing.
51
+ */
52
+ cooldown(name: string, seconds: number): Cooldown;
53
+ /** Seconds until `handle` fires next, or -1 when it is not live. */
54
+ remaining(handle: TimerHandle): number;
55
+ /** Stop a timer; false when the handle is not live. Safe from inside a callback. */
56
+ cancel(handle: TimerHandle): boolean;
57
+ /** Advance by `dt` seconds and fire what is due. Does nothing while paused. */
58
+ update(dt: number): void;
59
+ /** Cancel every timer and make every cooldown ready. */
60
+ clear(): void;
61
+ /** Hold every timer and cooldown where it is until `resume()`. */
62
+ pause(): void;
63
+ resume(): void;
64
+ }
65
+ /** A scheduler on the caller's clock; see the module comment. */
66
+ export declare function createScheduler(): Scheduler;
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Delayed and repeating calls on the game's own clock (ws/core-2).
3
+ *
4
+ * The scheduler owns the bookkeeping, not time (the `tween` convention): it advances only when the
5
+ * game calls `update(dt)`, normally from a fixed step or a scene's `update`, so a paused loop, a
6
+ * replay or a test steps it exactly. A timer fires on the first `update` at which the scheduler's
7
+ * time reaches its due time (within 1e-9 s, so `after(1, fn)` under 60 steps of 1/60 fires on the
8
+ * 60th). Fires within one `update` run in due order (ties in scheduling order); an `every` that
9
+ * fell several periods behind in one long `dt` fires once per period, in order with the rest.
10
+ * A timer scheduled from inside a callback waits for the next `update`, even with 0 seconds.
11
+ *
12
+ * Handles are integers: a slot in a reused table plus a generation, so a stale handle (a timer
13
+ * that fired or was cancelled, its slot since reused) never touches the new occupant. The slot
14
+ * table and the heap grow to the peak number of live timers and are reused, and `update` creates
15
+ * no closures, so steady-state scheduling allocates nothing beyond the callbacks a game passes.
16
+ */
17
+ const EPS = 1e-9;
18
+ const SLOT_BITS = 2 ** 20;
19
+ class CooldownImpl {
20
+ name;
21
+ duration;
22
+ left = 0;
23
+ constructor(name, duration) {
24
+ this.name = name;
25
+ this.duration = duration;
26
+ }
27
+ get ready() {
28
+ return this.left <= EPS;
29
+ }
30
+ get remaining() {
31
+ return this.left <= EPS ? 0 : this.left;
32
+ }
33
+ get progress() {
34
+ if (this.duration <= 0 || this.left <= EPS)
35
+ return 1;
36
+ return 1 - this.left / this.duration;
37
+ }
38
+ use() {
39
+ if (this.left > EPS)
40
+ return false;
41
+ this.left = this.duration;
42
+ return true;
43
+ }
44
+ reset() {
45
+ this.left = 0;
46
+ }
47
+ }
48
+ class SchedulerImpl {
49
+ now = 0;
50
+ seq = 0;
51
+ isPaused = false;
52
+ updating = false;
53
+ live = 0;
54
+ entries = [];
55
+ free = [];
56
+ /** Min-heap of slot indices by (due, seq). */
57
+ heap = [];
58
+ /** Slots scheduled during `update`, joined to the heap when it returns. */
59
+ incoming = [];
60
+ cooldowns = new Map();
61
+ cooldownList = [];
62
+ get time() {
63
+ return this.now;
64
+ }
65
+ get active() {
66
+ return this.live;
67
+ }
68
+ get paused() {
69
+ return this.isPaused;
70
+ }
71
+ after(seconds, fn) {
72
+ return this.add(seconds, 0, 1, fn);
73
+ }
74
+ every(seconds, fn, opts) {
75
+ const count = opts?.count ?? Number.POSITIVE_INFINITY;
76
+ if (!(count >= 1))
77
+ return 0;
78
+ const s = Math.max(0, seconds);
79
+ return this.add(s, s, Math.floor(count), fn);
80
+ }
81
+ cooldown(name, seconds) {
82
+ let c = this.cooldowns.get(name);
83
+ if (!c) {
84
+ c = new CooldownImpl(name, Math.max(0, seconds));
85
+ this.cooldowns.set(name, c);
86
+ this.cooldownList.push(c);
87
+ }
88
+ else
89
+ c.duration = Math.max(0, seconds);
90
+ return c;
91
+ }
92
+ remaining(handle) {
93
+ const e = this.lookup(handle);
94
+ return e ? Math.max(0, e.due - this.now) : -1;
95
+ }
96
+ cancel(handle) {
97
+ const e = this.lookup(handle);
98
+ if (!e)
99
+ return false;
100
+ e.live = false;
101
+ e.fn = null;
102
+ this.live--;
103
+ // In the heap: out now. Otherwise it waits in `incoming`, which frees it when the update ends.
104
+ if (e.heapIndex >= 0) {
105
+ this.heapRemove(e.heapIndex);
106
+ e.heapIndex = -1;
107
+ this.release(handle % SLOT_BITS);
108
+ }
109
+ return true;
110
+ }
111
+ update(dt) {
112
+ if (this.isPaused || !(dt > 0))
113
+ return;
114
+ this.now += dt;
115
+ const cds = this.cooldownList;
116
+ for (let i = 0; i < cds.length; i++) {
117
+ const c = cds[i];
118
+ if (c.left > 0)
119
+ c.left = Math.max(0, c.left - dt);
120
+ }
121
+ this.updating = true;
122
+ try {
123
+ const heap = this.heap;
124
+ const limit = this.now + EPS;
125
+ while (heap.length > 0) {
126
+ const slot = heap[0];
127
+ const e = this.entries[slot];
128
+ if (e.due > limit)
129
+ break;
130
+ this.heapRemove(0);
131
+ e.heapIndex = -1;
132
+ const fn = e.fn;
133
+ e.left--;
134
+ const repeat = e.left > 0;
135
+ if (repeat) {
136
+ e.due += e.interval;
137
+ e.seq = this.seq++;
138
+ // A zero period fires once per update; otherwise catch up within this one.
139
+ if (e.interval > 0)
140
+ this.heapPush(slot);
141
+ else
142
+ this.incoming.push(slot);
143
+ }
144
+ else {
145
+ e.live = false;
146
+ e.fn = null;
147
+ this.live--;
148
+ // Its handle is stale from here (a reuse bumps the generation), so `fn` may reuse it.
149
+ this.release(slot);
150
+ }
151
+ fn();
152
+ }
153
+ }
154
+ finally {
155
+ this.updating = false;
156
+ this.joinIncoming();
157
+ }
158
+ }
159
+ clear() {
160
+ for (let i = 0; i < this.entries.length; i++) {
161
+ const e = this.entries[i];
162
+ if (e.live)
163
+ this.cancel(e.gen * SLOT_BITS + i);
164
+ }
165
+ for (let i = 0; i < this.cooldownList.length; i++)
166
+ this.cooldownList[i].reset();
167
+ }
168
+ pause() {
169
+ this.isPaused = true;
170
+ }
171
+ resume() {
172
+ this.isPaused = false;
173
+ }
174
+ // ── internals ─────────────────────────────────────────────────────────────
175
+ add(seconds, interval, left, fn) {
176
+ let slot = this.free.pop();
177
+ if (slot === undefined) {
178
+ slot = this.entries.length;
179
+ if (slot >= SLOT_BITS)
180
+ throw new RangeError('Scheduler: too many live timers');
181
+ this.entries.push({
182
+ gen: 0,
183
+ live: false,
184
+ due: 0,
185
+ interval: 0,
186
+ left: 0,
187
+ fn: null,
188
+ seq: 0,
189
+ heapIndex: -1,
190
+ });
191
+ }
192
+ const e = this.entries[slot];
193
+ e.gen++;
194
+ e.live = true;
195
+ e.due = this.now + Math.max(0, seconds);
196
+ e.interval = interval;
197
+ e.left = left;
198
+ e.fn = fn;
199
+ e.seq = this.seq++;
200
+ e.heapIndex = -1;
201
+ this.live++;
202
+ if (this.updating)
203
+ this.incoming.push(slot);
204
+ else
205
+ this.heapPush(slot);
206
+ return e.gen * SLOT_BITS + slot;
207
+ }
208
+ lookup(handle) {
209
+ if (!Number.isInteger(handle) || handle <= 0)
210
+ return null;
211
+ const slot = handle % SLOT_BITS;
212
+ const e = this.entries[slot];
213
+ if (!e?.live || e.gen !== Math.floor(handle / SLOT_BITS))
214
+ return null;
215
+ return e;
216
+ }
217
+ release(slot) {
218
+ this.free.push(slot);
219
+ }
220
+ joinIncoming() {
221
+ const inc = this.incoming;
222
+ for (let i = 0; i < inc.length; i++) {
223
+ const slot = inc[i];
224
+ if (this.entries[slot].live)
225
+ this.heapPush(slot);
226
+ else
227
+ this.release(slot);
228
+ }
229
+ inc.length = 0;
230
+ }
231
+ less(a, b) {
232
+ const ea = this.entries[a];
233
+ const eb = this.entries[b];
234
+ return ea.due < eb.due || (ea.due === eb.due && ea.seq < eb.seq);
235
+ }
236
+ place(i, slot) {
237
+ this.heap[i] = slot;
238
+ this.entries[slot].heapIndex = i;
239
+ }
240
+ heapPush(slot) {
241
+ this.heap.push(slot);
242
+ this.siftUp(this.heap.length - 1);
243
+ }
244
+ heapRemove(i) {
245
+ const heap = this.heap;
246
+ const last = heap.pop();
247
+ if (i < heap.length) {
248
+ this.place(i, last);
249
+ this.siftDown(i);
250
+ this.siftUp(this.entries[last].heapIndex);
251
+ }
252
+ }
253
+ siftUp(i) {
254
+ const heap = this.heap;
255
+ const slot = heap[i];
256
+ while (i > 0) {
257
+ const p = (i - 1) >> 1;
258
+ if (!this.less(slot, heap[p]))
259
+ break;
260
+ this.place(i, heap[p]);
261
+ i = p;
262
+ }
263
+ this.place(i, slot);
264
+ }
265
+ siftDown(i) {
266
+ const heap = this.heap;
267
+ const n = heap.length;
268
+ const slot = heap[i];
269
+ for (;;) {
270
+ const l = 2 * i + 1;
271
+ if (l >= n)
272
+ break;
273
+ const r = l + 1;
274
+ const c = r < n && this.less(heap[r], heap[l]) ? r : l;
275
+ if (!this.less(heap[c], slot))
276
+ break;
277
+ this.place(i, heap[c]);
278
+ i = c;
279
+ }
280
+ this.place(i, slot);
281
+ }
282
+ }
283
+ /** A scheduler on the caller's clock; see the module comment. */
284
+ export function createScheduler() {
285
+ return new SchedulerImpl();
286
+ }
@@ -0,0 +1,29 @@
1
+ /** Floats per billboard instance in the storage buffer (`BILLBOARD_BYTES` / 4). */
2
+ export declare const BILLBOARD_FLOATS = 20;
3
+ export declare const BILLBOARD_BYTES: number;
4
+ /** Instance flag bits, in `pos.w` as a float. */
5
+ export declare const BB_FLAG_PX = 1;
6
+ export declare const BB_FLAG_YAW = 2;
7
+ export declare const BB_FLAG_TEXTURED = 4;
8
+ export declare const BB_FLAG_BAR = 8;
9
+ /**
10
+ * The billboard batch's shader: six vertices per instance, read from a storage buffer.
11
+ *
12
+ * - `pos.xyz` is the world anchor (position plus offset); `pos.w` carries the flags above.
13
+ * - `size.xy` is the quad size: world units, or logical px with `BB_FLAG_PX` (then the quad is
14
+ * screen-aligned and sized from `globals.logicalSize`, `globals.targetSize` and the view's
15
+ * `camera.viewport`, so it keeps its px size at any distance). `size.z` is the bar fraction.
16
+ * - World-unit quads face the camera (`camera.view` rows 0 and 1), or turn only about y with
17
+ * `BB_FLAG_YAW` (right = the view's right flattened onto xz, up = +y).
18
+ * - `color` multiplies the atlas sample (`BB_FLAG_TEXTURED`) or stands alone; with `BB_FLAG_BAR`
19
+ * the fragment is `color` where `uv.x < size.z` and `color2` beyond.
20
+ */
21
+ export declare const BILLBOARD_WGSL = "\n\nstruct EngineGlobals {\n logicalSize: vec2f,\n targetSize: vec2f,\n time: f32,\n dt: f32,\n _pad: vec2f,\n};\n@group(0) @binding(0) var<uniform> globals: EngineGlobals;\nstruct EngineCamera {\n view: mat4x4f,\n proj: mat4x4f,\n view_proj: mat4x4f,\n camera_pos: vec4f,\n viewport: vec4f,\n view_index: u32,\n _pad0: u32, _pad1: u32, _pad2: u32,\n inv_view_proj: mat4x4f,\n prev_view_proj: mat4x4f,\n prev_view: mat4x4f,\n jitter: vec4f,\n};\n@group(0) @binding(1) var<uniform> camera: EngineCamera;\n\nstruct Billboard {\n pos: vec4f,\n size: vec4f,\n uv: vec4f,\n color: vec4f,\n color2: vec4f,\n};\n@group(1) @binding(0) var<storage, read> billboards: array<Billboard>;\n@group(1) @binding(1) var atlas_sampler: sampler;\n@group(1) @binding(2) var atlas: texture_2d<f32>;\n\nstruct VSOut {\n @builtin(position) clip: vec4f,\n @location(0) uv: vec2f,\n @location(1) q: vec2f,\n @location(2) color: vec4f,\n @location(3) color2: vec4f,\n @location(4) @interpolate(flat) flags: u32,\n @location(5) fraction: f32,\n};\nstruct FragOut {\n @location(0) color: vec4f,\n @location(1) emissive: vec4f,\n};\n\nfn view_row(r: u32) -> vec3f {\n return vec3f(camera.view[0][r], camera.view[1][r], camera.view[2][r]);\n}\n\n@vertex fn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> VSOut {\n var o: VSOut;\n let b = billboards[ii];\n var corners = array<vec2f, 6>(\n vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),\n vec2f(-1.0, -1.0), vec2f(1.0, 1.0), vec2f(-1.0, 1.0)\n );\n let q = corners[vi];\n let flags = u32(b.pos.w + 0.5);\n let half = b.size.xy * 0.5;\n if ((flags & 1u) != 0u) {\n var clip = camera.view_proj * vec4f(b.pos.xyz, 1.0);\n // Logical px \u2192 target px \u2192 NDC, scaled by w so the division leaves the px size intact.\n let px_per_logical = globals.targetSize / globals.logicalSize;\n let ndc = (q * half * px_per_logical) / max(camera.viewport.zw, vec2f(1.0)) * 2.0;\n clip = vec4f(clip.xy + ndc * clip.w, clip.zw);\n o.clip = clip;\n } else {\n var right = view_row(0u);\n var up = view_row(1u);\n if ((flags & 2u) != 0u) {\n let flat = vec3f(right.x, 0.0, right.z);\n let len = length(flat);\n right = select(vec3f(1.0, 0.0, 0.0), flat / max(len, 1e-6), len > 1e-6);\n up = vec3f(0.0, 1.0, 0.0);\n }\n let world = b.pos.xyz + right * (q.x * half.x) + up * (q.y * half.y);\n o.clip = camera.view_proj * vec4f(world, 1.0);\n }\n // Canvas uv: v grows downward, so the top of the quad (q.y = 1) samples v0.\n let t = q * 0.5 + 0.5;\n o.uv = vec2f(mix(b.uv.x, b.uv.z, t.x), mix(b.uv.w, b.uv.y, t.y));\n o.q = t;\n o.color = b.color;\n o.color2 = b.color2;\n o.flags = flags;\n o.fraction = b.size.z;\n return o;\n}\n\n@fragment fn fs(in: VSOut) -> FragOut {\n var c = in.color;\n if ((in.flags & 8u) != 0u) {\n c = select(in.color2, in.color, in.q.x < in.fraction);\n }\n // Sampled unconditionally: textureSample needs uniform control flow.\n let s = textureSample(atlas, atlas_sampler, in.uv);\n c *= select(vec4f(1.0), s, (in.flags & 4u) != 0u);\n var o: FragOut;\n o.color = c;\n o.emissive = vec4f(0.0, 0.0, 0.0, c.a);\n return o;\n}\n";
22
+ /**
23
+ * `BILLBOARD_WGSL`, or with `velocity` (the velocity attachment's fragment location, 2 or 3)
24
+ * the build that writes its own motion (ws/render-11): binding 3 holds each sorted instance's
25
+ * previous anchor (`xyz`, `w` = 1 when known), the vertex stage projects the same corner of
26
+ * last frame's quad through `camera.prev_view_proj` / `prev_view`, and the fragment writes
27
+ * `vec4f(engine_motion(..), 0, alpha)` there. Internal; `0` is the exported string itself.
28
+ */
29
+ export declare function billboardWgsl(velocity: number): string;