@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,214 @@
1
+ /// <reference path="./xr-types.d.ts" preserve="true" />
2
+ /**
3
+ * The XR surface (ws/xr; ARCHITECTURE "Surface"): a `SceneTarget` per eye per frame. Built on
4
+ * the WebXR/WebGPU binding, it makes one `XRProjectionLayer` for the session (colour in
5
+ * `SCENE_FORMAT`, since every material's pipeline writes that format, plus a `DEPTH_FORMAT`
6
+ * depth texture) and each frame turns the viewer pose into `XrEyeView`s: a `Camera` whose
7
+ * projection and view matrices are the `XRView`'s (`viewIndex` = eye index, depth on) and a
8
+ * `SceneTarget` adopting the eye's part of the layer (`SceneTarget.external`). Eyes that share
9
+ * one layer texture (the default `texture` layout, side by side) share one target and differ by
10
+ * `camera.screen`, so the renderer clears it once and scissors each eye to its viewport; a
11
+ * `texture-array` layer gives each eye its own target over its array layer.
12
+ *
13
+ * Two ways to draw the eyes. Direct (the default): each eye is a scene pass into its layer
14
+ * target; the colour goes to the layer as linear HDR, the emissive target is written and
15
+ * dropped and no post stack runs. Through the post stack (`scene: true`, ws/xr-post, what
16
+ * `createGame` uses): the surface keeps `scene`, one HDR `SceneTarget` the size of an eye
17
+ * (allocated on the first frame, resized when the layer's eye size changes), every eye camera
18
+ * covers it whole and the caller renders each eye into it and resolves it into the eye's layer
19
+ * target at `eye.viewport` (`renderer.render(frame, eye.camera, surface.scene)` then
20
+ * `renderer.resolve(surface.scene, eye.target.color.view, eye.viewport)`), so the headset sees
21
+ * the same bloom, tone map and grade as the screen; the layer then takes `colorFormat`, the
22
+ * format the post stack writes (`renderer.format`), and no depth by default.
23
+ *
24
+ * `head` is a camera at the viewer pose with the first eye's projection, for the scenes' one
25
+ * `render(frame, camera, alpha)` call per frame.
26
+ */
27
+ import { Camera } from '../render/camera.js';
28
+ import { DEPTH_FORMAT } from '../render/material.js';
29
+ import { SCENE_FORMAT, SceneTarget, } from '../render/scene-target.js';
30
+ class EyeView {
31
+ index;
32
+ eye = 'none';
33
+ camera;
34
+ target;
35
+ viewport = { x: 0, y: 0, width: 0, height: 0 };
36
+ /** The array layer this eye reads through (0 for a plain texture). */
37
+ layer = 0;
38
+ /** This eye's own target, used unless an earlier eye already adopted the same texture. */
39
+ own;
40
+ constructor(index, device, first, aux) {
41
+ this.index = index;
42
+ this.camera = new Camera();
43
+ this.camera.depthTest = true;
44
+ this.camera.depthWrite = true;
45
+ this.camera.viewIndex = index;
46
+ this.own = SceneTarget.external({
47
+ device,
48
+ color: first.colorTexture,
49
+ depth: first.depthStencilTexture,
50
+ view: first.getViewDescriptor(),
51
+ label: `xr-eye-${index}`,
52
+ aux,
53
+ });
54
+ this.target = this.own;
55
+ }
56
+ }
57
+ export class XrSurface {
58
+ session;
59
+ device;
60
+ binding;
61
+ layer;
62
+ referenceSpace;
63
+ /**
64
+ * A camera at the viewer pose (between the eyes) with the first eye's projection, depth on,
65
+ * updated by `views`: what the scenes record through once per frame.
66
+ */
67
+ head = new Camera();
68
+ /**
69
+ * With `scene: true`, the eye-sized HDR target every eye renders into before `resolve`;
70
+ * made by the first `views` with a pose and resized when the eye size changes. Null before
71
+ * then, and always null for a direct surface.
72
+ */
73
+ scene = null;
74
+ eyes = [];
75
+ out = [];
76
+ viaScene;
77
+ /** `opts.aux`: on the scene target with `scene`, else on each eye target. */
78
+ aux;
79
+ destroyed = false;
80
+ /**
81
+ * Makes the session's projection layer and installs it (`session.updateRenderState`).
82
+ * Throws where the browser has no `XRGPUBinding`; check `XrSurface.supported()` first.
83
+ */
84
+ constructor(session, device, opts) {
85
+ this.session = session;
86
+ this.device = device;
87
+ const Binding = globalThis.XRGPUBinding;
88
+ if (!Binding)
89
+ throw new Error('XrSurface: this browser has no WebXR/WebGPU binding');
90
+ this.referenceSpace = opts.referenceSpace;
91
+ this.viaScene = opts.scene === true;
92
+ this.aux = opts.aux;
93
+ this.binding = new Binding(session, device);
94
+ const depth = opts.depthStencilFormat === undefined
95
+ ? this.viaScene
96
+ ? null
97
+ : DEPTH_FORMAT
98
+ : opts.depthStencilFormat;
99
+ this.layer = this.binding.createProjectionLayer({
100
+ colorFormat: opts.colorFormat ?? SCENE_FORMAT,
101
+ ...(depth ? { depthStencilFormat: depth } : {}),
102
+ textureType: opts.textureType ?? 'texture',
103
+ });
104
+ session.updateRenderState({
105
+ layers: [this.layer],
106
+ depthNear: opts.depthNear ?? 0.1,
107
+ depthFar: opts.depthFar ?? 1000,
108
+ });
109
+ this.head.depthTest = true;
110
+ this.head.depthWrite = true;
111
+ }
112
+ /** True where `XRGPUBinding` exists (the WebXR/WebGPU binding). */
113
+ static supported() {
114
+ return typeof globalThis.XRGPUBinding !== 'undefined';
115
+ }
116
+ /**
117
+ * The eyes of this frame, in viewer-pose order, each with its camera aimed and its target
118
+ * adopting the layer's texture for the frame. Empty when the pose is unavailable (tracking
119
+ * lost). The array and the views are reused; read them within the frame.
120
+ */
121
+ views(frame) {
122
+ const out = this.out;
123
+ out.length = 0;
124
+ if (this.destroyed)
125
+ return out;
126
+ const pose = frame.getViewerPose(this.referenceSpace);
127
+ if (!pose)
128
+ return out;
129
+ const views = pose.views;
130
+ for (let i = 0; i < views.length; i++) {
131
+ const v = views[i];
132
+ const sub = this.binding.getViewSubImage(this.layer, v);
133
+ let eye = this.eyes[i];
134
+ if (!eye) {
135
+ eye = new EyeView(i, this.device, sub, this.viaScene ? undefined : this.aux);
136
+ this.eyes[i] = eye;
137
+ }
138
+ eye.eye = v.eye;
139
+ const cam = eye.camera;
140
+ cam.setProjection(v.projectionMatrix);
141
+ cam.setViewMatrix(v.transform.inverse.matrix);
142
+ const vd = sub.getViewDescriptor();
143
+ const layer = vd.baseArrayLayer ?? 0;
144
+ const vp = eye.viewport;
145
+ vp.x = sub.viewport.x;
146
+ vp.y = sub.viewport.y;
147
+ vp.width = sub.viewport.width;
148
+ vp.height = sub.viewport.height;
149
+ // An earlier eye on the same texture and array layer: share its target (one clear).
150
+ let target = null;
151
+ for (let j = 0; j < i; j++) {
152
+ const o = out[j];
153
+ if (o.target.adoptedColor === sub.colorTexture && o.layer === layer) {
154
+ target = o.target;
155
+ break;
156
+ }
157
+ }
158
+ if (!target) {
159
+ target = eye.own;
160
+ target.adopt({
161
+ color: sub.colorTexture,
162
+ depth: sub.depthStencilTexture,
163
+ view: vd,
164
+ viewport: vp,
165
+ });
166
+ }
167
+ eye.target = target;
168
+ eye.layer = layer;
169
+ const s = cam.screen;
170
+ if (this.viaScene) {
171
+ // The eye renders into the whole scene target; `viewport` places the resolve.
172
+ s.x = 0;
173
+ s.y = 0;
174
+ s.width = 1;
175
+ s.height = 1;
176
+ const sc = this.scene ?? this.makeScene();
177
+ sc.resize(vp.width, vp.height);
178
+ }
179
+ else {
180
+ s.x = vp.x / target.width;
181
+ s.y = vp.y / target.height;
182
+ s.width = vp.width / target.width;
183
+ s.height = vp.height / target.height;
184
+ }
185
+ out.push(eye);
186
+ }
187
+ if (views.length > 0) {
188
+ this.head.setProjection(views[0].projectionMatrix);
189
+ this.head.setViewMatrix(pose.transform.inverse.matrix);
190
+ }
191
+ return out;
192
+ }
193
+ makeScene() {
194
+ this.scene = new SceneTarget(this.device, {
195
+ width: 1,
196
+ height: 1,
197
+ label: 'xr-scene',
198
+ aux: this.aux,
199
+ });
200
+ return this.scene;
201
+ }
202
+ /** Frees the eye targets' own textures, the scene target and the layer. The session is left to its owner. */
203
+ destroy() {
204
+ if (this.destroyed)
205
+ return;
206
+ this.destroyed = true;
207
+ for (const e of this.eyes)
208
+ e.own.destroy();
209
+ this.eyes.length = 0;
210
+ this.scene?.destroy();
211
+ this.scene = null;
212
+ this.layer.destroy();
213
+ }
214
+ }
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Ambient declarations for the parts of the WebXR Device API, the WebXR Hand Input module and
3
+ * the WebXR/WebGPU binding the engine uses (ws/xr). TypeScript's DOM lib has none of them and
4
+ * the engine takes no `@types/webxr` dependency. Everything here is optional at runtime: callers
5
+ * check `navigator.xr` and `XRGPUBinding` before touching them, so the engine typechecks and
6
+ * runs where WebXR is missing (every row of the e2e matrix). Files that use these types
7
+ * reference this file with `/// <reference path="…/xr-types.d.ts" />` so a program that enters
8
+ * the engine through `harness/` (tsconfig.e2e.json) sees them too.
9
+ */
10
+
11
+ type XRSessionMode = 'inline' | 'immersive-vr' | 'immersive-ar';
12
+ type XRReferenceSpaceType = 'viewer' | 'local' | 'local-floor' | 'bounded-floor' | 'unbounded';
13
+ type XREye = 'none' | 'left' | 'right';
14
+ type XRHandedness = 'none' | 'left' | 'right';
15
+ type XRTargetRayMode = 'gaze' | 'tracked-pointer' | 'screen' | 'transient-pointer';
16
+ type XRHandJoint =
17
+ | 'wrist'
18
+ | 'thumb-metacarpal'
19
+ | 'thumb-phalanx-proximal'
20
+ | 'thumb-phalanx-distal'
21
+ | 'thumb-tip'
22
+ | 'index-finger-metacarpal'
23
+ | 'index-finger-phalanx-proximal'
24
+ | 'index-finger-phalanx-intermediate'
25
+ | 'index-finger-phalanx-distal'
26
+ | 'index-finger-tip'
27
+ | 'middle-finger-metacarpal'
28
+ | 'middle-finger-phalanx-proximal'
29
+ | 'middle-finger-phalanx-intermediate'
30
+ | 'middle-finger-phalanx-distal'
31
+ | 'middle-finger-tip'
32
+ | 'ring-finger-metacarpal'
33
+ | 'ring-finger-phalanx-proximal'
34
+ | 'ring-finger-phalanx-intermediate'
35
+ | 'ring-finger-phalanx-distal'
36
+ | 'ring-finger-tip'
37
+ | 'pinky-finger-metacarpal'
38
+ | 'pinky-finger-phalanx-proximal'
39
+ | 'pinky-finger-phalanx-intermediate'
40
+ | 'pinky-finger-phalanx-distal'
41
+ | 'pinky-finger-tip';
42
+
43
+ interface XRSessionInit {
44
+ requiredFeatures?: string[];
45
+ optionalFeatures?: string[];
46
+ }
47
+
48
+ interface XRSystem {
49
+ isSessionSupported(mode: XRSessionMode): Promise<boolean>;
50
+ requestSession(mode: XRSessionMode, init?: XRSessionInit): Promise<XRSession>;
51
+ }
52
+
53
+ interface Navigator {
54
+ /** The WebXR entry point; undefined where the browser has no WebXR. */
55
+ readonly xr?: XRSystem;
56
+ }
57
+
58
+ interface XRRigidTransform {
59
+ readonly position: DOMPointReadOnly;
60
+ readonly orientation: DOMPointReadOnly;
61
+ /** Column-major 4×4, the same layout as `mat4`. */
62
+ readonly matrix: Float32Array;
63
+ readonly inverse: XRRigidTransform;
64
+ }
65
+
66
+ // biome-ignore lint/suspicious/noEmptyInterface: an opaque handle
67
+ interface XRSpace {}
68
+
69
+ interface XRReferenceSpace extends XRSpace {
70
+ getOffsetReferenceSpace(originOffset: XRRigidTransform): XRReferenceSpace;
71
+ }
72
+
73
+ interface XRJointSpace extends XRSpace {
74
+ readonly jointName: XRHandJoint;
75
+ }
76
+
77
+ interface XRHand {
78
+ readonly size: number;
79
+ get(joint: XRHandJoint): XRJointSpace | undefined;
80
+ }
81
+
82
+ interface XRPose {
83
+ readonly transform: XRRigidTransform;
84
+ readonly emulatedPosition: boolean;
85
+ }
86
+
87
+ interface XRJointPose extends XRPose {
88
+ /** Joint radius in metres. */
89
+ readonly radius: number | undefined;
90
+ }
91
+
92
+ interface XRViewport {
93
+ readonly x: number;
94
+ readonly y: number;
95
+ readonly width: number;
96
+ readonly height: number;
97
+ }
98
+
99
+ interface XRView {
100
+ readonly eye: XREye;
101
+ /** Column-major 4×4 projection for this eye. */
102
+ readonly projectionMatrix: Float32Array;
103
+ /** The eye's pose in the reference space; `transform.inverse.matrix` is the view matrix. */
104
+ readonly transform: XRRigidTransform;
105
+ readonly recommendedViewportScale?: number | null;
106
+ requestViewportScale?(scale: number | null): void;
107
+ }
108
+
109
+ interface XRViewerPose extends XRPose {
110
+ readonly views: readonly XRView[];
111
+ }
112
+
113
+ interface XRInputSource {
114
+ readonly handedness: XRHandedness;
115
+ readonly targetRayMode: XRTargetRayMode;
116
+ readonly targetRaySpace: XRSpace;
117
+ readonly gripSpace?: XRSpace | null;
118
+ /** `xr-standard` mapping: `buttons[0]` is the trigger, `buttons[1]` the squeeze. */
119
+ readonly gamepad?: Gamepad | null;
120
+ readonly hand?: XRHand | null;
121
+ readonly profiles: readonly string[];
122
+ }
123
+
124
+ interface XRInputSourceArray {
125
+ readonly length: number;
126
+ [index: number]: XRInputSource;
127
+ [Symbol.iterator](): IterableIterator<XRInputSource>;
128
+ }
129
+
130
+ interface XRFrame {
131
+ readonly session: XRSession;
132
+ readonly predictedDisplayTime: number;
133
+ getViewerPose(referenceSpace: XRReferenceSpace): XRViewerPose | undefined;
134
+ getPose(space: XRSpace, baseSpace: XRSpace): XRPose | undefined;
135
+ /** Hand Input module; missing where hands are not supported. */
136
+ getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose | undefined;
137
+ }
138
+
139
+ type XRFrameRequestCallback = (time: DOMHighResTimeStamp, frame: XRFrame) => void;
140
+
141
+ interface XRRenderStateInit {
142
+ depthNear?: number;
143
+ depthFar?: number;
144
+ layers?: XRLayer[];
145
+ }
146
+
147
+ interface XRRenderState {
148
+ readonly depthNear: number;
149
+ readonly depthFar: number;
150
+ readonly layers?: readonly XRLayer[];
151
+ }
152
+
153
+ interface XRSessionEvent extends Event {
154
+ readonly session: XRSession;
155
+ }
156
+
157
+ interface XRInputSourceEvent extends Event {
158
+ readonly frame: XRFrame;
159
+ readonly inputSource: XRInputSource;
160
+ }
161
+
162
+ interface XRInputSourcesChangeEvent extends Event {
163
+ readonly session: XRSession;
164
+ readonly added: readonly XRInputSource[];
165
+ readonly removed: readonly XRInputSource[];
166
+ }
167
+
168
+ interface XRSessionEventMap {
169
+ end: XRSessionEvent;
170
+ inputsourceschange: XRInputSourcesChangeEvent;
171
+ select: XRInputSourceEvent;
172
+ selectstart: XRInputSourceEvent;
173
+ selectend: XRInputSourceEvent;
174
+ squeeze: XRInputSourceEvent;
175
+ squeezestart: XRInputSourceEvent;
176
+ squeezeend: XRInputSourceEvent;
177
+ visibilitychange: XRSessionEvent;
178
+ }
179
+
180
+ interface XRSession extends EventTarget {
181
+ readonly inputSources: XRInputSourceArray;
182
+ readonly renderState: XRRenderState;
183
+ readonly visibilityState: 'visible' | 'visible-blurred' | 'hidden';
184
+ requestReferenceSpace(type: XRReferenceSpaceType): Promise<XRReferenceSpace>;
185
+ updateRenderState(state?: XRRenderStateInit): void;
186
+ requestAnimationFrame(callback: XRFrameRequestCallback): number;
187
+ cancelAnimationFrame(handle: number): void;
188
+ end(): Promise<void>;
189
+ addEventListener<K extends keyof XRSessionEventMap>(
190
+ type: K,
191
+ listener: (this: XRSession, ev: XRSessionEventMap[K]) => void,
192
+ options?: boolean | AddEventListenerOptions,
193
+ ): void;
194
+ addEventListener(
195
+ type: string,
196
+ listener: EventListenerOrEventListenerObject,
197
+ options?: boolean | AddEventListenerOptions,
198
+ ): void;
199
+ removeEventListener<K extends keyof XRSessionEventMap>(
200
+ type: K,
201
+ listener: (this: XRSession, ev: XRSessionEventMap[K]) => void,
202
+ options?: boolean | EventListenerOptions,
203
+ ): void;
204
+ removeEventListener(
205
+ type: string,
206
+ listener: EventListenerOrEventListenerObject,
207
+ options?: boolean | EventListenerOptions,
208
+ ): void;
209
+ }
210
+
211
+ // ── WebXR Layers + WebXR/WebGPU binding ───────────────────────────────────────
212
+
213
+ // biome-ignore lint/suspicious/noEmptyInterface: an opaque handle
214
+ interface XRLayer {}
215
+
216
+ interface XRCompositionLayer extends XRLayer {
217
+ readonly layout: 'default' | 'mono' | 'stereo' | 'stereo-left-right' | 'stereo-top-bottom';
218
+ readonly mipLevels: number;
219
+ needsRedraw: boolean;
220
+ destroy(): void;
221
+ }
222
+
223
+ interface XRProjectionLayer extends XRCompositionLayer {
224
+ readonly textureWidth: number;
225
+ readonly textureHeight: number;
226
+ readonly textureArrayLength: number;
227
+ readonly ignoreDepthValues: boolean;
228
+ fixedFoveation?: number | null;
229
+ }
230
+
231
+ interface XRGPUProjectionLayerInit {
232
+ colorFormat?: GPUTextureFormat;
233
+ depthStencilFormat?: GPUTextureFormat;
234
+ /** `texture` (default): one texture, eyes side by side; `texture-array`: one layer per eye. */
235
+ textureType?: 'texture' | 'texture-array';
236
+ textureUsage?: GPUTextureUsageFlags;
237
+ scaleFactor?: number;
238
+ }
239
+
240
+ interface XRGPUSubImage {
241
+ readonly colorTexture: GPUTexture;
242
+ readonly depthStencilTexture?: GPUTexture | null;
243
+ /** The part of `colorTexture` this view draws into, in texture pixels, origin top-left. */
244
+ readonly viewport: XRViewport;
245
+ /** The texture view to make (array layer, mip) for this view. */
246
+ getViewDescriptor(): GPUTextureViewDescriptor;
247
+ }
248
+
249
+ interface XRGPUBinding {
250
+ readonly nativeProjectionScaleFactor: number;
251
+ createProjectionLayer(init?: XRGPUProjectionLayerInit): XRProjectionLayer;
252
+ getViewSubImage(layer: XRProjectionLayer, view: XRView): XRGPUSubImage;
253
+ getPreferredColorFormat(): GPUTextureFormat;
254
+ }
255
+
256
+ interface XRGPUBindingConstructor {
257
+ readonly prototype: XRGPUBinding;
258
+ new (session: XRSession, device: GPUDevice): XRGPUBinding;
259
+ }
260
+
261
+ /** The WebXR/WebGPU binding; undefined where the browser does not have it. */
262
+ declare var XRGPUBinding: XRGPUBindingConstructor | undefined;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The AO sample radius in uv (0..1 of the screen) for a world `radius` at view depth `z`
3
+ * through a projection of x scale `projScale`: `projScale × radius / z / 2` under a
4
+ * perspective camera, `projScale × radius / 2` under an orthographic one (where depth does not
5
+ * shrink anything). The shader's `ruv` does the same.
6
+ */
7
+ export declare function aoProjectedRadius(radius: number, projScale: number, z: number, ortho: boolean): number;
8
+ /** Shared by both AO passes and DoF: depth → view-space position. */
9
+ export declare const WGSL_DEPTH_VIEW = "\nfn view_pos(uv: vec2f, depth: f32) -> vec3f {\n let ndc = vec3f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth);\n let p = P.invProj * vec4f(ndc, 1.0);\n return p.xyz / p.w;\n}\nfn linear_depth(uv: vec2f, depth: f32) -> f32 {\n return -view_pos(uv, depth).z;\n}\n/** The centre of the depth texel under `uv`: positions must be rebuilt where the depth was read. */\nfn texel_uv(uv: vec2f, dim: vec2f) -> vec2f {\n return (floor(clamp(uv, vec2f(0.0), vec2f(0.9999)) * dim) + 0.5) / dim;\n}\n";
10
+ export declare const AO_WGSL = "\n\nstruct PostUniforms {\n frame: vec4f, // time, aspect, 1/width, 1/height\n enables: vec4f, // bloom, fog, rays, vignette\n enables2: vec4f, // grade, tonemap (0 none, 1 aces, 2 reinhard), dither, exposure\n bloom: vec4f, // intensity, threshold, knee, emissiveWeight\n bloom2: vec4f, // scatter, -, -, -\n fogColor: vec4f, // rgb, density\n fog: vec4f, // top, bottom, noiseScale, speed\n fog2: vec4f, // lightScatter, falloff, -, -\n rays: vec4f, // light uv x, y, intensity, decay\n rays2: vec4f, // density, weight, source radius (uv-y units), source intensity\n raysColor: vec4f, // rgb, bloomSource\n vignette: vec4f, // intensity, radius, softness, -\n vignetteColor: vec4f,\n lift: vec4f,\n gamma: vec4f,\n gain: vec4f,\n grade: vec4f, // saturation, contrast, -, -\n quality: vec4f, // ray samples, fog octaves, ortho projection (1, ws/post-4), -\n ao: vec4f, // enabled (0 without depth), radius, intensity, bias\n ao2: vec4f, // power, samples, proj x scale, proj y scale\n dof: vec4f, // enabled (0 without depth), focus distance, focus range, max blur (uv of width)\n dof2: vec4f, // near blur, taps, near plane, far plane\n invProj: mat4x4f, // clip -> view\n fxaa: vec4f, // enabled, subpixel, edgeThreshold, -\n lut: vec4f, // enabled, (size-1)/size, intensity, 0.5/size\n grain: vec4f, // intensity, cell size (px), luminanceResponse, seed\n aberration: vec4f, // intensity (px), radialOnly, -, -\n sharpen: vec4f, // amount, -, -, -\n outline: vec4f, // enabled (0 without depth), thickness (scene px), depthThreshold, normalThreshold\n outlineColor: vec4f, // rgb, intensity\n // Post 3 (ws/post-3).\n taa: vec4f, // enabled (0 without depth), feedback, sharpen, clampMode (0 aabb, 1 variance)\n taa2: vec4f, // view jitter x (uv), view jitter y (uv), reset (1 = copy the current frame), velocity reprojection (1, ws/post-5)\n ssr: vec4f, // enabled (0 without depth), maxSteps, thickness, maxDistance\n ssr2: vec4f, // roughnessCutoff, intensity, fadeEdges (uv), rough-metal target (1)\n exposure: vec4f, // auto (1), histogramLow, histogramHigh, keyValue\n wb0: vec4f, // white-balance matrix row 0 (rgb weights), enabled\n wb1: vec4f, // row 1\n wb2: vec4f, // row 2\n motionBlur: vec4f, // enabled (0 without depth), intensity, samples, velocity target (1 = object)\n dirt: vec4f, // enabled, intensity, -, -\n reproj: mat4x4f, // current clip -> previous frame's clip (identity on a reset)\n // Post 5 (ws/post-5).\n taa3: vec4f, // depthReject (fraction), velocityReject (px), history filter (1 = Catmull-Rom, ws/post-6), -\n};\n@group(0) @binding(0) var<uniform> P: PostUniforms;\n\n@group(0) @binding(1) var nearest: sampler;\n@group(0) @binding(2) var linSamp: sampler;\n@group(0) @binding(3) var depthTex: texture_depth_2d;\n\nfn view_pos(uv: vec2f, depth: f32) -> vec3f {\n let ndc = vec3f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth);\n let p = P.invProj * vec4f(ndc, 1.0);\n return p.xyz / p.w;\n}\nfn linear_depth(uv: vec2f, depth: f32) -> f32 {\n return -view_pos(uv, depth).z;\n}\n/** The centre of the depth texel under `uv`: positions must be rebuilt where the depth was read. */\nfn texel_uv(uv: vec2f, dim: vec2f) -> vec2f {\n return (floor(clamp(uv, vec2f(0.0), vec2f(0.9999)) * dim) + 0.5) / dim;\n}\n\n\n/** Depth at the texel under `uv` and the view position of that texel's centre (w = depth). */\nfn fetch(uv: vec2f, dim: vec2f) -> vec4f {\n let tuv = texel_uv(uv, dim);\n let d = textureSampleLevel(depthTex, nearest, tuv, 0u);\n return vec4f(view_pos(tuv, d), d);\n}\n\n/** Interleaved-gradient noise (Jimenez 2014), 0..1 per output pixel. */\nfn ign(px: vec2f) -> f32 {\n return fract(52.9829189 * fract(0.06711056 * px.x + 0.00583715 * px.y));\n}\n\n@fragment fn fs_main(in: FullscreenIn) -> @location(0) vec4f {\n let dim = vec2f(textureDimensions(depthTex));\n let c = fetch(in.uv, dim);\n if (c.w >= 1.0) {\n return vec4f(1.0);\n }\n let p = c.xyz;\n let uv = texel_uv(in.uv, dim);\n // Normal from the closer neighbour on each axis (one depth texel).\n let t = 1.0 / dim;\n let pl = fetch(uv - vec2f(t.x, 0.0), dim).xyz;\n let pr = fetch(uv + vec2f(t.x, 0.0), dim).xyz;\n let pu = fetch(uv - vec2f(0.0, t.y), dim).xyz;\n let pd = fetch(uv + vec2f(0.0, t.y), dim).xyz;\n var dx = pr - p;\n if (abs(pl.z - p.z) < abs(pr.z - p.z)) { dx = p - pl; }\n var dy = pu - p;\n if (abs(pd.z - p.z) < abs(pu.z - p.z)) { dy = p - pd; }\n let n = normalize(cross(dx, dy));\n\n let radius = P.ao.y;\n let z = -p.z;\n // World radius projected to uv: proj scale (over the depth under a perspective camera, not\n // under an ortho one: P.quality.z), halved for the -1..1 \u2192 0..1 range.\n let zs = select(max(z, 1e-3), 1.0, P.quality.z > 0.5);\n let ruv = vec2f(P.ao2.z, P.ao2.w) * radius / zs * 0.5;\n let count = i32(P.ao2.y);\n let rot = ign(in.pos.xy) * 6.2831853;\n var occ = 0.0;\n for (var i = 0; i < count; i++) {\n let a = (f32(i) + 0.5) / f32(count);\n let ang = rot + a * 6.2831853 * 3.0;\n let suv = uv + vec2f(cos(ang), sin(ang)) * ruv * sqrt(a);\n let s = fetch(suv, dim);\n if (s.w >= 1.0) { continue; }\n let sp = s.xyz;\n let v = sp - p;\n let vv = dot(v, v);\n let vn = dot(v, n) - P.ao.w;\n let falloff = max(0.0, 1.0 - vv / (radius * radius));\n occ += max(0.0, vn * inverseSqrt(vv + 1e-4)) * falloff;\n }\n occ = occ / f32(count) * 2.0 * P.ao.z;\n let ao = pow(clamp(1.0 - occ, 0.0, 1.0), P.ao2.x);\n return vec4f(ao, ao, ao, 1.0);\n}\n";
11
+ /** 4×4 depth-aware blur of the AO term (half res in, half res out). */
12
+ export declare const AO_BLUR_WGSL = "\n\nstruct PostUniforms {\n frame: vec4f, // time, aspect, 1/width, 1/height\n enables: vec4f, // bloom, fog, rays, vignette\n enables2: vec4f, // grade, tonemap (0 none, 1 aces, 2 reinhard), dither, exposure\n bloom: vec4f, // intensity, threshold, knee, emissiveWeight\n bloom2: vec4f, // scatter, -, -, -\n fogColor: vec4f, // rgb, density\n fog: vec4f, // top, bottom, noiseScale, speed\n fog2: vec4f, // lightScatter, falloff, -, -\n rays: vec4f, // light uv x, y, intensity, decay\n rays2: vec4f, // density, weight, source radius (uv-y units), source intensity\n raysColor: vec4f, // rgb, bloomSource\n vignette: vec4f, // intensity, radius, softness, -\n vignetteColor: vec4f,\n lift: vec4f,\n gamma: vec4f,\n gain: vec4f,\n grade: vec4f, // saturation, contrast, -, -\n quality: vec4f, // ray samples, fog octaves, ortho projection (1, ws/post-4), -\n ao: vec4f, // enabled (0 without depth), radius, intensity, bias\n ao2: vec4f, // power, samples, proj x scale, proj y scale\n dof: vec4f, // enabled (0 without depth), focus distance, focus range, max blur (uv of width)\n dof2: vec4f, // near blur, taps, near plane, far plane\n invProj: mat4x4f, // clip -> view\n fxaa: vec4f, // enabled, subpixel, edgeThreshold, -\n lut: vec4f, // enabled, (size-1)/size, intensity, 0.5/size\n grain: vec4f, // intensity, cell size (px), luminanceResponse, seed\n aberration: vec4f, // intensity (px), radialOnly, -, -\n sharpen: vec4f, // amount, -, -, -\n outline: vec4f, // enabled (0 without depth), thickness (scene px), depthThreshold, normalThreshold\n outlineColor: vec4f, // rgb, intensity\n // Post 3 (ws/post-3).\n taa: vec4f, // enabled (0 without depth), feedback, sharpen, clampMode (0 aabb, 1 variance)\n taa2: vec4f, // view jitter x (uv), view jitter y (uv), reset (1 = copy the current frame), velocity reprojection (1, ws/post-5)\n ssr: vec4f, // enabled (0 without depth), maxSteps, thickness, maxDistance\n ssr2: vec4f, // roughnessCutoff, intensity, fadeEdges (uv), rough-metal target (1)\n exposure: vec4f, // auto (1), histogramLow, histogramHigh, keyValue\n wb0: vec4f, // white-balance matrix row 0 (rgb weights), enabled\n wb1: vec4f, // row 1\n wb2: vec4f, // row 2\n motionBlur: vec4f, // enabled (0 without depth), intensity, samples, velocity target (1 = object)\n dirt: vec4f, // enabled, intensity, -, -\n reproj: mat4x4f, // current clip -> previous frame's clip (identity on a reset)\n // Post 5 (ws/post-5).\n taa3: vec4f, // depthReject (fraction), velocityReject (px), history filter (1 = Catmull-Rom, ws/post-6), -\n};\n@group(0) @binding(0) var<uniform> P: PostUniforms;\n\n@group(0) @binding(1) var nearest: sampler;\n@group(0) @binding(2) var linSamp: sampler;\n@group(0) @binding(3) var depthTex: texture_depth_2d;\n@group(0) @binding(4) var aoTex: texture_2d<f32>;\n\nfn view_pos(uv: vec2f, depth: f32) -> vec3f {\n let ndc = vec3f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth);\n let p = P.invProj * vec4f(ndc, 1.0);\n return p.xyz / p.w;\n}\nfn linear_depth(uv: vec2f, depth: f32) -> f32 {\n return -view_pos(uv, depth).z;\n}\n/** The centre of the depth texel under `uv`: positions must be rebuilt where the depth was read. */\nfn texel_uv(uv: vec2f, dim: vec2f) -> vec2f {\n return (floor(clamp(uv, vec2f(0.0), vec2f(0.9999)) * dim) + 0.5) / dim;\n}\n\n\n@fragment fn fs_main(in: FullscreenIn) -> @location(0) vec4f {\n let dim = vec2f(textureDimensions(depthTex));\n let uv = in.uv;\n let t = 1.0 / vec2f(textureDimensions(aoTex));\n let dc = textureSampleLevel(depthTex, nearest, uv, 0u);\n if (dc >= 1.0) {\n return vec4f(1.0);\n }\n let zc = linear_depth(texel_uv(uv, dim), dc);\n var sum = 0.0;\n var wsum = 0.0;\n for (var y = 0; y < 4; y++) {\n for (var x = 0; x < 4; x++) {\n let o = vec2f(f32(x) - 1.5, f32(y) - 1.5) * t;\n let suv = uv + o;\n let zs = linear_depth(texel_uv(suv, dim), textureSampleLevel(depthTex, nearest, suv, 0u));\n let w = 1.0 / (1.0 + 16.0 * abs(zs - zc) / max(zc, 1e-3));\n sum += textureSampleLevel(aoTex, nearest, suv, 0.0).r * w;\n wsum += w;\n }\n }\n let ao = sum / max(wsum, 1e-4);\n return vec4f(ao, ao, ao, 1.0);\n}\n";
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Screen-space ambient occlusion (ws/post-depth): a half-res pass over the scene depth, then a
3
+ * 4×4 depth-aware blur. The composite multiplies the result into the scene colour before bloom.
4
+ *
5
+ * Positions come back from depth through `P.invProj`; normals from the smaller of the two depth
6
+ * differences on each axis (so creases keep their edge). 12 (`PostQuality.aoSamples`) spiral
7
+ * samples per pixel, rotated per pixel by interleaved-gradient noise, weighted by the cosine
8
+ * to the normal and a smooth falloff inside `ao.radius`. The radius projects to the screen
9
+ * through the projection's x/y scale, over the view depth for a perspective camera and without
10
+ * it for an orthographic one (`aoProjectedRadius`, ws/post-4).
11
+ */
12
+ import { WGSL_POST_UNIFORMS } from './settings.js';
13
+ /**
14
+ * The AO sample radius in uv (0..1 of the screen) for a world `radius` at view depth `z`
15
+ * through a projection of x scale `projScale`: `projScale × radius / z / 2` under a
16
+ * perspective camera, `projScale × radius / 2` under an orthographic one (where depth does not
17
+ * shrink anything). The shader's `ruv` does the same.
18
+ */
19
+ export function aoProjectedRadius(radius, projScale, z, ortho) {
20
+ return (projScale * radius * 0.5) / (ortho ? 1 : Math.max(z, 1e-3));
21
+ }
22
+ /** Shared by both AO passes and DoF: depth → view-space position. */
23
+ export const WGSL_DEPTH_VIEW = /* wgsl */ `
24
+ fn view_pos(uv: vec2f, depth: f32) -> vec3f {
25
+ let ndc = vec3f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth);
26
+ let p = P.invProj * vec4f(ndc, 1.0);
27
+ return p.xyz / p.w;
28
+ }
29
+ fn linear_depth(uv: vec2f, depth: f32) -> f32 {
30
+ return -view_pos(uv, depth).z;
31
+ }
32
+ /** The centre of the depth texel under \`uv\`: positions must be rebuilt where the depth was read. */
33
+ fn texel_uv(uv: vec2f, dim: vec2f) -> vec2f {
34
+ return (floor(clamp(uv, vec2f(0.0), vec2f(0.9999)) * dim) + 0.5) / dim;
35
+ }
36
+ `;
37
+ export const AO_WGSL = /* wgsl */ `
38
+ ${WGSL_POST_UNIFORMS}
39
+ @group(0) @binding(1) var nearest: sampler;
40
+ @group(0) @binding(2) var linSamp: sampler;
41
+ @group(0) @binding(3) var depthTex: texture_depth_2d;
42
+ ${WGSL_DEPTH_VIEW}
43
+
44
+ /** Depth at the texel under \`uv\` and the view position of that texel's centre (w = depth). */
45
+ fn fetch(uv: vec2f, dim: vec2f) -> vec4f {
46
+ let tuv = texel_uv(uv, dim);
47
+ let d = textureSampleLevel(depthTex, nearest, tuv, 0u);
48
+ return vec4f(view_pos(tuv, d), d);
49
+ }
50
+
51
+ /** Interleaved-gradient noise (Jimenez 2014), 0..1 per output pixel. */
52
+ fn ign(px: vec2f) -> f32 {
53
+ return fract(52.9829189 * fract(0.06711056 * px.x + 0.00583715 * px.y));
54
+ }
55
+
56
+ @fragment fn fs_main(in: FullscreenIn) -> @location(0) vec4f {
57
+ let dim = vec2f(textureDimensions(depthTex));
58
+ let c = fetch(in.uv, dim);
59
+ if (c.w >= 1.0) {
60
+ return vec4f(1.0);
61
+ }
62
+ let p = c.xyz;
63
+ let uv = texel_uv(in.uv, dim);
64
+ // Normal from the closer neighbour on each axis (one depth texel).
65
+ let t = 1.0 / dim;
66
+ let pl = fetch(uv - vec2f(t.x, 0.0), dim).xyz;
67
+ let pr = fetch(uv + vec2f(t.x, 0.0), dim).xyz;
68
+ let pu = fetch(uv - vec2f(0.0, t.y), dim).xyz;
69
+ let pd = fetch(uv + vec2f(0.0, t.y), dim).xyz;
70
+ var dx = pr - p;
71
+ if (abs(pl.z - p.z) < abs(pr.z - p.z)) { dx = p - pl; }
72
+ var dy = pu - p;
73
+ if (abs(pd.z - p.z) < abs(pu.z - p.z)) { dy = p - pd; }
74
+ let n = normalize(cross(dx, dy));
75
+
76
+ let radius = P.ao.y;
77
+ let z = -p.z;
78
+ // World radius projected to uv: proj scale (over the depth under a perspective camera, not
79
+ // under an ortho one: P.quality.z), halved for the -1..1 → 0..1 range.
80
+ let zs = select(max(z, 1e-3), 1.0, P.quality.z > 0.5);
81
+ let ruv = vec2f(P.ao2.z, P.ao2.w) * radius / zs * 0.5;
82
+ let count = i32(P.ao2.y);
83
+ let rot = ign(in.pos.xy) * 6.2831853;
84
+ var occ = 0.0;
85
+ for (var i = 0; i < count; i++) {
86
+ let a = (f32(i) + 0.5) / f32(count);
87
+ let ang = rot + a * 6.2831853 * 3.0;
88
+ let suv = uv + vec2f(cos(ang), sin(ang)) * ruv * sqrt(a);
89
+ let s = fetch(suv, dim);
90
+ if (s.w >= 1.0) { continue; }
91
+ let sp = s.xyz;
92
+ let v = sp - p;
93
+ let vv = dot(v, v);
94
+ let vn = dot(v, n) - P.ao.w;
95
+ let falloff = max(0.0, 1.0 - vv / (radius * radius));
96
+ occ += max(0.0, vn * inverseSqrt(vv + 1e-4)) * falloff;
97
+ }
98
+ occ = occ / f32(count) * 2.0 * P.ao.z;
99
+ let ao = pow(clamp(1.0 - occ, 0.0, 1.0), P.ao2.x);
100
+ return vec4f(ao, ao, ao, 1.0);
101
+ }
102
+ `;
103
+ /** 4×4 depth-aware blur of the AO term (half res in, half res out). */
104
+ export const AO_BLUR_WGSL = /* wgsl */ `
105
+ ${WGSL_POST_UNIFORMS}
106
+ @group(0) @binding(1) var nearest: sampler;
107
+ @group(0) @binding(2) var linSamp: sampler;
108
+ @group(0) @binding(3) var depthTex: texture_depth_2d;
109
+ @group(0) @binding(4) var aoTex: texture_2d<f32>;
110
+ ${WGSL_DEPTH_VIEW}
111
+
112
+ @fragment fn fs_main(in: FullscreenIn) -> @location(0) vec4f {
113
+ let dim = vec2f(textureDimensions(depthTex));
114
+ let uv = in.uv;
115
+ let t = 1.0 / vec2f(textureDimensions(aoTex));
116
+ let dc = textureSampleLevel(depthTex, nearest, uv, 0u);
117
+ if (dc >= 1.0) {
118
+ return vec4f(1.0);
119
+ }
120
+ let zc = linear_depth(texel_uv(uv, dim), dc);
121
+ var sum = 0.0;
122
+ var wsum = 0.0;
123
+ for (var y = 0; y < 4; y++) {
124
+ for (var x = 0; x < 4; x++) {
125
+ let o = vec2f(f32(x) - 1.5, f32(y) - 1.5) * t;
126
+ let suv = uv + o;
127
+ let zs = linear_depth(texel_uv(suv, dim), textureSampleLevel(depthTex, nearest, suv, 0u));
128
+ let w = 1.0 / (1.0 + 16.0 * abs(zs - zc) / max(zc, 1e-3));
129
+ sum += textureSampleLevel(aoTex, nearest, suv, 0.0).r * w;
130
+ wsum += w;
131
+ }
132
+ }
133
+ let ao = sum / max(wsum, 1e-4);
134
+ return vec4f(ao, ao, ao, 1.0);
135
+ }
136
+ `;
@@ -0,0 +1,27 @@
1
+ import { type Ease } from '../tween/ease.js';
2
+ import type { PostSettings, PostSettingsPatch } from './settings.js';
3
+ export type { Ease };
4
+ export declare const easeLinear: Ease;
5
+ /** Smoothstep: gentle start and end. The default for `blendTo`. */
6
+ export declare const easeInOut: Ease;
7
+ export declare const easeOut: Ease;
8
+ export declare const easeIn: Ease;
9
+ /**
10
+ * Interpolates post settings over time. Numbers and RGB triples ease from their value when
11
+ * `blendTo` is called; everything else switches at once (`enabled: true`, so a pass can fade
12
+ * in) or at the end (`enabled: false`, `tonemap`, `dither`, `levels`, so a pass can fade out).
13
+ * Pure: no GPU, no clock. `PostStack` advances it with the frame time.
14
+ */
15
+ export declare class PostBlender {
16
+ private tracks;
17
+ /** True while any value is still moving. */
18
+ get active(): boolean;
19
+ blendTo(target: PostSettings, patch: PostSettingsPatch, seconds: number, ease: Ease): void;
20
+ /** Stop blending the given keys (e.g. after `set` overwrote them). */
21
+ cancel(patch: PostSettingsPatch): void;
22
+ /** Jump every track to its end value. */
23
+ finish(target: PostSettings): void;
24
+ /** Move every track forward by `dt` seconds and write the values into `target`. */
25
+ advance(target: PostSettings, dt: number): void;
26
+ private drop;
27
+ }