@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,306 @@
1
+ import { VERTEX3D_FLOATS } from '../render/mesh.js';
2
+ /** Outward normal of each `VoxelFace`. */
3
+ export const VOXEL_FACE_NORMALS = [
4
+ [1, 0, 0],
5
+ [-1, 0, 0],
6
+ [0, 1, 0],
7
+ [0, -1, 0],
8
+ [0, 0, 1],
9
+ [0, 0, -1],
10
+ ];
11
+ /** Default AO curve: corner level (0 darkest .. 3 open) → vertex brightness. */
12
+ export const VOXEL_AO_CURVE = [0.42, 0.62, 0.82, 1];
13
+ /** Floats per vertex of the mesher's output (`VERTEX_LAYOUT_3D`). */
14
+ export const VOXEL_VERTEX_FLOATS = VERTEX3D_FLOATS;
15
+ /** Output buffers with room for `quads` quads before the first growth. */
16
+ export function createChunkMeshOut(quads = 1024) {
17
+ return {
18
+ vertices: new Float32Array(quads * 4 * VOXEL_VERTEX_FLOATS),
19
+ indices: new Uint32Array(quads * 6),
20
+ vertexCount: 0,
21
+ indexCount: 0,
22
+ bounds: { center: [0, 0, 0], radius: 0 },
23
+ };
24
+ }
25
+ const defaultLayer = (block) => block - 1;
26
+ /** Growth factor of `ChunkMeshOut` buffers (1.5×, a vector's amortised growth). */
27
+ const GROWTH = 1.5;
28
+ let mask = new Int32Array(0);
29
+ const p = [0, 0, 0];
30
+ const n = [0, 0, 0];
31
+ const ea = [0, 0, 0];
32
+ const eb = [0, 0, 0];
33
+ const extent = [0, 0, 0];
34
+ const corners = new Int32Array(4);
35
+ const aoLevels = new Int32Array(4);
36
+ /**
37
+ * Mesh chunk (`cx`, `cy`, `cz`) of `grid` into `out`. Returns `out`. Every quad is planar on
38
+ * its face's axis, winds counter-clockwise seen from outside (both triangles) and its vertex
39
+ * normal is the face's normal. `out.vertexCount` 0 means an empty chunk.
40
+ */
41
+ export function meshChunk(grid, cx, cy, cz, opts, out) {
42
+ const size = grid.chunk;
43
+ if (mask.length < size * size)
44
+ mask = new Int32Array(size * size);
45
+ const ao = opts.ao ?? true;
46
+ const curve = opts.aoCurve ?? VOXEL_AO_CURVE;
47
+ const layerOf = opts.layerOf ?? defaultLayer;
48
+ const outside = opts.outside ?? 0;
49
+ const outsideFn = typeof outside === 'function' ? outside : null;
50
+ const outsideBlock = typeof outside === 'number' ? outside : 0;
51
+ const data = grid.data;
52
+ const sx = grid.sizeX;
53
+ const sy = grid.sizeY;
54
+ const sz = grid.sizeZ;
55
+ const ox = cx * size;
56
+ const oy = cy * size;
57
+ const oz = cz * size;
58
+ extent[0] = Math.min(size, sx - ox);
59
+ extent[1] = Math.min(size, sy - oy);
60
+ extent[2] = Math.min(size, sz - oz);
61
+ const at = (x, y, z) => {
62
+ if (x >= 0 && y >= 0 && z >= 0 && x < sx && y < sy && z < sz) {
63
+ return data[x + sx * (y + sy * z)];
64
+ }
65
+ return outsideFn ? outsideFn(x, y, z) : outsideBlock;
66
+ };
67
+ let vf = 0; // floats written
68
+ let ic = 0; // indices written
69
+ let minX = Infinity;
70
+ let minY = Infinity;
71
+ let minZ = Infinity;
72
+ let maxX = -Infinity;
73
+ let maxY = -Infinity;
74
+ let maxZ = -Infinity;
75
+ for (let d = 0; d < 3; d++) {
76
+ // (a, b, d) is a cyclic permutation of (x, y, z): a × b = d, so corners emitted in
77
+ // (a0,b0) (a1,b0) (a1,b1) (a0,b1) order wind counter-clockwise seen from +d.
78
+ const a = (d + 1) % 3;
79
+ const b = (d + 2) % 3;
80
+ ea[0] = ea[1] = ea[2] = 0;
81
+ eb[0] = eb[1] = eb[2] = 0;
82
+ ea[a] = 1;
83
+ eb[b] = 1;
84
+ const na = extent[a];
85
+ const nb = extent[b];
86
+ const nd = extent[d];
87
+ for (let dir = 1; dir >= -1; dir -= 2) {
88
+ const face = (d * 2 + (dir > 0 ? 0 : 1));
89
+ n[0] = n[1] = n[2] = 0;
90
+ n[d] = dir;
91
+ for (let k = 0; k < nd; k++) {
92
+ // The mask of this slice.
93
+ let any = false;
94
+ for (let j = 0; j < nb; j++) {
95
+ for (let i = 0; i < na; i++) {
96
+ p[d] = k;
97
+ p[a] = i;
98
+ p[b] = j;
99
+ const wx = ox + p[0];
100
+ const wy = oy + p[1];
101
+ const wz = oz + p[2];
102
+ const block = data[wx + sx * (wy + sy * wz)];
103
+ let key = 0;
104
+ if (block !== 0) {
105
+ const qx = wx + n[0];
106
+ const qy = wy + n[1];
107
+ const qz = wz + n[2];
108
+ if (at(qx, qy, qz) === 0) {
109
+ key = 1 | ((layerOf(block, face) & 0xff) << 1);
110
+ if (ao) {
111
+ for (let slot = 0; slot < 4; slot++) {
112
+ const sa = slot & 1 ? 1 : -1;
113
+ const sb = slot & 2 ? 1 : -1;
114
+ const s1 = at(qx + sa * ea[0], qy + sa * ea[1], qz + sa * ea[2]) !== 0 ? 1 : 0;
115
+ const s2 = at(qx + sb * eb[0], qy + sb * eb[1], qz + sb * eb[2]) !== 0 ? 1 : 0;
116
+ let level;
117
+ if (s1 && s2)
118
+ level = 0;
119
+ else {
120
+ const c = at(qx + sa * ea[0] + sb * eb[0], qy + sa * ea[1] + sb * eb[1], qz + sa * ea[2] + sb * eb[2]) !== 0
121
+ ? 1
122
+ : 0;
123
+ level = 3 - (s1 + s2 + c);
124
+ }
125
+ key |= level << (9 + 2 * slot);
126
+ }
127
+ }
128
+ any = true;
129
+ }
130
+ }
131
+ mask[i + size * j] = key;
132
+ }
133
+ }
134
+ if (!any)
135
+ continue;
136
+ // Greedy merge.
137
+ for (let j = 0; j < nb; j++) {
138
+ for (let i = 0; i < na;) {
139
+ const key = mask[i + size * j];
140
+ if (key === 0) {
141
+ i++;
142
+ continue;
143
+ }
144
+ let w = 1;
145
+ while (i + w < na && mask[i + w + size * j] === key)
146
+ w++;
147
+ let h = 1;
148
+ outer: while (j + h < nb) {
149
+ for (let t = 0; t < w; t++) {
150
+ if (mask[i + t + size * (j + h)] !== key)
151
+ break outer;
152
+ }
153
+ h++;
154
+ }
155
+ for (let hh = 0; hh < h; hh++) {
156
+ for (let t = 0; t < w; t++)
157
+ mask[i + t + size * (j + hh)] = 0;
158
+ }
159
+ // Emit the quad: the plane sits at d = k (+1 for the positive face).
160
+ if (vf + 4 * VOXEL_VERTEX_FLOATS > out.vertices.length) {
161
+ const bigger = new Float32Array(Math.ceil(out.vertices.length * GROWTH));
162
+ bigger.set(out.vertices);
163
+ out.vertices = bigger;
164
+ }
165
+ if (ic + 6 > out.indices.length) {
166
+ const bigger = new Uint32Array(Math.ceil(out.indices.length * GROWTH));
167
+ bigger.set(out.indices);
168
+ out.indices = bigger;
169
+ }
170
+ const verts = out.vertices;
171
+ const layer = (key >> 1) & 0xff;
172
+ const plane = k + (dir > 0 ? 1 : 0);
173
+ const base = vf / VOXEL_VERTEX_FLOATS;
174
+ for (let c = 0; c < 4; c++) {
175
+ // Corner order (a0,b0) (a1,b0) (a1,b1) (a0,b1); reversed for the negative face.
176
+ const cc = dir > 0 ? c : (4 - c) % 4;
177
+ const ha = cc === 1 || cc === 2 ? 1 : 0;
178
+ const hb = cc === 2 || cc === 3 ? 1 : 0;
179
+ const ac = i + ha * w;
180
+ const bc = j + hb * h;
181
+ p[d] = plane;
182
+ p[a] = ac;
183
+ p[b] = bc;
184
+ const px = p[0];
185
+ const py = p[1];
186
+ const pz = p[2];
187
+ if (px < minX)
188
+ minX = px;
189
+ if (py < minY)
190
+ minY = py;
191
+ if (pz < minZ)
192
+ minZ = pz;
193
+ if (px > maxX)
194
+ maxX = px;
195
+ if (py > maxY)
196
+ maxY = py;
197
+ if (pz > maxZ)
198
+ maxZ = pz;
199
+ verts[vf] = px;
200
+ verts[vf + 1] = py;
201
+ verts[vf + 2] = pz;
202
+ verts[vf + 3] = n[0];
203
+ verts[vf + 4] = n[1];
204
+ verts[vf + 5] = n[2];
205
+ // uv in block units: u along the horizontal axis, v downward from the quad's top.
206
+ let u;
207
+ let v;
208
+ if (d === 0) {
209
+ // a = y (vertical), b = z.
210
+ u = bc - j;
211
+ v = i + w - ac;
212
+ }
213
+ else if (d === 2) {
214
+ // a = x, b = y (vertical).
215
+ u = ac - i;
216
+ v = j + h - bc;
217
+ }
218
+ else {
219
+ u = ac - i;
220
+ v = bc - j;
221
+ }
222
+ verts[vf + 6] = u;
223
+ verts[vf + 7] = v;
224
+ const slot = ha | (hb << 1);
225
+ const level = ao ? (key >> (9 + 2 * slot)) & 3 : 3;
226
+ const bright = ao ? (curve[level] ?? 1) : 1;
227
+ aoLevels[c] = level;
228
+ verts[vf + 8] = bright;
229
+ verts[vf + 9] = bright;
230
+ verts[vf + 10] = bright;
231
+ verts[vf + 11] = layer;
232
+ corners[c] = base + c;
233
+ vf += VOXEL_VERTEX_FLOATS;
234
+ }
235
+ // Split along the diagonal whose corners are darker, so the dark pair shares an edge.
236
+ const idx = out.indices;
237
+ if (aoLevels[0] + aoLevels[2] > aoLevels[1] + aoLevels[3]) {
238
+ idx[ic++] = corners[1];
239
+ idx[ic++] = corners[2];
240
+ idx[ic++] = corners[3];
241
+ idx[ic++] = corners[1];
242
+ idx[ic++] = corners[3];
243
+ idx[ic++] = corners[0];
244
+ }
245
+ else {
246
+ idx[ic++] = corners[0];
247
+ idx[ic++] = corners[1];
248
+ idx[ic++] = corners[2];
249
+ idx[ic++] = corners[0];
250
+ idx[ic++] = corners[2];
251
+ idx[ic++] = corners[3];
252
+ }
253
+ i += w;
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ out.vertexCount = vf / VOXEL_VERTEX_FLOATS;
260
+ out.indexCount = ic;
261
+ const bounds = out.bounds;
262
+ if (vf === 0) {
263
+ bounds.center[0] = bounds.center[1] = bounds.center[2] = 0;
264
+ bounds.radius = 0;
265
+ }
266
+ else {
267
+ bounds.center[0] = (minX + maxX) / 2;
268
+ bounds.center[1] = (minY + maxY) / 2;
269
+ bounds.center[2] = (minZ + maxZ) / 2;
270
+ bounds.radius = Math.hypot(maxX - minX, maxY - minY, maxZ - minZ) / 2;
271
+ }
272
+ return out;
273
+ }
274
+ /**
275
+ * Exposed faces of chunk (`cx`, `cy`, `cz`) counted one cell at a time (no merging): the
276
+ * reference the mesher's quads must cover exactly. Each quad of `meshChunk` covers
277
+ * `w × h` of these, so a test sums quad areas against it. Same `outside` rule.
278
+ */
279
+ export function countExposedFaces(grid, cx, cy, cz, outside = 0) {
280
+ const size = grid.chunk;
281
+ const x0 = cx * size;
282
+ const y0 = cy * size;
283
+ const z0 = cz * size;
284
+ const x1 = Math.min(grid.sizeX, x0 + size);
285
+ const y1 = Math.min(grid.sizeY, y0 + size);
286
+ const z1 = Math.min(grid.sizeZ, z0 + size);
287
+ const at = (x, y, z) => grid.inBounds(x, y, z)
288
+ ? grid.get(x, y, z)
289
+ : typeof outside === 'function'
290
+ ? outside(x, y, z)
291
+ : outside;
292
+ let faces = 0;
293
+ for (let z = z0; z < z1; z++) {
294
+ for (let y = y0; y < y1; y++) {
295
+ for (let x = x0; x < x1; x++) {
296
+ if (grid.get(x, y, z) === 0)
297
+ continue;
298
+ for (const [nx, ny, nz] of VOXEL_FACE_NORMALS) {
299
+ if (at(x + nx, y + ny, z + nz) === 0)
300
+ faces++;
301
+ }
302
+ }
303
+ }
304
+ }
305
+ return faces;
306
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Block picking: a ray walked cell by cell through a `VoxelGrid` (Amanatides & Woo's DDA).
3
+ * Grid units are world units with the grid's corner at the origin; a world placed elsewhere
4
+ * subtracts its origin from the ray first. Pure, no allocation.
5
+ */
6
+ import type { VoxelGrid } from './grid.js';
7
+ /** What `raycastVoxels` fills on a hit. */
8
+ export interface VoxelHit {
9
+ /** The solid cell hit. */
10
+ x: number;
11
+ y: number;
12
+ z: number;
13
+ /** Outward normal of the face entered (one unit axis; all zero when the ray starts inside a block). */
14
+ nx: number;
15
+ ny: number;
16
+ nz: number;
17
+ /** The empty cell in front of that face: where a placed block goes (the hit cell itself when inside). */
18
+ px: number;
19
+ py: number;
20
+ pz: number;
21
+ /** Ray parameter of the hit, in units of the direction's length (world units for a unit direction). */
22
+ distance: number;
23
+ }
24
+ /** A hit record to fill. */
25
+ export declare function createVoxelHit(): VoxelHit;
26
+ /**
27
+ * Walk the ray from (`ox`, `oy`, `oz`) along (`dx`, `dy`, `dz`) up to `maxDist` (in units of
28
+ * the direction's length) through `grid`, returning true and filling `out` at the first
29
+ * non-air cell. Cells outside the grid are air. A ray starting inside a block hits it at
30
+ * distance 0 with a zero normal.
31
+ */
32
+ export declare function raycastVoxels(grid: VoxelGrid, ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, maxDist: number, out: VoxelHit): boolean;
@@ -0,0 +1,73 @@
1
+ /** A hit record to fill. */
2
+ export function createVoxelHit() {
3
+ return { x: 0, y: 0, z: 0, nx: 0, ny: 0, nz: 0, px: 0, py: 0, pz: 0, distance: 0 };
4
+ }
5
+ /**
6
+ * Walk the ray from (`ox`, `oy`, `oz`) along (`dx`, `dy`, `dz`) up to `maxDist` (in units of
7
+ * the direction's length) through `grid`, returning true and filling `out` at the first
8
+ * non-air cell. Cells outside the grid are air. A ray starting inside a block hits it at
9
+ * distance 0 with a zero normal.
10
+ */
11
+ export function raycastVoxels(grid, ox, oy, oz, dx, dy, dz, maxDist, out) {
12
+ let x = Math.floor(ox);
13
+ let y = Math.floor(oy);
14
+ let z = Math.floor(oz);
15
+ const stepX = dx > 0 ? 1 : dx < 0 ? -1 : 0;
16
+ const stepY = dy > 0 ? 1 : dy < 0 ? -1 : 0;
17
+ const stepZ = dz > 0 ? 1 : dz < 0 ? -1 : 0;
18
+ const tDeltaX = stepX === 0 ? Infinity : Math.abs(1 / dx);
19
+ const tDeltaY = stepY === 0 ? Infinity : Math.abs(1 / dy);
20
+ const tDeltaZ = stepZ === 0 ? Infinity : Math.abs(1 / dz);
21
+ let tMaxX = stepX === 0 ? Infinity : (stepX > 0 ? x + 1 - ox : ox - x) * tDeltaX;
22
+ let tMaxY = stepY === 0 ? Infinity : (stepY > 0 ? y + 1 - oy : oy - y) * tDeltaY;
23
+ let tMaxZ = stepZ === 0 ? Infinity : (stepZ > 0 ? z + 1 - oz : oz - z) * tDeltaZ;
24
+ let nx = 0;
25
+ let ny = 0;
26
+ let nz = 0;
27
+ let t = 0;
28
+ // Every step crosses one cell boundary; the ray crosses at most one per axis per unit of
29
+ // travel along that axis, so `3 * maxDist + 3` steps cover the whole distance.
30
+ const steps = Math.ceil(3 * maxDist * Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz))) + 3;
31
+ for (let i = 0; i < steps; i++) {
32
+ if (grid.inBounds(x, y, z) && grid.data[grid.index(x, y, z)] !== 0) {
33
+ out.x = x;
34
+ out.y = y;
35
+ out.z = z;
36
+ out.nx = nx;
37
+ out.ny = ny;
38
+ out.nz = nz;
39
+ out.px = x + nx;
40
+ out.py = y + ny;
41
+ out.pz = z + nz;
42
+ out.distance = t;
43
+ return true;
44
+ }
45
+ if (tMaxX < tMaxY && tMaxX < tMaxZ) {
46
+ t = tMaxX;
47
+ x += stepX;
48
+ tMaxX += tDeltaX;
49
+ nx = -stepX;
50
+ ny = 0;
51
+ nz = 0;
52
+ }
53
+ else if (tMaxY < tMaxZ) {
54
+ t = tMaxY;
55
+ y += stepY;
56
+ tMaxY += tDeltaY;
57
+ nx = 0;
58
+ ny = -stepY;
59
+ nz = 0;
60
+ }
61
+ else {
62
+ t = tMaxZ;
63
+ z += stepZ;
64
+ tMaxZ += tDeltaZ;
65
+ nx = 0;
66
+ ny = 0;
67
+ nz = -stepZ;
68
+ }
69
+ if (t > maxDist)
70
+ return false;
71
+ }
72
+ return false;
73
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * WGSL helpers for a block material over the mesher's vertex convention. Prepend `VOXEL_WGSL`
3
+ * to the material's `wgsl` (after any `@group(1)` declarations it needs) and read:
4
+ *
5
+ * - `voxel_layer(in.color)`: the texture-array layer the mesher wrote to colour.a
6
+ * (`u32(round(a))`, exact through interpolation because every vertex of a quad carries the
7
+ * same layer);
8
+ * - `voxel_ao(in.color)`: the baked ambient occlusion in colour.r;
9
+ * - `voxel_uv_wrap(in.uv)`: the uv wrapped into 0..1 for a clamping sampler or an atlas;
10
+ * the quad's uv spans whole block units, so `fract` tiles the face. Sample with
11
+ * `textureSampleGrad(tex, s, voxel_uv_wrap(in.uv), layer, dpdx(in.uv), dpdy(in.uv))`: the
12
+ * derivatives of the unwrapped uv keep the mip selection continuous across the wrap seam.
13
+ * With the `'nearest-mip-repeat'` sampler kind the wrap is the sampler's and
14
+ * `textureSample(tex, s, in.uv, layer)` is enough.
15
+ */
16
+ export declare const VOXEL_WGSL = "\nfn voxel_layer(color: vec4f) -> u32 {\n return u32(round(max(color.a, 0.0)));\n}\n\nfn voxel_ao(color: vec4f) -> f32 {\n return color.r;\n}\n\nfn voxel_uv_wrap(uv: vec2f) -> vec2f {\n return fract(uv);\n}\n";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * WGSL helpers for a block material over the mesher's vertex convention. Prepend `VOXEL_WGSL`
3
+ * to the material's `wgsl` (after any `@group(1)` declarations it needs) and read:
4
+ *
5
+ * - `voxel_layer(in.color)`: the texture-array layer the mesher wrote to colour.a
6
+ * (`u32(round(a))`, exact through interpolation because every vertex of a quad carries the
7
+ * same layer);
8
+ * - `voxel_ao(in.color)`: the baked ambient occlusion in colour.r;
9
+ * - `voxel_uv_wrap(in.uv)`: the uv wrapped into 0..1 for a clamping sampler or an atlas;
10
+ * the quad's uv spans whole block units, so `fract` tiles the face. Sample with
11
+ * `textureSampleGrad(tex, s, voxel_uv_wrap(in.uv), layer, dpdx(in.uv), dpdy(in.uv))`: the
12
+ * derivatives of the unwrapped uv keep the mip selection continuous across the wrap seam.
13
+ * With the `'nearest-mip-repeat'` sampler kind the wrap is the sampler's and
14
+ * `textureSample(tex, s, in.uv, layer)` is enough.
15
+ */
16
+ export const VOXEL_WGSL = /* wgsl */ `
17
+ fn voxel_layer(color: vec4f) -> u32 {
18
+ return u32(round(max(color.a, 0.0)));
19
+ }
20
+
21
+ fn voxel_ao(color: vec4f) -> f32 {
22
+ return color.r;
23
+ }
24
+
25
+ fn voxel_uv_wrap(uv: vec2f) -> vec2f {
26
+ return fract(uv);
27
+ }
28
+ `;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The mesher behind a promise: `createVoxelMesher(grid, { worker })` runs `meshChunk` in the
3
+ * Worker the game made from a three-line script calling `installVoxelMesherWorker`
4
+ * (`mesher-worker.ts`), or on the main thread when no Worker is given (the same code, the same
5
+ * reply shape, a microtask later). The Worker owns a copy of the grid: `createVoxelMesher`
6
+ * sends `grid.serialize()` once and mirrors every `set` the grid reports afterwards
7
+ * (`VoxelGrid.subscribe`), so the game edits the grid and nothing else.
8
+ *
9
+ * `remesh(chunk)` resolves with a `ChunkMesh`: one transferred `ArrayBuffer` in the
10
+ * `MeshReply` shape `Mesh.update` takes as it is (vertices from byte 0, uint32 indices after
11
+ * them). One request per chunk is in flight at a time; a repeat while one is in flight waits
12
+ * for the next run (coalesced: a burst of edits to one chunk meshes it twice at most).
13
+ */
14
+ import type { MeshBounds, MeshReply } from '../render/mesh.js';
15
+ import type { VoxelGrid } from './grid.js';
16
+ import { type ChunkMeshOut, type MeshChunkOptions } from './mesher.js';
17
+ /** A meshed chunk: `Mesh.update` takes it as a `MeshReply`. */
18
+ export interface ChunkMesh extends MeshReply {
19
+ chunk: number;
20
+ buffer: ArrayBuffer;
21
+ vertexCount: number;
22
+ /** 6 per quad; 0 for an empty chunk (`buffer` is then empty). */
23
+ indexCount: number;
24
+ /** Byte offset of the uint32 indices in `buffer`. */
25
+ indexOffset: number;
26
+ /** Bounding sphere in chunk-local units (radius 0 when empty). */
27
+ bounds: MeshBounds;
28
+ }
29
+ /** Page → Worker. */
30
+ export type VoxelMesherRequest = {
31
+ type: 'grid';
32
+ buffer: ArrayBuffer;
33
+ } | {
34
+ type: 'set';
35
+ x: number;
36
+ y: number;
37
+ z: number;
38
+ block: number;
39
+ } | {
40
+ type: 'mesh';
41
+ chunk: number;
42
+ };
43
+ /** Worker → page. */
44
+ export type VoxelMesherReply = ChunkMesh & {
45
+ type: 'mesh';
46
+ };
47
+ /** The part of a `Worker` the client uses (a test passes a fake). */
48
+ export interface VoxelWorkerLike {
49
+ postMessage(message: VoxelMesherRequest, transfer?: Transferable[]): void;
50
+ addEventListener(type: 'message', listener: (e: {
51
+ data: unknown;
52
+ }) => void): void;
53
+ removeEventListener(type: 'message', listener: (e: {
54
+ data: unknown;
55
+ }) => void): void;
56
+ }
57
+ export interface VoxelMesherOptions extends MeshChunkOptions {
58
+ /** Mesh in this Worker (made from a script calling `installVoxelMesherWorker`). Default: in-thread. */
59
+ worker?: VoxelWorkerLike;
60
+ }
61
+ export interface VoxelMesher {
62
+ readonly grid: VoxelGrid;
63
+ /** True when a Worker does the meshing. */
64
+ readonly offThread: boolean;
65
+ /** Requests not yet resolved. */
66
+ readonly pending: number;
67
+ /** Mesh `chunk` (a chunk index) as the grid stands when the request runs. */
68
+ remesh(chunk: number): Promise<ChunkMesh>;
69
+ /** Resend the whole grid to the Worker (`fill` and `deserialize` do this on their own). */
70
+ sync(): void;
71
+ /** Stop mirroring the grid and listening to the Worker. The game terminates the Worker. */
72
+ dispose(): void;
73
+ }
74
+ /**
75
+ * Copy the mesher's output into one new `ArrayBuffer` (vertices, then uint32 indices) as a
76
+ * `ChunkMesh`, ready to transfer. An empty output gives an empty buffer.
77
+ */
78
+ export declare function packChunkMesh(out: ChunkMeshOut, chunk: number): ChunkMesh;
79
+ export declare function createVoxelMesher(grid: VoxelGrid, opts?: VoxelMesherOptions): VoxelMesher;
@@ -0,0 +1,122 @@
1
+ import { createChunkMeshOut, meshChunk, VOXEL_VERTEX_FLOATS, } from './mesher.js';
2
+ /**
3
+ * Copy the mesher's output into one new `ArrayBuffer` (vertices, then uint32 indices) as a
4
+ * `ChunkMesh`, ready to transfer. An empty output gives an empty buffer.
5
+ */
6
+ export function packChunkMesh(out, chunk) {
7
+ const vertexBytes = out.vertexCount * VOXEL_VERTEX_FLOATS * 4;
8
+ const indexBytes = out.indexCount * 4;
9
+ const buffer = new ArrayBuffer(vertexBytes + indexBytes);
10
+ if (vertexBytes > 0) {
11
+ new Float32Array(buffer, 0, out.vertexCount * VOXEL_VERTEX_FLOATS).set(out.vertices.subarray(0, out.vertexCount * VOXEL_VERTEX_FLOATS));
12
+ }
13
+ if (indexBytes > 0) {
14
+ new Uint32Array(buffer, vertexBytes, out.indexCount).set(out.indices.subarray(0, out.indexCount));
15
+ }
16
+ const b = out.bounds;
17
+ return {
18
+ chunk,
19
+ buffer,
20
+ vertexCount: out.vertexCount,
21
+ indexCount: out.indexCount,
22
+ indexOffset: vertexBytes,
23
+ bounds: { center: [b.center[0], b.center[1], b.center[2]], radius: b.radius },
24
+ };
25
+ }
26
+ function deferred() {
27
+ let resolve;
28
+ const promise = new Promise((r) => {
29
+ resolve = r;
30
+ });
31
+ return { promise, resolve };
32
+ }
33
+ const coordsOut = [0, 0, 0];
34
+ export function createVoxelMesher(grid, opts = {}) {
35
+ const worker = opts.worker ?? null;
36
+ const inflight = new Map();
37
+ const queued = new Map();
38
+ let out = null;
39
+ let pendingCount = 0;
40
+ const send = (chunk, d) => {
41
+ inflight.set(chunk, d);
42
+ worker.postMessage({ type: 'mesh', chunk });
43
+ };
44
+ const onMessage = (e) => {
45
+ const reply = e.data;
46
+ if (!reply || reply.type !== 'mesh')
47
+ return;
48
+ const d = inflight.get(reply.chunk);
49
+ if (!d)
50
+ return;
51
+ inflight.delete(reply.chunk);
52
+ pendingCount--;
53
+ const next = queued.get(reply.chunk);
54
+ if (next) {
55
+ queued.delete(reply.chunk);
56
+ send(reply.chunk, next);
57
+ }
58
+ d.resolve(reply);
59
+ };
60
+ const unsubscribe = grid.subscribe({
61
+ set: (x, y, z, block) => worker?.postMessage({ type: 'set', x, y, z, block }),
62
+ reset: () => sync(),
63
+ });
64
+ function sync() {
65
+ if (!worker)
66
+ return;
67
+ const buffer = grid.serialize();
68
+ worker.postMessage({ type: 'grid', buffer }, [buffer]);
69
+ }
70
+ if (worker) {
71
+ worker.addEventListener('message', onMessage);
72
+ sync();
73
+ }
74
+ const remeshInThread = (chunk) => {
75
+ const d = deferred();
76
+ inflight.set(chunk, d);
77
+ pendingCount++;
78
+ queueMicrotask(() => {
79
+ inflight.delete(chunk);
80
+ pendingCount--;
81
+ out ??= createChunkMeshOut();
82
+ grid.chunkCoords(chunk, coordsOut);
83
+ meshChunk(grid, coordsOut[0], coordsOut[1], coordsOut[2], opts, out);
84
+ d.resolve(packChunkMesh(out, chunk));
85
+ });
86
+ return d.promise;
87
+ };
88
+ return {
89
+ grid,
90
+ offThread: worker !== null,
91
+ get pending() {
92
+ return pendingCount;
93
+ },
94
+ remesh(chunk) {
95
+ const current = inflight.get(chunk);
96
+ if (current) {
97
+ if (!worker)
98
+ return current.promise;
99
+ let next = queued.get(chunk);
100
+ if (!next) {
101
+ next = deferred();
102
+ queued.set(chunk, next);
103
+ pendingCount++;
104
+ }
105
+ return next.promise;
106
+ }
107
+ if (!worker)
108
+ return remeshInThread(chunk);
109
+ const d = deferred();
110
+ pendingCount++;
111
+ send(chunk, d);
112
+ return d.promise;
113
+ },
114
+ sync,
115
+ dispose() {
116
+ unsubscribe();
117
+ worker?.removeEventListener('message', onMessage);
118
+ inflight.clear();
119
+ queued.clear();
120
+ },
121
+ };
122
+ }