@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,204 @@
1
+ /**
2
+ * Test-only fake WebGPU device. It records resource creation, queue writes and pass commands,
3
+ * and applies the validation rules the engine has tripped over before (e.g. `writeBuffer`
4
+ * into a buffer without `COPY_DST`). Buffers hold their bytes: `writeBuffer` stores them,
5
+ * `copyBufferToBuffer`, `clearBuffer` and `resolveQuerySet` apply at `queue.submit`, and a
6
+ * `MAP_READ` buffer maps them back (ws/render-9). Not exported from `@thunderclap-engine/engine/render`;
7
+ * tests import it from `@thunderclap-engine/engine/testing`.
8
+ */
9
+ /** Install the WebGPU flag globals (`GPUBufferUsage` …) when running outside a browser. */
10
+ export declare function installGpuGlobals(): void;
11
+ /**
12
+ * What the fake throws for a usage-flag mistake a real device rejects (a missing `COPY_SRC`,
13
+ * `COPY_DST`, `MAP_READ`, `MAP_WRITE` or `QUERY_RESOLVE`), named like WebGPU's
14
+ * `GPUValidationError` (ws/render-9). The message is also pushed to `FakeDevice.errors`.
15
+ */
16
+ export declare class FakeGpuValidationError extends Error {
17
+ readonly name = "GPUValidationError";
18
+ }
19
+ export interface FakeBuffer {
20
+ label?: string;
21
+ size: number;
22
+ usage: number;
23
+ destroyed: boolean;
24
+ /** As `GPUBuffer.mapState`. */
25
+ readonly mapState: GPUBufferMapState;
26
+ /**
27
+ * The buffer's bytes (`size` long, zeroed, made on first use). `writeBuffer` fills them and a
28
+ * submitted copy moves them; a test writes here to stand in for what a shader would write.
29
+ */
30
+ readonly data: Uint8Array;
31
+ /**
32
+ * As `GPUBuffer.mapAsync`: throws `FakeGpuValidationError` without `MAP_READ` (mode `READ`)
33
+ * or `MAP_WRITE` (mode `WRITE`); rejects when the buffer is not unmapped. Resolves a
34
+ * microtask later, by when every copy submitted before it has landed.
35
+ */
36
+ mapAsync(mode: number, offset?: number, size?: number): Promise<void>;
37
+ /** A copy of the mapped bytes; `unmap` detaches it (a `WRITE` map's range is written back). */
38
+ getMappedRange(offset?: number, size?: number): ArrayBuffer;
39
+ unmap(): void;
40
+ destroy(): void;
41
+ }
42
+ /** A fake `GPUQuerySet`: `values` is what `resolveQuerySet` writes (a test fills it). */
43
+ export interface FakeQuerySet {
44
+ label?: string;
45
+ type: GPUQueryType;
46
+ count: number;
47
+ readonly values: BigUint64Array;
48
+ destroyed: boolean;
49
+ destroy(): void;
50
+ }
51
+ /** One `copyBufferToBuffer`, as encoded. */
52
+ export interface FakeBufferCopy {
53
+ src: FakeBuffer;
54
+ srcOffset: number;
55
+ dst: FakeBuffer;
56
+ dstOffset: number;
57
+ size: number;
58
+ }
59
+ export interface FakeTexture {
60
+ label?: string;
61
+ width: number;
62
+ height: number;
63
+ format: GPUTextureFormat;
64
+ mipLevelCount: number;
65
+ usage: number;
66
+ destroyed: boolean;
67
+ createView(desc?: {
68
+ label?: string;
69
+ }): FakeView;
70
+ destroy(): void;
71
+ }
72
+ export interface FakeView {
73
+ texture: FakeTexture;
74
+ label?: string;
75
+ }
76
+ export interface FakeBindGroup {
77
+ label?: string;
78
+ layout: {
79
+ label?: string;
80
+ entries: GPUBindGroupLayoutEntry[];
81
+ };
82
+ entries: GPUBindGroupEntry[];
83
+ }
84
+ export type PassCommand = {
85
+ op: 'setPipeline';
86
+ pipeline: unknown;
87
+ } | {
88
+ op: 'setBindGroup';
89
+ index: number;
90
+ group: unknown;
91
+ offsets: number[];
92
+ } | {
93
+ op: 'draw';
94
+ vertices: number;
95
+ instances: number;
96
+ firstInstance: number;
97
+ } | {
98
+ op: 'drawIndexed';
99
+ indices: number;
100
+ instances: number;
101
+ firstInstance: number;
102
+ /** Recorded when non-zero (an `InstanceParams.range` draw). */
103
+ firstIndex?: number;
104
+ } | {
105
+ op: 'dispatch';
106
+ x: number;
107
+ y: number;
108
+ } | {
109
+ op: 'other';
110
+ name: string;
111
+ args?: number[];
112
+ slot?: number;
113
+ buffer?: unknown;
114
+ /** `setVertexBuffer`'s byte offset, recorded when passed. */
115
+ offset?: number;
116
+ };
117
+ export interface FakePass {
118
+ kind: 'render' | 'compute';
119
+ label?: string;
120
+ desc: unknown;
121
+ commands: PassCommand[];
122
+ }
123
+ export interface FakeDevice {
124
+ /** Cast to `GPUDevice` for engine constructors. */
125
+ readonly device: GPUDevice;
126
+ readonly buffers: FakeBuffer[];
127
+ readonly textures: FakeTexture[];
128
+ readonly bindGroups: FakeBindGroup[];
129
+ readonly writes: {
130
+ buffer: FakeBuffer;
131
+ offset: number;
132
+ bytes: number;
133
+ }[];
134
+ /**
135
+ * The source of each `writes` entry, index for index: the caller's data (live, not a copy)
136
+ * and its `dataOffset` (bytes for an `ArrayBuffer`, elements for a typed array).
137
+ */
138
+ readonly writeData: {
139
+ data: ArrayBuffer | ArrayBufferView;
140
+ dataOffset: number;
141
+ }[];
142
+ readonly textureWrites: {
143
+ texture: FakeTexture;
144
+ bytesPerRow: number;
145
+ /** `rowsPerImage` of the layout (0 when not given). */
146
+ rowsPerImage: number;
147
+ /** The destination mip level (0 when not given). */
148
+ mipLevel: number;
149
+ size: number[];
150
+ data: ArrayBufferView | ArrayBuffer;
151
+ }[];
152
+ readonly passes: FakePass[];
153
+ /**
154
+ * `copyTextureToTexture` calls (ws/render-hooks): source, destination and how many passes
155
+ * had been begun when the copy was encoded, so a test can place it between two passes.
156
+ */
157
+ readonly textureCopies: {
158
+ src: FakeTexture;
159
+ dst: FakeTexture;
160
+ afterPasses: number;
161
+ }[];
162
+ /** `copyBufferToBuffer` calls in encoding order (ws/render-9); the bytes move at submit. */
163
+ readonly bufferCopies: FakeBufferCopy[];
164
+ readonly querySets: FakeQuerySet[];
165
+ /** `queue.submit` calls so far. */
166
+ readonly submits: number;
167
+ /**
168
+ * Stands in for the shaders (ws/render-9): called with each render or compute pass when its
169
+ * command buffer is submitted, in order with the encoder's copies and clears, so a test can
170
+ * write what a dispatch would into a buffer's `data`. Null (default): passes change nothing.
171
+ */
172
+ runPass: ((pass: FakePass) => void) | null;
173
+ /** Validation errors that a real device would raise. */
174
+ readonly errors: string[];
175
+ /**
176
+ * `device.lost` (ws/testing-2): pending until `loseDevice` or `device.destroy()` resolves it
177
+ * once with a `GPUDeviceLostInfo`, as a real device's does. The same promise as `device.lost`.
178
+ */
179
+ readonly lost: Promise<GPUDeviceLostInfo>;
180
+ /**
181
+ * Simulate a device loss (ws/testing-2): resolve `lost` with `{ reason, message }`. Default
182
+ * reason `'unknown'` (a driver crash or reset); `'destroyed'` is what `device.destroy()` sends,
183
+ * which the engine treats as no loss. Only the first loss counts; later calls do nothing.
184
+ */
185
+ loseDevice(reason?: GPUDeviceLostReason, message?: string): void;
186
+ }
187
+ /**
188
+ * Create a fake device. `limits` overrides defaults (e.g. `minUniformBufferOffsetAlignment`);
189
+ * `features` is its feature set (`device.features`, empty by default).
190
+ */
191
+ export declare function createFakeDevice(limits?: Partial<Record<string, number>>, features?: Iterable<string>): FakeDevice;
192
+ /** `{ device, context, format }` for `new Renderer(...)` on a fake device. */
193
+ export declare function fakeRendererGpu(fake: FakeDevice): {
194
+ device: GPUDevice;
195
+ context: GPUCanvasContext;
196
+ format: GPUTextureFormat;
197
+ };
198
+ /** A fake canvas context good enough for `new Renderer(...)`. */
199
+ export declare function fakeCanvasContext(fake: FakeDevice): GPUCanvasContext;
200
+ /**
201
+ * `renderer.sceneTargets` for a stub renderer in a drawable's unit test (ws/render-10): the
202
+ * same lists a real renderer hands out, without one.
203
+ */
204
+ export declare function fakeSceneTargets(blend?: GPUBlendState, aux?: number): GPUColorTargetState[];
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Test-only fake WebGPU device. It records resource creation, queue writes and pass commands,
3
+ * and applies the validation rules the engine has tripped over before (e.g. `writeBuffer`
4
+ * into a buffer without `COPY_DST`). Buffers hold their bytes: `writeBuffer` stores them,
5
+ * `copyBufferToBuffer`, `clearBuffer` and `resolveQuerySet` apply at `queue.submit`, and a
6
+ * `MAP_READ` buffer maps them back (ws/render-9). Not exported from `@thunderclap-engine/engine/render`;
7
+ * tests import it from `@thunderclap-engine/engine/testing`.
8
+ */
9
+ import { sceneColorTargets } from './material.js';
10
+ const BUFFER_USAGE = {
11
+ MAP_READ: 0x0001,
12
+ MAP_WRITE: 0x0002,
13
+ COPY_SRC: 0x0004,
14
+ COPY_DST: 0x0008,
15
+ INDEX: 0x0010,
16
+ VERTEX: 0x0020,
17
+ UNIFORM: 0x0040,
18
+ STORAGE: 0x0080,
19
+ INDIRECT: 0x0100,
20
+ QUERY_RESOLVE: 0x0200,
21
+ };
22
+ const TEXTURE_USAGE = {
23
+ COPY_SRC: 0x01,
24
+ COPY_DST: 0x02,
25
+ TEXTURE_BINDING: 0x04,
26
+ STORAGE_BINDING: 0x08,
27
+ RENDER_ATTACHMENT: 0x10,
28
+ };
29
+ const SHADER_STAGE = { VERTEX: 0x1, FRAGMENT: 0x2, COMPUTE: 0x4 };
30
+ const MAP_MODE = { READ: 0x1, WRITE: 0x2 };
31
+ /** Install the WebGPU flag globals (`GPUBufferUsage` …) when running outside a browser. */
32
+ export function installGpuGlobals() {
33
+ const g = globalThis;
34
+ g.GPUBufferUsage ??= BUFFER_USAGE;
35
+ g.GPUTextureUsage ??= TEXTURE_USAGE;
36
+ g.GPUShaderStage ??= SHADER_STAGE;
37
+ g.GPUMapMode ??= MAP_MODE;
38
+ }
39
+ /**
40
+ * What the fake throws for a usage-flag mistake a real device rejects (a missing `COPY_SRC`,
41
+ * `COPY_DST`, `MAP_READ`, `MAP_WRITE` or `QUERY_RESOLVE`), named like WebGPU's
42
+ * `GPUValidationError` (ws/render-9). The message is also pushed to `FakeDevice.errors`.
43
+ */
44
+ export class FakeGpuValidationError extends Error {
45
+ name = 'GPUValidationError';
46
+ }
47
+ /** Byte view of `writeBuffer`'s source: `dataOffset`/`dataSize` are elements for a typed array. */
48
+ function sourceBytes(data, dataOffset, dataSize) {
49
+ if (ArrayBuffer.isView(data)) {
50
+ const bpe = data.BYTES_PER_ELEMENT ?? 1;
51
+ const n = dataSize ?? data.byteLength / bpe - dataOffset;
52
+ return new Uint8Array(data.buffer, data.byteOffset + dataOffset * bpe, n * bpe);
53
+ }
54
+ return new Uint8Array(data, dataOffset, dataSize ?? data.byteLength - dataOffset);
55
+ }
56
+ /**
57
+ * Create a fake device. `limits` overrides defaults (e.g. `minUniformBufferOffsetAlignment`);
58
+ * `features` is its feature set (`device.features`, empty by default).
59
+ */
60
+ export function createFakeDevice(limits = {}, features = []) {
61
+ installGpuGlobals();
62
+ const buffers = [];
63
+ const textures = [];
64
+ const bindGroups = [];
65
+ const writes = [];
66
+ const writeData = [];
67
+ const textureWrites = [];
68
+ const passes = [];
69
+ const textureCopies = [];
70
+ const bufferCopies = [];
71
+ const querySets = [];
72
+ const errors = [];
73
+ let submits = 0;
74
+ let resolveLost = null;
75
+ const lost = new Promise((resolve) => {
76
+ resolveLost = resolve;
77
+ });
78
+ const loseDevice = (reason = 'unknown', message = 'fake device lost') => {
79
+ const resolve = resolveLost;
80
+ resolveLost = null;
81
+ resolve?.({ reason, message });
82
+ };
83
+ /** Record and throw a usage-flag error, as a real device rejects it. */
84
+ const needs = (b, flag, where) => {
85
+ if (b.usage & BUFFER_USAGE[flag])
86
+ return;
87
+ const msg = `${where}: ${b.label} lacks ${flag}`;
88
+ errors.push(msg);
89
+ throw new FakeGpuValidationError(msg);
90
+ };
91
+ const makeBuffer = (desc) => {
92
+ let bytes = null;
93
+ let state = 'unmapped';
94
+ let mapMode = 0;
95
+ /** Bumped by every unmap, so a map pending across one rejects. */
96
+ let epoch = 0;
97
+ const ranges = [];
98
+ const store = () => {
99
+ bytes ??= new Uint8Array(desc.size);
100
+ return bytes;
101
+ };
102
+ const unmap = () => {
103
+ if (mapMode === MAP_MODE.WRITE) {
104
+ for (const r of ranges)
105
+ store().set(new Uint8Array(r.ab), r.offset);
106
+ }
107
+ // Detach every range handed out, as a real unmap does.
108
+ for (const r of ranges)
109
+ structuredClone(r.ab, { transfer: [r.ab] });
110
+ ranges.length = 0;
111
+ state = 'unmapped';
112
+ mapMode = 0;
113
+ epoch++;
114
+ };
115
+ if (desc.mappedAtCreation) {
116
+ state = 'mapped';
117
+ mapMode = MAP_MODE.WRITE;
118
+ }
119
+ const b = {
120
+ label: desc.label,
121
+ size: desc.size,
122
+ usage: desc.usage,
123
+ destroyed: false,
124
+ get mapState() {
125
+ return state;
126
+ },
127
+ get data() {
128
+ return store();
129
+ },
130
+ mapAsync(mode, offset = 0, size) {
131
+ if (mode & MAP_MODE.READ)
132
+ needs(b, 'MAP_READ', 'mapAsync');
133
+ if (mode & MAP_MODE.WRITE)
134
+ needs(b, 'MAP_WRITE', 'mapAsync');
135
+ const end = offset + (size ?? b.size - offset);
136
+ if (b.destroyed || state !== 'unmapped' || end > b.size) {
137
+ const why = b.destroyed ? 'destroyed' : state !== 'unmapped' ? state : 'out of range';
138
+ const msg = `mapAsync: ${b.label} is ${why}`;
139
+ errors.push(msg);
140
+ return Promise.reject(new Error(msg));
141
+ }
142
+ state = 'pending';
143
+ const at = epoch;
144
+ return Promise.resolve().then(() => {
145
+ if (epoch !== at || b.destroyed) {
146
+ throw new Error(`mapAsync: ${b.label} unmapped before it mapped`);
147
+ }
148
+ state = 'mapped';
149
+ mapMode = mode;
150
+ });
151
+ },
152
+ getMappedRange(offset = 0, size) {
153
+ const n = size ?? b.size - offset;
154
+ if (state !== 'mapped')
155
+ throw new Error(`getMappedRange: ${b.label} is ${state}`);
156
+ if (offset % 8 !== 0 || n % 4 !== 0 || offset + n > b.size) {
157
+ throw new Error(`getMappedRange: ${b.label} range ${offset}+${n} of ${b.size}`);
158
+ }
159
+ const ab = store().slice(offset, offset + n).buffer;
160
+ ranges.push({ ab, offset });
161
+ return ab;
162
+ },
163
+ unmap,
164
+ destroy() {
165
+ if (state !== 'unmapped')
166
+ unmap();
167
+ b.destroyed = true;
168
+ },
169
+ };
170
+ return b;
171
+ };
172
+ const runOps = (ops) => {
173
+ for (const o of ops) {
174
+ if (o.op === 'copy') {
175
+ const c = o.copy;
176
+ for (const x of [c.src, c.dst]) {
177
+ if (x.mapState !== 'unmapped')
178
+ errors.push(`submit: ${x.label} is ${x.mapState}`);
179
+ if (x.destroyed)
180
+ errors.push(`submit: ${x.label} is destroyed`);
181
+ }
182
+ c.dst.data.set(c.src.data.subarray(c.srcOffset, c.srcOffset + c.size), c.dstOffset);
183
+ }
184
+ else if (o.op === 'pass') {
185
+ fake.runPass?.(o.pass);
186
+ }
187
+ else if (o.op === 'clear') {
188
+ o.buffer.data.fill(0, o.offset, o.offset + o.size);
189
+ }
190
+ else {
191
+ o.dst.data.set(new Uint8Array(o.set.values.buffer, o.first * 8, o.count * 8), o.offset);
192
+ }
193
+ }
194
+ };
195
+ const makePass = (ops, kind, desc) => {
196
+ const p = { kind, label: desc?.label, desc, commands: [] };
197
+ passes.push(p);
198
+ ops.push({ op: 'pass', pass: p });
199
+ const cmd = (c) => p.commands.push(c);
200
+ return {
201
+ setPipeline: (pipeline) => cmd({ op: 'setPipeline', pipeline }),
202
+ setBindGroup: (index, group, offsets) => cmd({ op: 'setBindGroup', index, group, offsets: offsets ? [...offsets] : [] }),
203
+ draw: (vertices, instances = 1, _fv = 0, firstInstance = 0) => cmd({ op: 'draw', vertices, instances, firstInstance }),
204
+ drawIndexed: (indices, instances = 1, firstIndex = 0, _bv = 0, firstInstance = 0) => cmd(firstIndex === 0
205
+ ? { op: 'drawIndexed', indices, instances, firstInstance }
206
+ : { op: 'drawIndexed', indices, instances, firstInstance, firstIndex }),
207
+ dispatchWorkgroups: (x, y = 1) => cmd({ op: 'dispatch', x, y }),
208
+ setVertexBuffer: (slot, buffer, offset) => cmd(offset === undefined
209
+ ? { op: 'other', name: 'setVertexBuffer', slot, buffer }
210
+ : { op: 'other', name: 'setVertexBuffer', slot, buffer, offset }),
211
+ setIndexBuffer: () => cmd({ op: 'other', name: 'setIndexBuffer' }),
212
+ setBlendConstant: () => cmd({ op: 'other', name: 'setBlendConstant' }),
213
+ setViewport: (...args) => cmd({ op: 'other', name: 'setViewport', args }),
214
+ setScissorRect: (...args) => cmd({ op: 'other', name: 'setScissorRect', args }),
215
+ end: () => cmd({ op: 'other', name: 'end' }),
216
+ };
217
+ };
218
+ const device = {
219
+ limits: { minUniformBufferOffsetAlignment: 256, maxUniformBufferBindingSize: 65536, ...limits },
220
+ features: new Set(features),
221
+ lost,
222
+ destroy: () => loseDevice('destroyed', 'device destroyed'),
223
+ addEventListener() { },
224
+ createBuffer(desc) {
225
+ const b = makeBuffer(desc);
226
+ buffers.push(b);
227
+ return b;
228
+ },
229
+ createQuerySet(desc) {
230
+ const q = {
231
+ label: desc.label,
232
+ type: desc.type,
233
+ count: desc.count,
234
+ values: new BigUint64Array(desc.count),
235
+ destroyed: false,
236
+ destroy() {
237
+ q.destroyed = true;
238
+ },
239
+ };
240
+ querySets.push(q);
241
+ return q;
242
+ },
243
+ createTexture(desc) {
244
+ const size = desc.size;
245
+ const t = {
246
+ label: desc.label,
247
+ width: size[0],
248
+ height: size[1] ?? 1,
249
+ format: desc.format,
250
+ mipLevelCount: desc.mipLevelCount ?? 1,
251
+ usage: desc.usage,
252
+ destroyed: false,
253
+ createView: (d) => ({ texture: t, label: d?.label }),
254
+ destroy() {
255
+ t.destroyed = true;
256
+ },
257
+ };
258
+ textures.push(t);
259
+ return t;
260
+ },
261
+ createSampler: (desc) => ({ label: desc?.label }),
262
+ createBindGroupLayout: (desc) => ({
263
+ label: desc.label,
264
+ entries: [...desc.entries],
265
+ }),
266
+ createPipelineLayout: (desc) => ({ ...desc }),
267
+ createBindGroup(desc) {
268
+ const g = {
269
+ label: desc.label,
270
+ layout: desc.layout,
271
+ entries: [...desc.entries],
272
+ };
273
+ bindGroups.push(g);
274
+ return g;
275
+ },
276
+ createShaderModule: (desc) => ({
277
+ label: desc.label,
278
+ code: desc.code,
279
+ getCompilationInfo: async () => ({ messages: [] }),
280
+ }),
281
+ createRenderPipeline: (desc) => ({ label: desc.label, desc }),
282
+ createComputePipeline: (desc) => ({ label: desc.label, desc }),
283
+ createCommandEncoder: (desc) => {
284
+ const ops = [];
285
+ return {
286
+ label: desc?.label,
287
+ beginRenderPass: (d) => makePass(ops, 'render', d),
288
+ beginComputePass: (d) => makePass(ops, 'compute', d),
289
+ copyTextureToTexture(src, dst) {
290
+ if (!(src.texture.usage & TEXTURE_USAGE.COPY_SRC)) {
291
+ errors.push(`copyTextureToTexture: ${src.texture.label} lacks COPY_SRC`);
292
+ }
293
+ if (!(dst.texture.usage & TEXTURE_USAGE.COPY_DST)) {
294
+ errors.push(`copyTextureToTexture: ${dst.texture.label} lacks COPY_DST`);
295
+ }
296
+ if (src.texture.format !== dst.texture.format) {
297
+ errors.push(`copyTextureToTexture: ${src.texture.label} → ${dst.texture.label} formats differ`);
298
+ }
299
+ textureCopies.push({ src: src.texture, dst: dst.texture, afterPasses: passes.length });
300
+ },
301
+ copyBufferToBuffer(src, a, b, c, d) {
302
+ // (src, srcOffset, dst, dstOffset, size?) or the short (src, dst, size?).
303
+ const short = typeof a === 'object';
304
+ const srcOffset = short ? 0 : a;
305
+ const dst = (short ? a : b);
306
+ const dstOffset = short ? 0 : (c ?? 0);
307
+ const size = (short ? b : d) ?? src.size - srcOffset;
308
+ needs(src, 'COPY_SRC', 'copyBufferToBuffer');
309
+ needs(dst, 'COPY_DST', 'copyBufferToBuffer');
310
+ if (src === dst)
311
+ errors.push(`copyBufferToBuffer: ${src.label} onto itself`);
312
+ if (srcOffset % 4 || dstOffset % 4 || size % 4) {
313
+ errors.push(`copyBufferToBuffer: ${src.label} → ${dst.label} not 4-byte aligned`);
314
+ }
315
+ if (srcOffset + size > src.size || dstOffset + size > dst.size) {
316
+ errors.push(`copyBufferToBuffer: ${src.label} → ${dst.label} out of range`);
317
+ return;
318
+ }
319
+ const copy = { src, srcOffset, dst, dstOffset, size };
320
+ bufferCopies.push(copy);
321
+ ops.push({ op: 'copy', copy });
322
+ },
323
+ clearBuffer(buffer, offset = 0, size) {
324
+ if (!(buffer.usage & BUFFER_USAGE.COPY_DST)) {
325
+ errors.push(`clearBuffer: ${buffer.label} lacks COPY_DST`);
326
+ }
327
+ ops.push({ op: 'clear', buffer, offset, size: size ?? buffer.size - offset });
328
+ },
329
+ resolveQuerySet(set, first, count, dst, offset) {
330
+ needs(dst, 'QUERY_RESOLVE', 'resolveQuerySet');
331
+ if (offset % 256)
332
+ errors.push(`resolveQuerySet: offset ${offset} not 256-aligned`);
333
+ if (first + count > set.count || offset + count * 8 > dst.size) {
334
+ errors.push(`resolveQuerySet: ${set.label} → ${dst.label} out of range`);
335
+ return;
336
+ }
337
+ ops.push({ op: 'resolve', set, first, count, dst, offset });
338
+ },
339
+ finish: () => ({ ops }),
340
+ };
341
+ },
342
+ queue: {
343
+ writeBuffer(buffer, offset, data, dataOffset, dataSize) {
344
+ needs(buffer, 'COPY_DST', 'writeBuffer');
345
+ if (buffer.destroyed)
346
+ errors.push(`writeBuffer: ${buffer.label} is destroyed`);
347
+ if (buffer.mapState !== 'unmapped') {
348
+ errors.push(`writeBuffer: ${buffer.label} is ${buffer.mapState}`);
349
+ }
350
+ const src = sourceBytes(data, dataOffset ?? 0, dataSize);
351
+ const size = src.byteLength;
352
+ if (offset + size > buffer.size) {
353
+ errors.push(`writeBuffer: ${buffer.label} overflow (${offset}+${size}>${buffer.size})`);
354
+ }
355
+ else {
356
+ buffer.data.set(src, offset);
357
+ }
358
+ writes.push({ buffer, offset, bytes: size });
359
+ writeData.push({ data, dataOffset: dataOffset ?? 0 });
360
+ },
361
+ writeTexture(dst, data, layout, size) {
362
+ if (!(dst.texture.usage & TEXTURE_USAGE.COPY_DST)) {
363
+ errors.push(`writeTexture: ${dst.texture.label} lacks COPY_DST`);
364
+ }
365
+ textureWrites.push({
366
+ texture: dst.texture,
367
+ bytesPerRow: layout.bytesPerRow ?? 0,
368
+ rowsPerImage: layout.rowsPerImage ?? 0,
369
+ mipLevel: dst.mipLevel ?? 0,
370
+ size,
371
+ data,
372
+ });
373
+ },
374
+ copyExternalImageToTexture() { },
375
+ submit(cmds) {
376
+ submits++;
377
+ for (const cb of cmds)
378
+ if (cb?.ops)
379
+ runOps(cb.ops);
380
+ },
381
+ onSubmittedWorkDone: () => Promise.resolve(),
382
+ },
383
+ };
384
+ const fake = {
385
+ device: device,
386
+ buffers,
387
+ textures,
388
+ bindGroups,
389
+ writes,
390
+ writeData,
391
+ textureWrites,
392
+ passes,
393
+ textureCopies,
394
+ bufferCopies,
395
+ querySets,
396
+ get submits() {
397
+ return submits;
398
+ },
399
+ runPass: null,
400
+ errors,
401
+ lost,
402
+ loseDevice,
403
+ };
404
+ return fake;
405
+ }
406
+ /** `{ device, context, format }` for `new Renderer(...)` on a fake device. */
407
+ export function fakeRendererGpu(fake) {
408
+ return { device: fake.device, context: fakeCanvasContext(fake), format: 'bgra8unorm' };
409
+ }
410
+ /** A fake canvas context good enough for `new Renderer(...)`. */
411
+ export function fakeCanvasContext(fake) {
412
+ const tex = fake.device.createTexture({
413
+ label: 'swapchain',
414
+ size: [1, 1],
415
+ format: 'bgra8unorm',
416
+ usage: TEXTURE_USAGE.RENDER_ATTACHMENT,
417
+ });
418
+ return { getCurrentTexture: () => tex };
419
+ }
420
+ /**
421
+ * `renderer.sceneTargets` for a stub renderer in a drawable's unit test (ws/render-10): the
422
+ * same lists a real renderer hands out, without one.
423
+ */
424
+ export function fakeSceneTargets(blend, aux = 0) {
425
+ return sceneColorTargets(['rgba16float', 'rgba16float'], aux, blend, false);
426
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Flipbook (ws/ergo-2d): frame timing over a list of texture sub-rectangles. Pure: no GPU, no
3
+ * allocation in `update`. A 2D game keeps one per animated sprite, calls `update(dt)` each tick
4
+ * and hands `uv` to its `DrawParams.uv`.
5
+ */
6
+ /** A sub-rectangle of a texture, `u0, v0, u1, v1` in 0..1 (what `DrawParams.uv` takes). */
7
+ export type UvRect = readonly [u0: number, v0: number, u1: number, v1: number];
8
+ export interface FlipbookOptions {
9
+ /** The frames, in play order. Must not be empty. */
10
+ frames: readonly UvRect[];
11
+ /** Frames per second. Default 12. */
12
+ fps?: number;
13
+ /** Wrap to the first frame after the last (default true); otherwise hold the last and set `done`. */
14
+ loop?: boolean;
15
+ }
16
+ export interface Flipbook {
17
+ /** The frames being played (`play(frames)` swaps them). */
18
+ readonly frames: readonly UvRect[];
19
+ /** Frames per second; settable. */
20
+ fps: number;
21
+ /** Whether the book wraps; settable. */
22
+ loop: boolean;
23
+ /** Advance by `dt` seconds. */
24
+ update(dt: number): void;
25
+ /** The current frame's rectangle. */
26
+ readonly uv: UvRect;
27
+ /** Index of the current frame. */
28
+ readonly frame: number;
29
+ /** True once a non-looping book has shown its last frame for a full frame time. */
30
+ readonly done: boolean;
31
+ /** Back to the first frame, time 0. */
32
+ reset(): void;
33
+ /** Restart from the first frame, optionally with another frame list. */
34
+ play(frames?: readonly UvRect[]): void;
35
+ }
36
+ /**
37
+ * A grid atlas for `atlasFrames`: `cols × rows` equal cells. `inset` (ws/api-render) pulls each
38
+ * rectangle in by that many texels on every side so linear filtering never samples the next
39
+ * cell (half a texel, 0.5, is the usual fix for bleeding); it needs the texture's `width` and
40
+ * `height` in texels. Default 0.
41
+ */
42
+ export interface AtlasGrid {
43
+ cols: number;
44
+ rows: number;
45
+ inset?: number;
46
+ width?: number;
47
+ height?: number;
48
+ }
49
+ /**
50
+ * The `UvRect`s of a grid atlas's cells, row-major from the top left (`cols × rows` cells); with
51
+ * `indices`, only those cells in that order. Throws when `inset` is set without `width` and
52
+ * `height`. Allocates: call it at load time.
53
+ */
54
+ export declare function atlasFrames(atlas: AtlasGrid, indices?: readonly number[]): UvRect[];
55
+ /** Make a `Flipbook` over `frames` at `fps`. */
56
+ export declare function createFlipbook(opts: FlipbookOptions): Flipbook;