@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,472 @@
1
+ /**
2
+ * Mesh: a vertex buffer (+ optional index buffer) in one of the engine's vertex layouts.
3
+ *
4
+ * - `VERTEX_LAYOUT_2D` (the default): `pos: vec2f, uv: vec2f, color: vec4f`, 8 floats
5
+ * (`VERTEX_FLOATS`), 32 bytes per vertex.
6
+ * - `VERTEX_LAYOUT_3D`: `pos: vec3f, normal: vec3f, uv: vec2f, color: vec4f`, 12 floats
7
+ * (`VERTEX3D_FLOATS`), 48 bytes per vertex.
8
+ * - `VERTEX_LAYOUT_3D_TANGENT`: the 3D layout plus `tangent: vec4f` (xyz, handedness w),
9
+ * 16 floats, 64 bytes per vertex.
10
+ *
11
+ * Positions are in the mesh's local space; each draw's 3×4 instance matrix (built from
12
+ * `DrawParams` x, y, w, h, rotation, or taken from a `Transform`) maps local → world space.
13
+ * For `DrawParams` that is `xy + rotate(pos * wh)`: the built-in quad spans -0.5..0.5 so
14
+ * `w, h` are its size in logical pixels; for arbitrary meshes authored directly in logical
15
+ * pixels, draw with `x = 0, y = 0, w = 1, h = 1`.
16
+ *
17
+ * Materials build one pipeline per (vertex layout, depth mode), lazily, on first use.
18
+ */
19
+ export const VERTEX_FLOATS = 8;
20
+ export const VERTEX_STRIDE = VERTEX_FLOATS * 4;
21
+ export const VERTEX3D_FLOATS = 12;
22
+ export const VERTEX3D_STRIDE = VERTEX3D_FLOATS * 4;
23
+ /** The 2D layout's buffer layout (locations 0..2). */
24
+ export const VERTEX_BUFFER_LAYOUT = {
25
+ arrayStride: VERTEX_STRIDE,
26
+ stepMode: 'vertex',
27
+ attributes: [
28
+ { shaderLocation: 0, offset: 0, format: 'float32x2' },
29
+ { shaderLocation: 1, offset: 8, format: 'float32x2' },
30
+ { shaderLocation: 2, offset: 16, format: 'float32x4' },
31
+ ],
32
+ };
33
+ /** The 3D layout's buffer layout: position 0, normal 10, uv 1, colour 2. */
34
+ export const VERTEX3D_BUFFER_LAYOUT = {
35
+ arrayStride: VERTEX3D_STRIDE,
36
+ stepMode: 'vertex',
37
+ attributes: [
38
+ { shaderLocation: 0, offset: 0, format: 'float32x3' },
39
+ { shaderLocation: 10, offset: 12, format: 'float32x3' },
40
+ { shaderLocation: 1, offset: 24, format: 'float32x2' },
41
+ { shaderLocation: 2, offset: 32, format: 'float32x4' },
42
+ ],
43
+ };
44
+ /** 2D layout: `v.pos` is a `vec2f` (z = 0); the normal faces the viewer, `(0, 0, -1)`. */
45
+ export const VERTEX_LAYOUT_2D = {
46
+ name: '2d',
47
+ positionOffset: 0,
48
+ floats: VERTEX_FLOATS,
49
+ stride: VERTEX_STRIDE,
50
+ buffer: VERTEX_BUFFER_LAYOUT,
51
+ wgslFields: ` @location(0) pos: vec2f,
52
+ @location(1) uv: vec2f,
53
+ @location(2) color: vec4f,`,
54
+ wgslPosition: 'vec3f(v.pos, 0.0)',
55
+ wgslNormal: 'vec3f(0.0, 0.0, -1.0)',
56
+ };
57
+ /** 3D layout: `v.pos` and `v.normal` are `vec3f`. */
58
+ export const VERTEX_LAYOUT_3D = {
59
+ name: '3d',
60
+ positionOffset: 0,
61
+ floats: VERTEX3D_FLOATS,
62
+ stride: VERTEX3D_STRIDE,
63
+ buffer: VERTEX3D_BUFFER_LAYOUT,
64
+ wgslFields: ` @location(0) pos: vec3f,
65
+ @location(10) normal: vec3f,
66
+ @location(1) uv: vec2f,
67
+ @location(2) color: vec4f,`,
68
+ wgslPosition: 'v.pos',
69
+ wgslNormal: 'v.normal',
70
+ };
71
+ /**
72
+ * Tangent layout (ws/geom-2): the 3D layout's 12 floats followed by a tangent `vec4f` at
73
+ * `@location(13)` (3..9 are the instance buffer, 11 and 12 skinning): xyz the unit tangent
74
+ * along +u, w the handedness ±1, so the bitangent is `w · cross(normal, tangent)`. 16 floats,
75
+ * 64 bytes. `geom`'s `computeTangents` writes it; the prelude reads it like the 3D layout, so a
76
+ * material that ignores `v.tangent` draws unchanged.
77
+ */
78
+ export const VERTEX_LAYOUT_3D_TANGENT = {
79
+ name: '3d-tangent',
80
+ positionOffset: 0,
81
+ floats: 16,
82
+ stride: 64,
83
+ buffer: {
84
+ arrayStride: 64,
85
+ stepMode: 'vertex',
86
+ attributes: [
87
+ { shaderLocation: 0, offset: 0, format: 'float32x3' },
88
+ { shaderLocation: 10, offset: 12, format: 'float32x3' },
89
+ { shaderLocation: 1, offset: 24, format: 'float32x2' },
90
+ { shaderLocation: 2, offset: 32, format: 'float32x4' },
91
+ { shaderLocation: 13, offset: 48, format: 'float32x4' },
92
+ ],
93
+ },
94
+ wgslFields: ` @location(0) pos: vec3f,
95
+ @location(10) normal: vec3f,
96
+ @location(1) uv: vec2f,
97
+ @location(2) color: vec4f,
98
+ @location(13) tangent: vec4f,`,
99
+ wgslPosition: 'v.pos',
100
+ wgslNormal: 'v.normal',
101
+ wgslTangent: 'v.tangent',
102
+ };
103
+ /** Floats of `VERTEX_LAYOUT_3D_UV2` (the 3D layout plus a second uv). */
104
+ export const VERTEX3D_UV2_FLOATS = 14;
105
+ export const VERTEX3D_UV2_STRIDE = VERTEX3D_UV2_FLOATS * 4;
106
+ /**
107
+ * Two-uv layout (ws/render-4): the 3D layout's 12 floats followed by `uv1: vec2f` at
108
+ * `@location(14)` (glTF `TEXCOORD_1`, the usual home of a light or occlusion map): 14 floats,
109
+ * 56 bytes. The prelude carries it as `VSOut.uv1`; the standard material's maps pick it with
110
+ * `texCoord: 1`. Materials that ignore it draw as with the 3D layout.
111
+ */
112
+ export const VERTEX_LAYOUT_3D_UV2 = {
113
+ name: '3d-uv2',
114
+ positionOffset: 0,
115
+ floats: VERTEX3D_UV2_FLOATS,
116
+ stride: VERTEX3D_UV2_STRIDE,
117
+ buffer: {
118
+ arrayStride: VERTEX3D_UV2_STRIDE,
119
+ stepMode: 'vertex',
120
+ attributes: [
121
+ { shaderLocation: 0, offset: 0, format: 'float32x3' },
122
+ { shaderLocation: 10, offset: 12, format: 'float32x3' },
123
+ { shaderLocation: 1, offset: 24, format: 'float32x2' },
124
+ { shaderLocation: 2, offset: 32, format: 'float32x4' },
125
+ { shaderLocation: 14, offset: 48, format: 'float32x2' },
126
+ ],
127
+ },
128
+ wgslFields: ` @location(0) pos: vec3f,
129
+ @location(10) normal: vec3f,
130
+ @location(1) uv: vec2f,
131
+ @location(2) color: vec4f,
132
+ @location(14) uv1: vec2f,`,
133
+ wgslPosition: 'v.pos',
134
+ wgslNormal: 'v.normal',
135
+ wgslUv1: 'v.uv1',
136
+ };
137
+ /**
138
+ * Skinned layout: the 3D layout's 12 floats followed by four joint indices (`uint8x4`, read as
139
+ * `vec4u`) and four weights (`unorm8x4`, read as `vec4f`), 8 bytes that occupy the slots of
140
+ * floats 12 and 13: 14 "floats" (`VERTEX_SKINNED_FLOATS`), 56 bytes per vertex. Write the
141
+ * joints and weights through a byte view of the vertex buffer (`setVertexSkin` in `skin.ts`),
142
+ * not as floats (a packed value may be a NaN pattern). `materialPrelude` applies the four
143
+ * weighted joint matrices from the material's `SkinPalette` before the instance matrix.
144
+ */
145
+ export const VERTEX_SKINNED_FLOATS = 14;
146
+ export const VERTEX_SKINNED_STRIDE = VERTEX_SKINNED_FLOATS * 4;
147
+ /** Byte offset of the four joint indices inside a skinned vertex. */
148
+ export const SKIN_JOINTS_BYTE_OFFSET = 48;
149
+ /** Byte offset of the four weights (unorm8) inside a skinned vertex. */
150
+ export const SKIN_WEIGHTS_BYTE_OFFSET = 52;
151
+ /** The skinned layout's buffer layout: the 3D attributes, joints at 11 and weights at 12. */
152
+ export const VERTEX_SKINNED_BUFFER_LAYOUT = {
153
+ arrayStride: VERTEX_SKINNED_STRIDE,
154
+ stepMode: 'vertex',
155
+ attributes: [
156
+ { shaderLocation: 0, offset: 0, format: 'float32x3' },
157
+ { shaderLocation: 10, offset: 12, format: 'float32x3' },
158
+ { shaderLocation: 1, offset: 24, format: 'float32x2' },
159
+ { shaderLocation: 2, offset: 32, format: 'float32x4' },
160
+ { shaderLocation: 11, offset: SKIN_JOINTS_BYTE_OFFSET, format: 'uint8x4' },
161
+ { shaderLocation: 12, offset: SKIN_WEIGHTS_BYTE_OFFSET, format: 'unorm8x4' },
162
+ ],
163
+ };
164
+ /**
165
+ * Skinned layout: `v.pos`, `v.normal`, `v.uv`, `v.color` as in 3D plus `v.joints: vec4u` and
166
+ * `v.weights: vec4f`. The prelude's `engine_local_position` / `engine_local_normal` return the
167
+ * skinned position and normal (`engine_skin`), so `engine_vertex` and every material work
168
+ * unchanged. The instance's palette slot travels in `params.w` (see `skin.ts`).
169
+ */
170
+ export const VERTEX_LAYOUT_SKINNED = {
171
+ name: 'skinned',
172
+ positionOffset: 0,
173
+ floats: VERTEX_SKINNED_FLOATS,
174
+ stride: VERTEX_SKINNED_STRIDE,
175
+ buffer: VERTEX_SKINNED_BUFFER_LAYOUT,
176
+ wgslFields: ` @location(0) pos: vec3f,
177
+ @location(10) normal: vec3f,
178
+ @location(1) uv: vec2f,
179
+ @location(2) color: vec4f,
180
+ @location(11) joints: vec4u,
181
+ @location(12) weights: vec4f,`,
182
+ wgslPosition: 'engine_skin(v, v.pos, v.normal).position',
183
+ wgslNormal: 'engine_skin(v, v.pos, v.normal).normal',
184
+ wgslPreviousPosition: 'engine_skin_previous(v, v.pos)',
185
+ skinned: true,
186
+ };
187
+ /** Capacity (vertices) up to which `MeshDesc.autoBounds` defaults to on. */
188
+ export const AUTO_BOUNDS_MAX_VERTICES = 65536;
189
+ /** 1.5× growth, like a vector: amortised reallocations when a streamed mesh keeps growing. */
190
+ const GROWTH = 1.5;
191
+ export class Mesh {
192
+ device;
193
+ label;
194
+ /** Vertex layout of this mesh's buffer; pipelines are keyed by (material, layout). */
195
+ layout;
196
+ vertexBuffer;
197
+ indexBuffer = null;
198
+ indexFormat = 'uint16';
199
+ /** Vertices drawn (non-indexed) and uploaded by the last `update`. */
200
+ vertexCount = 0;
201
+ /**
202
+ * Indices drawn (`drawIndexed`) when > 0. With an index buffer and `indexCount` 0 the renderer
203
+ * skips the draw entirely (no non-indexed fallback, no draw call, nothing in
204
+ * `RenderStats`), so `update({ indexCount: 0 })` empties the mesh.
205
+ */
206
+ indexCount = 0;
207
+ /**
208
+ * Buffers reallocated so far, by `update()` exceeding `capacity` or changing the index format.
209
+ * A caller that caches `vertexBuffer`/`indexBuffer` (a drawable, a bind group) re-reads them
210
+ * when this changes.
211
+ */
212
+ growths = 0;
213
+ /**
214
+ * Bounding sphere in mesh space (the renderer carries it through each draw's instance matrix
215
+ * and culls against `camera.frustum`). From `MeshDesc.bounds`, `MeshUpdate.bounds` or, with
216
+ * `autoBounds`, the positions; `radius` Infinity when unknown (never culled). The object is
217
+ * owned by the mesh; read it, set it through `update({ bounds })`.
218
+ */
219
+ bounds = { center: [0, 0, 0], radius: Number.POSITIVE_INFINITY };
220
+ /** Whether `update()` recomputes `bounds` from uploaded vertices (`MeshDesc.autoBounds`). */
221
+ autoBounds;
222
+ /** Named index ranges from `MeshDesc.ranges`; storage only, the renderer never reads it. */
223
+ ranges;
224
+ /** The layout's position attribute (location 0) has a z component. */
225
+ pos3;
226
+ cap = { vertices: 0, indices: 0 };
227
+ /** 4-byte scratch for the last index of an odd uint16 count at the end of its buffer. */
228
+ tail16 = new Uint16Array(2);
229
+ constructor(device, desc) {
230
+ this.device = device;
231
+ this.label = desc.label ?? 'mesh';
232
+ this.layout = desc.layout ?? VERTEX_LAYOUT_2D;
233
+ const vCount = desc.vertices ? desc.vertices.length / this.layout.floats : 0;
234
+ this.cap.vertices = Math.max(vCount, desc.capacity?.vertices ?? 0, 1);
235
+ this.autoBounds = desc.autoBounds ?? this.cap.vertices < AUTO_BOUNDS_MAX_VERTICES;
236
+ this.ranges = desc.ranges;
237
+ this.pos3 = positionHasZ(this.layout);
238
+ this.vertexBuffer = this.makeVertexBuffer(this.cap.vertices);
239
+ const iCap = Math.max(desc.indices?.length ?? 0, desc.capacity?.indices ?? 0);
240
+ if (iCap > 0) {
241
+ this.indexFormat =
242
+ desc.indexFormat ??
243
+ (desc.indices ? formatOf(desc.indices) : this.cap.vertices > 0xffff ? 'uint32' : 'uint16');
244
+ this.cap.indices = iCap;
245
+ this.indexBuffer = this.makeIndexBuffer(iCap);
246
+ }
247
+ if (desc.vertices || desc.indices || desc.bounds) {
248
+ this.update({ vertices: desc.vertices, indices: desc.indices, bounds: desc.bounds });
249
+ }
250
+ }
251
+ /** Room in the buffers (vertices, indices); `indices` is 0 for a non-indexed mesh. */
252
+ get capacity() {
253
+ return this.cap;
254
+ }
255
+ /**
256
+ * Replace geometry (`MeshUpdate`). Writes with `queue.writeBuffer` straight from each view's
257
+ * buffer and reuses the GPU buffers while the counts fit `capacity`; grows them (1.5×) only
258
+ * when a count exceeds it or the index format changes. Returns true when a buffer was
259
+ * reallocated (`growths` counts them). `bounds` are copied when given, else recomputed from
260
+ * the uploaded positions when `autoBounds` is on (a `Float32Array` view is read in place;
261
+ * any other view type gets one over the same buffer). Allocation-free otherwise.
262
+ *
263
+ * A `MeshReply` (`{ buffer, vertexCount, indexCount?, bounds? }`, a Worker's message) is the
264
+ * same upload read straight out of the one transferred buffer; it allocates the two views.
265
+ */
266
+ update(u) {
267
+ if ('buffer' in u && u.buffer instanceof ArrayBuffer)
268
+ return this.updateFromReply(u);
269
+ return this.updateViews(u);
270
+ }
271
+ updateFromReply(r) {
272
+ const { stride } = this.layout;
273
+ const vBytes = r.vertexCount * stride;
274
+ const vertices = new Uint8Array(r.buffer, 0, vBytes);
275
+ let indices;
276
+ if (r.indexCount !== undefined) {
277
+ const bpi = this.indexFormat === 'uint32' ? 4 : 2;
278
+ const at = r.indexOffset ?? (vBytes + 3) & ~3;
279
+ indices = new Uint8Array(r.buffer, at, r.indexCount * bpi);
280
+ }
281
+ return this.updateViews({
282
+ vertices,
283
+ indices,
284
+ vertexCount: r.vertexCount,
285
+ // A reply without indices on an indexed mesh draws nothing until the next one.
286
+ indexCount: r.indexCount ?? (this.indexBuffer ? 0 : undefined),
287
+ bounds: r.bounds,
288
+ });
289
+ }
290
+ updateViews(u) {
291
+ let grew = false;
292
+ const { stride } = this.layout;
293
+ if (u.vertices) {
294
+ const count = u.vertexCount ?? Math.floor(u.vertices.byteLength / stride);
295
+ if (count > this.cap.vertices) {
296
+ this.vertexBuffer.destroy();
297
+ this.cap.vertices = Math.ceil(count * GROWTH);
298
+ this.vertexBuffer = this.makeVertexBuffer(this.cap.vertices);
299
+ grew = true;
300
+ }
301
+ this.vertexCount = count;
302
+ if (count > 0) {
303
+ this.device.queue.writeBuffer(this.vertexBuffer, 0, u.vertices.buffer, u.vertices.byteOffset, count * stride);
304
+ }
305
+ if (!u.bounds && this.autoBounds)
306
+ this.computeBounds(u.vertices, count);
307
+ }
308
+ else if (u.vertexCount !== undefined) {
309
+ this.vertexCount = Math.min(u.vertexCount, this.cap.vertices);
310
+ }
311
+ if (u.indices) {
312
+ const fmt = formatOf(u.indices, this.indexFormat);
313
+ const bpi = fmt === 'uint32' ? 4 : 2;
314
+ const count = u.indexCount ?? Math.floor(u.indices.byteLength / bpi);
315
+ if (!this.indexBuffer || count > this.cap.indices || fmt !== this.indexFormat) {
316
+ this.indexBuffer?.destroy();
317
+ this.cap.indices = Math.max(Math.ceil(count * GROWTH), 1);
318
+ this.indexFormat = fmt;
319
+ this.indexBuffer = this.makeIndexBuffer(this.cap.indices);
320
+ grew = true;
321
+ }
322
+ this.indexCount = count;
323
+ this.writeIndices(u.indices, count * bpi);
324
+ }
325
+ else if (u.indexCount !== undefined && this.indexBuffer) {
326
+ this.indexCount = Math.min(u.indexCount, this.cap.indices);
327
+ }
328
+ if (u.bounds) {
329
+ const b = this.bounds;
330
+ const c = u.bounds.center;
331
+ b.center[0] = c[0];
332
+ b.center[1] = c[1];
333
+ b.center[2] = c[2];
334
+ b.radius = u.bounds.radius;
335
+ }
336
+ if (grew)
337
+ this.growths++;
338
+ return grew;
339
+ }
340
+ /**
341
+ * Bounding sphere of the first `count` vertices of `view` in this layout: the centre of their
342
+ * axis-aligned box, the radius the farthest vertex from it. 2D positions have z = 0.
343
+ */
344
+ computeBounds(view, count) {
345
+ const b = this.bounds;
346
+ if (count === 0) {
347
+ b.center[0] = 0;
348
+ b.center[1] = 0;
349
+ b.center[2] = 0;
350
+ b.radius = 0;
351
+ return;
352
+ }
353
+ const floats = this.layout.floats;
354
+ const f = view instanceof Float32Array
355
+ ? view
356
+ : new Float32Array(view.buffer, view.byteOffset, count * floats);
357
+ const has3 = this.pos3;
358
+ let minX = Number.POSITIVE_INFINITY;
359
+ let minY = Number.POSITIVE_INFINITY;
360
+ let minZ = Number.POSITIVE_INFINITY;
361
+ let maxX = Number.NEGATIVE_INFINITY;
362
+ let maxY = Number.NEGATIVE_INFINITY;
363
+ let maxZ = Number.NEGATIVE_INFINITY;
364
+ const end = count * floats;
365
+ for (let o = 0; o < end; o += floats) {
366
+ const x = f[o];
367
+ const y = f[o + 1];
368
+ const z = has3 ? f[o + 2] : 0;
369
+ if (x < minX)
370
+ minX = x;
371
+ if (x > maxX)
372
+ maxX = x;
373
+ if (y < minY)
374
+ minY = y;
375
+ if (y > maxY)
376
+ maxY = y;
377
+ if (z < minZ)
378
+ minZ = z;
379
+ if (z > maxZ)
380
+ maxZ = z;
381
+ }
382
+ const cx = (minX + maxX) / 2;
383
+ const cy = (minY + maxY) / 2;
384
+ const cz = (minZ + maxZ) / 2;
385
+ let r2 = 0;
386
+ for (let o = 0; o < end; o += floats) {
387
+ const dx = f[o] - cx;
388
+ const dy = f[o + 1] - cy;
389
+ const dz = (has3 ? f[o + 2] : 0) - cz;
390
+ const d = dx * dx + dy * dy + dz * dz;
391
+ if (d > r2)
392
+ r2 = d;
393
+ }
394
+ b.center[0] = cx;
395
+ b.center[1] = cy;
396
+ b.center[2] = cz;
397
+ b.radius = Math.sqrt(r2);
398
+ }
399
+ /** `writeBuffer` wants 4-byte sizes and offsets; a uint16 count may be odd. */
400
+ writeIndices(view, bytes) {
401
+ if (bytes === 0)
402
+ return;
403
+ const ib = this.indexBuffer;
404
+ const { buffer, byteOffset } = view;
405
+ const even = bytes & ~3;
406
+ if (even === bytes) {
407
+ this.device.queue.writeBuffer(ib, 0, buffer, byteOffset, bytes);
408
+ return;
409
+ }
410
+ if (byteOffset + bytes + 2 <= buffer.byteLength) {
411
+ // Two bytes of slack after the data: upload them as padding.
412
+ this.device.queue.writeBuffer(ib, 0, buffer, byteOffset, bytes + 2);
413
+ return;
414
+ }
415
+ // The odd index ends its buffer: write the even prefix, then the last index via the scratch.
416
+ if (even > 0)
417
+ this.device.queue.writeBuffer(ib, 0, buffer, byteOffset, even);
418
+ const bytesView = new DataView(buffer, byteOffset + even, 2);
419
+ this.tail16[0] = bytesView.getUint16(0, true);
420
+ this.device.queue.writeBuffer(ib, even, this.tail16.buffer, 0, 4);
421
+ }
422
+ /** The `GPUVertexBufferLayout` of `layout` (buffer slot 0 of every pipeline drawing it). */
423
+ get vertexBufferLayout() {
424
+ return this.layout.buffer;
425
+ }
426
+ destroy() {
427
+ this.vertexBuffer.destroy();
428
+ this.indexBuffer?.destroy();
429
+ }
430
+ makeVertexBuffer(count) {
431
+ return this.device.createBuffer({
432
+ label: `${this.label}-vb`,
433
+ size: count * this.layout.stride,
434
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
435
+ });
436
+ }
437
+ makeIndexBuffer(count) {
438
+ const bytes = count * (this.indexFormat === 'uint32' ? 4 : 2);
439
+ return this.device.createBuffer({
440
+ label: `${this.label}-ib`,
441
+ size: Math.ceil(bytes / 4) * 4,
442
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
443
+ });
444
+ }
445
+ }
446
+ /** Does the layout's position attribute (shader location 0) carry three components? */
447
+ function positionHasZ(layout) {
448
+ for (const a of layout.buffer.attributes) {
449
+ if (a.shaderLocation === 0)
450
+ return a.format === 'float32x3' || a.format === 'float32x4';
451
+ }
452
+ return false;
453
+ }
454
+ /** Index format implied by a typed array; any other view keeps `fallback`. */
455
+ function formatOf(view, fallback = 'uint16') {
456
+ if (view instanceof Uint32Array)
457
+ return 'uint32';
458
+ if (view instanceof Uint16Array)
459
+ return 'uint16';
460
+ return fallback;
461
+ }
462
+ /** Unit quad centred on the origin (-0.5..0.5), uv (0,0) top-left, white. */
463
+ export function quadGeometry() {
464
+ // biome-ignore format: vertex table
465
+ const vertices = new Float32Array([
466
+ -0.5, -0.5, 0, 0, 1, 1, 1, 1,
467
+ 0.5, -0.5, 1, 0, 1, 1, 1, 1,
468
+ 0.5, 0.5, 1, 1, 1, 1, 1, 1,
469
+ -0.5, 0.5, 0, 1, 1, 1, 1, 1,
470
+ ]);
471
+ return { vertices, indices: new Uint16Array([0, 1, 2, 0, 2, 3]) };
472
+ }
@@ -0,0 +1,16 @@
1
+ import type { Texture } from './texture.js';
2
+ /** How `generateMipmaps` reduces a level: `'linear'` averages each 2×2 block, `'nearest'` keeps its top-left texel. */
3
+ export type MipFilter = 'linear' | 'nearest';
4
+ export interface GenerateMipmapsOptions {
5
+ /** Default `'linear'`. */
6
+ filter?: MipFilter;
7
+ }
8
+ /**
9
+ * Fill mip levels 1..`mipLevels - 1` of `texture` from level 0 on the GPU, each level rendered
10
+ * from the one above by a tiny blit pipeline (one per format and filter, cached per device).
11
+ * Arrays are handled layer by layer. The texture needs `TEXTURE_BINDING | RENDER_ATTACHMENT`
12
+ * usage and a renderable float format (e.g. `rgba8unorm`, `rgba8unorm-srgb`, `rgba16float`);
13
+ * sRGB textures average in linear space. One command buffer is submitted; a texture with one
14
+ * level is left as it is. Creation-time work: it allocates views and bind groups.
15
+ */
16
+ export declare function generateMipmaps(device: GPUDevice, texture: Texture, opts?: GenerateMipmapsOptions): void;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Fullscreen triangle; the fragment shader reads the level above with `textureLoad` (so any
3
+ * float format works, filterable or not) at twice its own pixel, clamped to the source size.
4
+ */
5
+ const MIPMAP_WGSL = /* wgsl */ `
6
+ @group(0) @binding(0) var src: texture_2d<f32>;
7
+
8
+ @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
9
+ let p = vec2f(f32((i << 1u) & 2u), f32(i & 2u));
10
+ return vec4f(p * 2.0 - 1.0, 0.0, 1.0);
11
+ }
12
+
13
+ fn at(p: vec2i) -> vec4f {
14
+ let last = vec2i(textureDimensions(src)) - 1;
15
+ return textureLoad(src, min(p, last), 0);
16
+ }
17
+
18
+ @fragment fn fs_linear(@builtin(position) pos: vec4f) -> @location(0) vec4f {
19
+ let p = vec2i(floor(pos.xy)) * 2;
20
+ return 0.25 * (at(p) + at(p + vec2i(1, 0)) + at(p + vec2i(0, 1)) + at(p + vec2i(1, 1)));
21
+ }
22
+
23
+ @fragment fn fs_nearest(@builtin(position) pos: vec4f) -> @location(0) vec4f {
24
+ return at(vec2i(floor(pos.xy)) * 2);
25
+ }
26
+ `;
27
+ const kits = new WeakMap();
28
+ function kitFor(device) {
29
+ let kit = kits.get(device);
30
+ if (!kit) {
31
+ const layout = device.createBindGroupLayout({
32
+ label: 'mipmap-layout',
33
+ entries: [
34
+ {
35
+ binding: 0,
36
+ visibility: GPUShaderStage.FRAGMENT,
37
+ texture: { sampleType: 'unfilterable-float' },
38
+ },
39
+ ],
40
+ });
41
+ kit = {
42
+ module: device.createShaderModule({ label: 'mipmap', code: MIPMAP_WGSL }),
43
+ layout,
44
+ pipelineLayout: device.createPipelineLayout({
45
+ label: 'mipmap-pipeline-layout',
46
+ bindGroupLayouts: [layout],
47
+ }),
48
+ pipelines: new Map(),
49
+ };
50
+ kits.set(device, kit);
51
+ }
52
+ return kit;
53
+ }
54
+ /** The blit pipeline for `format` and `filter`: built once per device, then cached. */
55
+ function pipelineFor(device, format, filter) {
56
+ const kit = kitFor(device);
57
+ const key = `${format}:${filter}`;
58
+ let pipeline = kit.pipelines.get(key);
59
+ if (!pipeline) {
60
+ pipeline = device.createRenderPipeline({
61
+ label: `mipmap:${key}`,
62
+ layout: kit.pipelineLayout,
63
+ vertex: { module: kit.module, entryPoint: 'vs' },
64
+ fragment: {
65
+ module: kit.module,
66
+ entryPoint: filter === 'nearest' ? 'fs_nearest' : 'fs_linear',
67
+ targets: [{ format }],
68
+ },
69
+ primitive: { topology: 'triangle-list' },
70
+ });
71
+ kit.pipelines.set(key, pipeline);
72
+ }
73
+ return { pipeline, layout: kit.layout };
74
+ }
75
+ /**
76
+ * Fill mip levels 1..`mipLevels - 1` of `texture` from level 0 on the GPU, each level rendered
77
+ * from the one above by a tiny blit pipeline (one per format and filter, cached per device).
78
+ * Arrays are handled layer by layer. The texture needs `TEXTURE_BINDING | RENDER_ATTACHMENT`
79
+ * usage and a renderable float format (e.g. `rgba8unorm`, `rgba8unorm-srgb`, `rgba16float`);
80
+ * sRGB textures average in linear space. One command buffer is submitted; a texture with one
81
+ * level is left as it is. Creation-time work: it allocates views and bind groups.
82
+ */
83
+ export function generateMipmaps(device, texture, opts = {}) {
84
+ if (texture.mipLevels <= 1)
85
+ return;
86
+ const need = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
87
+ if ((texture.texture.usage & need) !== need) {
88
+ throw new Error(`generateMipmaps: ${texture.texture.label || 'texture'} needs TEXTURE_BINDING | RENDER_ATTACHMENT usage`);
89
+ }
90
+ const { pipeline, layout } = pipelineFor(device, texture.format, opts.filter ?? 'linear');
91
+ const encoder = device.createCommandEncoder({ label: 'mipmap' });
92
+ const view = (level, layer) => texture.texture.createView({
93
+ label: `mipmap:${level}:${layer}`,
94
+ dimension: '2d',
95
+ baseMipLevel: level,
96
+ mipLevelCount: 1,
97
+ baseArrayLayer: layer,
98
+ arrayLayerCount: 1,
99
+ });
100
+ for (let layer = 0; layer < texture.layers; layer++) {
101
+ let src = view(0, layer);
102
+ for (let level = 1; level < texture.mipLevels; level++) {
103
+ const dst = view(level, layer);
104
+ const group = device.createBindGroup({
105
+ label: `mipmap:${level}:${layer}`,
106
+ layout,
107
+ entries: [{ binding: 0, resource: src }],
108
+ });
109
+ const pass = encoder.beginRenderPass({
110
+ label: `mipmap:${level}:${layer}`,
111
+ colorAttachments: [{ view: dst, loadOp: 'clear', storeOp: 'store' }],
112
+ });
113
+ pass.setPipeline(pipeline);
114
+ pass.setBindGroup(0, group);
115
+ pass.draw(3);
116
+ pass.end();
117
+ src = dst;
118
+ }
119
+ }
120
+ device.queue.submit([encoder.finish()]);
121
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Parallax (ws/ergo-2d-2): tile layers that scroll at a fraction of the camera. `update` moves
3
+ * each layer's `origin` to `base + camera × (1 - factor)`, so a layer with factor 0 is pinned to
4
+ * the screen and one with factor 1 moves with the world; a layer with a `wrapW` / `wrapH`
5
+ * pattern period is kept within one period of the camera instead (the origin stays in
6
+ * `camera - wrap .. camera`), so a short repeating strip covers any scroll distance. `draw`
7
+ * draws the layers in order, far to near. No allocation per frame.
8
+ */
9
+ import type { Frame, InstanceParams } from './frame.js';
10
+ import type { Renderer } from './renderer.js';
11
+ import type { TileLayer } from './tile-layer.js';
12
+ export interface ParallaxLayerOptions {
13
+ layer: TileLayer;
14
+ /** 0 pins the layer to the view, 1 moves it with the world. */
15
+ factorX: number;
16
+ factorY: number;
17
+ /** Pattern period in px: the layer wraps every `wrapW` along x (default none). */
18
+ wrapW?: number;
19
+ wrapH?: number;
20
+ /** Per-layer draw params (tint, order, layers), passed to `TileLayer.draw`. */
21
+ params?: InstanceParams;
22
+ }
23
+ export interface ParallaxLayer extends ParallaxLayerOptions {
24
+ /** The layer's `origin` when the parallax was made: where it sits at camera `(0, 0)`. */
25
+ readonly baseX: number;
26
+ readonly baseY: number;
27
+ /** Offset `update` last added to the base (`camera × (1 - factor)`, wrapped). */
28
+ readonly offsetX: number;
29
+ readonly offsetY: number;
30
+ }
31
+ export interface Parallax {
32
+ /** The layers, in draw order. */
33
+ readonly layers: readonly ParallaxLayer[];
34
+ /**
35
+ * Aim every layer for a view whose top-left is `(cameraX, cameraY)` (an ortho2d `Camera`'s
36
+ * `x`, `y`): writes each layer's `origin`.
37
+ */
38
+ update(cameraX: number, cameraY: number): void;
39
+ /** `layer.draw(frame, params)` for each layer in order. */
40
+ draw(frame: Frame): void;
41
+ /** Destroys every layer. */
42
+ destroy(): void;
43
+ }
44
+ /** Wrapped parallax offset: `camera - (camera × factor mod wrap)`, in `camera - wrap .. camera`. */
45
+ export declare function parallaxOffset(camera: number, factor: number, wrap?: number): number;
46
+ /**
47
+ * Make a `Parallax` over layers built on `renderer`. Each layer's `origin` at this moment is its
48
+ * base position. Allocates once.
49
+ */
50
+ export declare function createParallax(_renderer: Renderer, layers: ParallaxLayerOptions[]): Parallax;