@driftengine/core 3.63.0 → 4.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 (428) hide show
  1. package/CHANGELOG.json +122 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +69 -4
  9. package/dist/index.js +112 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +246 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  export { startLoop } from './core/loop.js';
4
4
  export { StepBudget } from './core/stepBudget.js';
5
5
  export { hashToUnit, mulberry32, pickBySeed, savableMulberry32 } from './core/rng.js';
6
- export { exactAcos, exactCos, exactExp, exactSin } from './math/exact.js';
6
+ export { exactAcos, exactCos, exactExp, exactLog, exactSin } from './math/exact.js';
7
7
  export { TickTrace } from './core/tickTrace.js';
8
8
  export { BrowserStore, MemoryStore, defaultStore } from './core/storage.js';
9
9
  /* The same seam over a backend that answers later, with the queue, the retry and the status. */
@@ -60,7 +60,7 @@ export { MAX_DEPTH_LAYER, Renderer, WebGL2Renderer } from './render/backend/webg
60
60
  export { PickableSet } from './render/pickable.js';
61
61
  /* How big a piece of geometry is, which everything that culls or picks a detail level starts from. */
62
62
  export { boundsOfBox, boundsOfPositions, createBounds } from './math/bounds.js';
63
- export { createFrustum, frustumFromViewProjection, sphereInFrustum } from './math/frustum.js';
63
+ export { boxInFrustum, createFrustum, frustumFromViewProjection, sphereInFrustum, } from './math/frustum.js';
64
64
  export { boundsVisible } from './render/visibility.js';
65
65
  export { apparentSize, lodForBounds } from './render/lod.js';
66
66
  /* A transform hierarchy. Additive: nothing in the renderer knows a node exists. */
@@ -79,6 +79,11 @@ export { createVisitResult, visitVisible } from './scene/visit.js';
79
79
  */
80
80
  export { generateMipChain, mipLevelCount, } from './render/backend/webgpu/surfaceTexturePass.js';
81
81
  export { createPassAttachment } from './render/passTarget.js';
82
+ /*
83
+ * What a pass drawing the world does with `PrepareContext.jitter`, so a reconstructed frame's
84
+ * resolve finds its geometry where the renderer's own verbs put theirs.
85
+ */
86
+ export { jitterClip } from './render/recon/jitter.js';
82
87
  export { OcclusionBuffer } from './render/occlusion.js';
83
88
  /*
84
89
  * `Renderer` above stays exported and is not deprecated. `createRenderer` is the way to get
@@ -87,6 +92,80 @@ export { OcclusionBuffer } from './render/occlusion.js';
87
92
  * take one.
88
93
  */
89
94
  export { createRenderer } from './render/backend/createRenderer.js';
95
+ /*
96
+ * The second pipeline, as the two things a consumer assembles: the scene packing and the pass
97
+ * that draws it.
98
+ *
99
+ * **Exported here and reached by nobody who does not ask for it.** `pipeline: 'gpu-driven'` on
100
+ * `createRenderer` is the permission — it fails at boot where the backend cannot run this — and
101
+ * `GpuDrivenPass` is the implementation, registered the way `@driftengine/splats` registers one.
102
+ * A consumer who names neither pays nothing: `core-only` is measured with these exported and does
103
+ * not move, because nothing in the forward path reaches them.
104
+ *
105
+ * It draws vertex colour, one directional term, a hemispheric ambient and an emissive add — not
106
+ * the standard material. `DRAFT_SCENES`, never `SCENES`, until it draws the six published ones.
107
+ */
108
+ export { GPU_DRIVEN_LISTS, GpuDrivenPass, MATERIAL_FLOATS, } from './render/backend/webgpu/gpuDrivenPass.js';
109
+ /*
110
+ * **One environment, one haze, on both pipelines.** `GpuDrivenView.fog` is the medium the forward
111
+ * path binds, and a consumer drawing both in one frame fills it from `atmosphereFog` rather than
112
+ * working the numbers out again — the voxel sandbox's port is the first.
113
+ */
114
+ export { atmosphereFog, createFogTarget } from './render/fog.js';
115
+ export { buildGpuDrivenScene } from './render/gpudriven/sceneUpload.js';
116
+ /*
117
+ * **The scene a `GpuDrivenPass` takes**, which is a streaming one since 2026-09-18 — a static
118
+ * scene is one filled once, so there is a single path rather than two. `buildGpuDrivenScene` stays
119
+ * exported because it is the packer `streamScene.test.ts` holds the streaming layout to.
120
+ */
121
+ export { StreamingScene, streamingScene } from './render/gpudriven/streamScene.js';
122
+ export { packDecodeTables, programFromEncoded } from './render/gpudriven/decodeTables.js';
123
+ /*
124
+ * **A network graph on a device**: the one neural runtime's device half. `@driftengine/texture`
125
+ * holds the references and validates a graph; this runs the validated graph, whose shapes it takes
126
+ * as given, on a device opened from whichever `GPU` the caller has — a browser's or the native
127
+ * host's Dawn. Exported because the device may not leave `render/`, so a package that runs a
128
+ * network does so through here or not at all.
129
+ */
130
+ export { openInferenceDevice } from './render/inference/device.js';
131
+ export { createGraphRunner } from './render/inference/runner.js';
132
+ /* The buffer-reuse rule, exported because `@driftengine/texture`'s evaluator plans by this one
133
+ rather than by a second copy of it — see `reuse.ts` for why it is on this side of the arrow. */
134
+ export { planReuse } from './render/inference/reuse.js';
135
+ /* The tile lists a device draws a splat cloud from, beside the shader that walks them. */
136
+ export { countSplatTiles, fillSplatTiles, splatPixelBox, splatTileGrid, splatTileOffsets, SPLAT_BIN_FLOATS, SPLAT_TILE, } from './render/inference/splatTiles.js';
137
+ /**
138
+ * **Indirect light, as three levels that fall back to each other and never off the end.**
139
+ *
140
+ * `ROADMAP.md` refused screen-space global illumination because its error is unbounded — a ray
141
+ * that leaves the frame has no answer, and every technique that ships one anyway invents one from
142
+ * whatever happened to be on screen. This does not reverse that refusal: the screen is an
143
+ * accelerator with a world-space distance field behind it, whose error is bounded by its own
144
+ * resolution, and a probe volume behind *that*, which is never wrong and only ever coarse.
145
+ *
146
+ * **CPU-side, and reached by nobody who does not ask.** There is no WGSL, no pass and no renderer
147
+ * option yet, so no scene renders differently for these existing — this wave's first constraint,
148
+ * measured rather than asserted: the eight published scenes are 0 of 921,600 pixels against the
149
+ * build before them, and `core-only` is byte-identical with these exported and without them.
150
+ * Exported anyway, for the reason `bake/cluster.ts` was not: a capability with no route out of its
151
+ * package is one the first consumer finds by failing a boundary test.
152
+ */
153
+ export { GI_SOURCE_FIELD, GI_SOURCE_PROBES, GI_SOURCE_SCREEN, newIndirectResult, traceIndirect, } from './render/gi/chain.js';
154
+ export { GLOBAL_FIELD_BLEND, composeGlobalField, createGlobalField, sampleGlobalField, } from './render/gi/globalField.js';
155
+ export { GI_SCREEN_MARCH, SCREEN_TRACE_BIAS_M, screenRayOrigin, traceScreen, } from './render/gi/traceScreen.js';
156
+ export { FIELD_MARCH, coneRadiusAt, newFieldHit, traceField } from './render/gi/traceField.js';
157
+ export { PROBE_VISIBILITY_SHARPNESS, bakeProbeVisibility, createProbeVisibility, probeUpdateSchedule, probeVisibilityWeight, sampleProbeVolume, visibleProbes, } from './render/gi/probeVolume.js';
158
+ export { DENOISE_MIN_ALPHA, filterStepFor, newTemporalPixel, spatialDenoise, temporalDenoise, } from './render/gi/denoise.js';
159
+ export { reflectDirection, reflectionCone, traceReflection } from './render/gi/reflection.js';
160
+ /*
161
+ * The pass that draws the renderer's field on a device. WebGPU only, and it says so at
162
+ * registration rather than at the first frame: a distance field is composed by compute and WebGL2
163
+ * has none. It no longer composes one of its own — `addDistanceField` is how a scene declares
164
+ * what its indirect light may be traced against, and this marches what the renderer made of them.
165
+ */
166
+ export { GiFieldPass } from './render/backend/webgpu/giFieldPass.js';
167
+ export { DistanceFieldScene, MAX_DISTANCE_FIELDS } from './render/gi/fieldScene.js';
168
+ export { placeCascade } from './render/gi/globalField.js';
90
169
  /*
91
170
  * The acceptance probe, exported because a consumer may want to ask the question itself — an
92
171
  * editor deciding whether to offer a backend, a shell deciding what to tell the player — and
@@ -225,6 +304,13 @@ export { DebugLines } from './render/debugLines.js';
225
304
  * over and what a drag does, and fills line buffers the caller draws with `drawLines`.
226
305
  * Nothing here touches a context.
227
306
  */
307
+ /*
308
+ * Ray intersection, exported because a consumer building a tool needs the same arithmetic the
309
+ * gizmo does. `editor/src/viewport/gizmo.ts` reaching into `src/math/intersect.ts` by path would
310
+ * be the editor using a private hook, which `ARCHITECTURE.md` treats as a hole in the engine
311
+ * rather than as the editor's problem — so the hole is closed here.
312
+ */
313
+ export { rayClosestOnLine, rayPlane, raySphere } from './math/intersect.js';
228
314
  export { GIZMO_GROUP_ACTIVE, GIZMO_GROUP_COLORS, GIZMO_GROUP_COUNT, GIZMO_GROUP_NEUTRAL, GIZMO_GROUP_X, GIZMO_GROUP_Y, GIZMO_GROUP_Z, GIZMO_NONE, GIZMO_ROTATE_X, GIZMO_ROTATE_Y, GIZMO_ROTATE_Z, GIZMO_SCALE_UNIFORM, GIZMO_SCALE_X, GIZMO_SCALE_Y, GIZMO_SCALE_Z, GIZMO_TRANSLATE_X, GIZMO_TRANSLATE_XY, GIZMO_TRANSLATE_Y, GIZMO_TRANSLATE_YZ, GIZMO_TRANSLATE_Z, GIZMO_TRANSLATE_ZX, Gizmo, gizmoScaleFor, } from './render/gizmo.js';
229
315
  export { RainField } from './render/rainField.js';
230
316
  export { coveredAbove } from './physics/heightSurface.js';
@@ -286,6 +372,21 @@ export { bakeOverlay, drawPixelText, pixelTextCells, pixelTextSize } from './ui/
286
372
  export { FpsMeter } from './dev/fpsMeter.js';
287
373
  export { CONTACT_LIMIT, createContactReports, describeContacts } from './dev/contactProbe.js';
288
374
  export { GPU_SLOTS, GpuTimer } from './render/gpuTimer.js';
375
+ /*
376
+ * Per-pass timings, which are a readout rather than a frame graph.
377
+ *
378
+ * **`render/frame/index.ts` says nothing under it may be reached from outside `render/` yet, and
379
+ * this module is the exception with a reason.** The rest of that directory is the graph's
380
+ * construction — declarations, lifetimes, aliasing, scheduling — whose public shape the design
381
+ * leaves to a later phase, and exporting it now would fix a shape nobody has had to live with.
382
+ * A timing readout is not that: it is seven functions over three arrays, its own header argues why
383
+ * it is not a widening of `GpuTimer`, and anything that profiles a frame needs it.
384
+ *
385
+ * The editor is what made this concrete. `AGENTS.md`'s rule is that a consumer needing a private
386
+ * import has found a hole in the engine, and the hole is fixed here rather than worked around
387
+ * there — which is the whole reason the editor was built outside `packages/`.
388
+ */
389
+ export { createPassTimings, passLabel, passMs, recordPassLabel, recordPassSample, resetPassTimings, } from './render/frame/passTimings.js';
289
390
  export { classifyRightGesture } from './input/rightGesture.js';
290
391
  export { createWindState, sampleWind } from './render/wind.js';
291
392
  export { advanceWindField, createWindField } from './render/windField.js';
@@ -329,3 +430,12 @@ export { parseSdfFont } from './render/sdfFont.js';
329
430
  export { DEFAULT_SDF_TEXT_STYLE, SdfTextLayout } from './render/sdfTextLayout.js';
330
431
  export { WindStreakRenderer } from './render/windStreakRenderer.js';
331
432
  export { buildTree } from './geometry/treeBuilder.js';
433
+ /*
434
+ * Large worlds: the cell grid that streams and freezes, and the origin that rendering rebases
435
+ * against while the simulation never does. See `world/rebase.ts` for why that asymmetry is the
436
+ * rule the whole design hangs on.
437
+ */
438
+ export { cellBounds, cellCoord, cellCoordInRange, cellCoordsOf, cellIdFor, cellIdFrom, cellsInFrustum, cellsInRadius, createCellGrid, } from './world/cell.js';
439
+ export { renderOrigin, toRenderSpace, toWorldSpace } from './world/rebase.js';
440
+ export { cameraPositionFrom, cellPredictor, createCellStream, pumpCellStream, setCellStreamOrigin, } from './world/cellStream.js';
441
+ export { createFrozenCells, freezeCell, frozenEntities, frozenFingerprintContribution, isCellFrozen, thawCell, } from './world/freeze.js';
@@ -317,7 +317,12 @@ export class InputSource {
317
317
  constructor(target, preventDefaultCodes = [], options = {}) {
318
318
  this.target = target;
319
319
  this.preventDefaultCodes = new Set(preventDefaultCodes);
320
- this.isCoarse = window.matchMedia('(pointer: coarse)').matches;
320
+ /* Guarded, and `ui/fullscreen.ts` guards the identical query with the identical test. This
321
+ line is in a constructor, so unguarded it did not degrade a hint — it threw, and an embedder
322
+ without `matchMedia` could not construct input at all. False is what a runtime with no
323
+ pointer media query honestly is. */
324
+ this.isCoarse =
325
+ typeof window.matchMedia === 'function' && window.matchMedia('(pointer: coarse)').matches;
321
326
  this.deadzone = options.deadzone ?? DEFAULT_DEADZONE;
322
327
  this.autoPoll = options.autoPoll ?? true;
323
328
  for (const name of ['keyboard', 'mouse', 'touch', 'gamepad']) {
@@ -18,9 +18,10 @@
18
18
  *
19
19
  * ## What is here, and what is deliberately not
20
20
  *
21
- * `exactSin`, `exactCos`, `exactExp`, `exactAcos`. Four, because four is what the engine and its
22
- * first consumer actually reach for: the terrain binding's slope angle needs `acos`, a lockstep
23
- * fixture rotating anything needs `sin` and `cos`, and exponential decay needs `exp`.
21
+ * `exactSin`, `exactCos`, `exactExp`, `exactAcos` and `exactLog`. Five, because five is what the
22
+ * engine and its first consumer actually reach for: the terrain binding's slope angle needs `acos`,
23
+ * a lockstep fixture rotating anything needs `sin` and `cos`, exponential decay needs `exp`, and a
24
+ * detector's box prior is a logit of the patch grid, which needs `log`.
24
25
  *
25
26
  * **`atan2` is absent.** It is the obvious fifth and nothing here needs one: `shape.ts` sorts by a
26
27
  * comparison key computed from two in-plane axes rather than by an angle, and `joints.ts` compares
@@ -55,6 +56,15 @@ export declare function exactCos(x: number): number;
55
56
  * representation and there is nothing a fitted polynomial would buy.
56
57
  */
57
58
  export declare function exactExp(x: number): number;
59
+ /**
60
+ * `Math.log`, reproducibly: fdlibm's algorithm, which is also V8's.
61
+ *
62
+ * Take the power of two out as `k` and leave a significand in [√2/2, √2), so that `f = m - 1` is
63
+ * small either side of zero; then log(1 + f) = f - f²/2 + s·(f²/2 + R(s²)) with s = f/(2 + f), and
64
+ * `k·ln 2` added back in two parts so the large part loses nothing. The exponent is read and the
65
+ * significand rescaled through the double's own words — integer operations, not transcendentals.
66
+ */
67
+ export declare function exactLog(x: number): number;
58
68
  /**
59
69
  * `Math.acos`, reproducibly. Outside [-1, 1] this answers NaN, as `Math.acos` does.
60
70
  *
@@ -18,9 +18,10 @@
18
18
  *
19
19
  * ## What is here, and what is deliberately not
20
20
  *
21
- * `exactSin`, `exactCos`, `exactExp`, `exactAcos`. Four, because four is what the engine and its
22
- * first consumer actually reach for: the terrain binding's slope angle needs `acos`, a lockstep
23
- * fixture rotating anything needs `sin` and `cos`, and exponential decay needs `exp`.
21
+ * `exactSin`, `exactCos`, `exactExp`, `exactAcos` and `exactLog`. Five, because five is what the
22
+ * engine and its first consumer actually reach for: the terrain binding's slope angle needs `acos`,
23
+ * a lockstep fixture rotating anything needs `sin` and `cos`, exponential decay needs `exp`, and a
24
+ * detector's box prior is a logit of the patch grid, which needs `log`.
24
25
  *
25
26
  * **`atan2` is absent.** It is the obvious fifth and nothing here needs one: `shape.ts` sorts by a
26
27
  * comparison key computed from two in-plane axes rather than by an angle, and `joints.ts` compares
@@ -226,6 +227,70 @@ export function exactExp(x) {
226
227
  sum = 1 + r * sum;
227
228
  return sum * pow2(k);
228
229
  }
230
+ /* fdlibm's `log` polynomial in s², for log(1 + f) around f = 0 by way of s = f / (2 + f). */
231
+ const LG1 = 6.66666666666673513e-1;
232
+ const LG2 = 3.999999999940941908e-1;
233
+ const LG3 = 2.857142874366239149e-1;
234
+ const LG4 = 2.222219843214978396e-1;
235
+ const LG5 = 1.818357216161805012e-1;
236
+ const LG6 = 1.531383769920937332e-1;
237
+ const LG7 = 1.479819860511658591e-1;
238
+ const TWO54 = 1.8014398509481984e16;
239
+ const SMALLEST_NORMAL = 2.2250738585072014e-308;
240
+ /* A double's two words, for reading and setting an exponent; one view, reused. */
241
+ const words = new DataView(new ArrayBuffer(8));
242
+ /**
243
+ * `Math.log`, reproducibly: fdlibm's algorithm, which is also V8's.
244
+ *
245
+ * Take the power of two out as `k` and leave a significand in [√2/2, √2), so that `f = m - 1` is
246
+ * small either side of zero; then log(1 + f) = f - f²/2 + s·(f²/2 + R(s²)) with s = f/(2 + f), and
247
+ * `k·ln 2` added back in two parts so the large part loses nothing. The exponent is read and the
248
+ * significand rescaled through the double's own words — integer operations, not transcendentals.
249
+ */
250
+ export function exactLog(x) {
251
+ if (Number.isNaN(x) || x < 0)
252
+ return Number.NaN;
253
+ if (x === 0)
254
+ return Number.NEGATIVE_INFINITY;
255
+ if (x === Number.POSITIVE_INFINITY)
256
+ return x;
257
+ let k = 0;
258
+ let value = x;
259
+ if (value < SMALLEST_NORMAL) {
260
+ k = -54;
261
+ value *= TWO54;
262
+ }
263
+ words.setFloat64(0, value);
264
+ let hx = words.getUint32(0);
265
+ k += (hx >>> 20) - 1023;
266
+ hx &= 0x000fffff;
267
+ /* Keep the significand at or above √2/2: past √2, halve it and count one more power of two. */
268
+ const i = (hx + 0x95f64) & 0x100000;
269
+ words.setUint32(0, hx | (i ^ 0x3ff00000));
270
+ k += i >>> 20;
271
+ const f = words.getFloat64(0) - 1;
272
+ if ((0x000fffff & (2 + hx)) < 3) {
273
+ /* |f| < 2^-20: two terms of the series are the whole answer. */
274
+ if (f === 0)
275
+ return k === 0 ? 0 : k * LN2_HI + k * LN2_LO;
276
+ const r = f * f * (0.5 - 0.33333333333333333 * f);
277
+ return k === 0 ? f - r : k * LN2_HI - (r - k * LN2_LO - f);
278
+ }
279
+ const s = f / (2 + f);
280
+ const z = s * s;
281
+ const w = z * z;
282
+ const t1 = w * (LG2 + w * (LG4 + w * LG6));
283
+ const t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
284
+ const r = t2 + t1;
285
+ /* Far enough from one that f²/2 is worth carrying apart from f. */
286
+ if (((hx - 0x6147a) | (0x6b851 - hx)) > 0) {
287
+ const half = 0.5 * f * f;
288
+ return k === 0
289
+ ? f - (half - s * (half + r))
290
+ : k * LN2_HI - (half - (s * (half + r) + k * LN2_LO) - f);
291
+ }
292
+ return k === 0 ? f - s * (f - r) : k * LN2_HI - (s * (f - r) - k * LN2_LO - f);
293
+ }
229
294
  /** fdlibm's `asin` rational on `z = x²`, valid where `z` is small. */
230
295
  function asinRational(z) {
231
296
  const numerator = z * (P0 + z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))));
@@ -10,6 +10,11 @@ import type { ReadonlyMat4 } from 'gl-matrix';
10
10
  * the frustum when `n · p + d >= 0` for all six.
11
11
  */
12
12
  export type Frustum = Float32Array;
13
+ /**
14
+ * Planes in either precision. **Double precision is for a world past 2^24 units**, where a plane's
15
+ * offset is a number a single float cannot hold to the metre; `cellsInFrustum` asks for it.
16
+ */
17
+ export type FrustumPlanes = Float32Array | Float64Array;
13
18
  export declare function createFrustum(): Frustum;
14
19
  /**
15
20
  * Pull the six planes out of a view-projection matrix.
@@ -28,7 +33,7 @@ export declare function createFrustum(): Frustum;
28
33
  *
29
34
  * gl-matrix stores column-major, so `m[column * 4 + row]`.
30
35
  */
31
- export declare function frustumFromViewProjection(m: ReadonlyMat4, out: Frustum): Frustum;
36
+ export declare function frustumFromViewProjection<T extends FrustumPlanes>(m: ReadonlyMat4 | Float64Array, out: T): T;
32
37
  /**
33
38
  * Whether a world-space sphere is anywhere inside the frustum.
34
39
  *
@@ -41,4 +46,14 @@ export declare function frustumFromViewProjection(m: ReadonlyMat4, out: Frustum)
41
46
  * all six planes, near an edge. That costs a draw that turns out to be invisible and never costs
42
47
  * a draw that was visible, which is the only asymmetry a cull may have.
43
48
  */
44
- export declare function sphereInFrustum(frustum: Frustum, x: number, y: number, z: number, radius: number): boolean;
49
+ export declare function sphereInFrustum(frustum: FrustumPlanes, x: number, y: number, z: number, radius: number): boolean;
50
+ /**
51
+ * Whether an axis-aligned box is anywhere inside the frustum, by the same question the sphere test
52
+ * asks: outside only when wholly beyond one plane.
53
+ *
54
+ * **The corner that decides it is chosen per plane** — the one furthest along that plane's normal.
55
+ * A fixed corner answers correctly for the planes whose normals happen to point its way and culls a
56
+ * box straddling any of the others. Conservative at the edges, as the sphere test is: a box near a
57
+ * corner of the frustum can be outside it and still kept.
58
+ */
59
+ export declare function boxInFrustum(frustum: FrustumPlanes, minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): boolean;
@@ -88,3 +88,27 @@ export function sphereInFrustum(frustum, x, y, z, radius) {
88
88
  }
89
89
  return true;
90
90
  }
91
+ /**
92
+ * Whether an axis-aligned box is anywhere inside the frustum, by the same question the sphere test
93
+ * asks: outside only when wholly beyond one plane.
94
+ *
95
+ * **The corner that decides it is chosen per plane** — the one furthest along that plane's normal.
96
+ * A fixed corner answers correctly for the planes whose normals happen to point its way and culls a
97
+ * box straddling any of the others. Conservative at the edges, as the sphere test is: a box near a
98
+ * corner of the frustum can be outside it and still kept.
99
+ */
100
+ export function boxInFrustum(frustum, minX, minY, minZ, maxX, maxY, maxZ) {
101
+ for (let plane = 0; plane < PLANE_COUNT; plane += 1) {
102
+ const at = plane * 4;
103
+ const nx = frustum[at] ?? 0;
104
+ const ny = frustum[at + 1] ?? 0;
105
+ const nz = frustum[at + 2] ?? 0;
106
+ const reach = nx * (nx >= 0 ? maxX : minX) +
107
+ ny * (ny >= 0 ? maxY : minY) +
108
+ nz * (nz >= 0 ? maxZ : minZ) +
109
+ (frustum[at + 3] ?? 0);
110
+ if (reach < 0)
111
+ return false;
112
+ }
113
+ return true;
114
+ }
@@ -464,7 +464,20 @@ export type RendererApi = Omit<{
464
464
  */
465
465
  updateMesh(mesh: MeshHandle, positions: Float32Array, normals?: Float32Array): void;
466
466
  /** Draw a handle this renderer made. Passing one from the other backend is a caller error. */
467
- drawMesh(mesh: MeshHandle, model: ReadonlyMat4, depthLayer?: number, tint?: Vec3 | null): void;
467
+ drawMesh(mesh: MeshHandle, model: ReadonlyMat4, depthLayer?: number, tint?: Vec3 | null,
468
+ /**
469
+ * Where this mesh's surface was last frame, for a reconstruction's motion target.
470
+ *
471
+ * **Only a reconstruction reads it**, and only on WebGPU: it is what turns a moving object's
472
+ * stale history from a smear into a reprojection. A draw that says nothing gets the camera's
473
+ * motion, derived from the depth, which is exactly right for anything that did not move and
474
+ * wrong in proportion to how far a mover moved. Null and omitted mean the same thing.
475
+ *
476
+ * It is the *model* matrix this mesh was drawn with last frame, not a velocity: the pass
477
+ * transforms each vertex twice and lets the perspective divide do the rest, so a rotation and a
478
+ * scale are as correct as a translation.
479
+ */
480
+ previousModel?: ReadonlyMat4 | null): void;
468
481
  /** Release the geometry behind a handle. */
469
482
  disposeMesh(mesh: MeshHandle): void;
470
483
  /**
@@ -494,3 +507,23 @@ export type RendererApi = Omit<{
494
507
  };
495
508
  /** Which backend is actually drawing. Reported, never inferred. */
496
509
  export type RenderBackend = 'webgl2' | 'webgpu';
510
+ /**
511
+ * Whether this backend can be driven from buffers the GPU itself wrote.
512
+ *
513
+ * **A fact about the backend, not a method on this surface, and that is the finding rather than
514
+ * the shortcut.** Indirect execution needs a render or compute pass encoder, and both are already
515
+ * in the hands of the code that would use them: `PassContext` hands a contributed pass the
516
+ * `GPURenderPassEncoder`, and `ComputeDefinition.dispatch` hands a definition the
517
+ * `GPUComputePassEncoder` while saying in as many words that the workgroup count is the
518
+ * definition's and does not cross this surface. A `drawIndexedIndirect` here would be a second
519
+ * way to reach an encoder a caller already holds.
520
+ *
521
+ * So what is missing is not a verb. It is an answer to *may I*, which a GPU-driven pipeline has
522
+ * to ask before it builds an argument buffer nothing can consume.
523
+ *
524
+ * **WebGL2 is a refusal rather than an omission.** It has no compute stage to write an argument
525
+ * buffer and no indirect draw to read one. Emulating it means reading the buffer back to the
526
+ * processor and issuing the draws from there, which is slower than the ordinary path it would be
527
+ * pretending to replace — so this reports false and the GPU-driven pipeline is WebGPU-only.
528
+ */
529
+ export declare function indirectSupport(backend: 'webgl2' | 'webgpu'): boolean;
@@ -1 +1,22 @@
1
- export {};
1
+ /**
2
+ * Whether this backend can be driven from buffers the GPU itself wrote.
3
+ *
4
+ * **A fact about the backend, not a method on this surface, and that is the finding rather than
5
+ * the shortcut.** Indirect execution needs a render or compute pass encoder, and both are already
6
+ * in the hands of the code that would use them: `PassContext` hands a contributed pass the
7
+ * `GPURenderPassEncoder`, and `ComputeDefinition.dispatch` hands a definition the
8
+ * `GPUComputePassEncoder` while saying in as many words that the workgroup count is the
9
+ * definition's and does not cross this surface. A `drawIndexedIndirect` here would be a second
10
+ * way to reach an encoder a caller already holds.
11
+ *
12
+ * So what is missing is not a verb. It is an answer to *may I*, which a GPU-driven pipeline has
13
+ * to ask before it builds an argument buffer nothing can consume.
14
+ *
15
+ * **WebGL2 is a refusal rather than an omission.** It has no compute stage to write an argument
16
+ * buffer and no indirect draw to read one. Emulating it means reading the buffer back to the
17
+ * processor and issuing the draws from there, which is slower than the ordinary path it would be
18
+ * pretending to replace — so this reports false and the GPU-driven pipeline is WebGPU-only.
19
+ */
20
+ export function indirectSupport(backend) {
21
+ return backend === 'webgpu';
22
+ }
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * What a frame asked of a backend, against what that backend allows.
3
3
  *
4
- * **This exists because a ceiling firing was unobservable.** The WebGPU backend holds ten per-frame
5
- * ceilings — draws, material changes, overlays, water bodies, light volumes, plumes, three kinds of
6
- * effect batch and the scatter shadow round — and past any of them it skips the work and writes one
7
- * `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and draws everything.
8
- * So a scene over a ceiling renders differently on the two backends, silently, and a consumer
9
- * developing against WebGL2 has no way to see it coming.
4
+ * **This exists because a ceiling firing was unobservable.** The WebGPU backend holds fourteen
5
+ * per-frame ceilings — draws, material changes, two kinds of shadow draw, water bodies, light
6
+ * volumes, four kinds of effect batch and four kinds of overlay — and past any of them it skips the
7
+ * work and writes one `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
8
+ * draws everything. So a scene over a ceiling renders differently on the two backends, silently,
9
+ * and a consumer developing against WebGL2 had no way to see it coming — which is why WebGL2 counts
10
+ * the same fifteen lines by the same rules, and reports the number the other backend rations.
10
11
  *
11
12
  * **The cost of that was measured from outside.** A consumer spent weeks on ground that
12
13
  * vanished and reappeared as the camera moved; its own report still lists, as the decisive
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * What a frame asked of a backend, against what that backend allows.
3
3
  *
4
- * **This exists because a ceiling firing was unobservable.** The WebGPU backend holds ten per-frame
5
- * ceilings — draws, material changes, overlays, water bodies, light volumes, plumes, three kinds of
6
- * effect batch and the scatter shadow round — and past any of them it skips the work and writes one
7
- * `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and draws everything.
8
- * So a scene over a ceiling renders differently on the two backends, silently, and a consumer
9
- * developing against WebGL2 has no way to see it coming.
4
+ * **This exists because a ceiling firing was unobservable.** The WebGPU backend holds fourteen
5
+ * per-frame ceilings — draws, material changes, two kinds of shadow draw, water bodies, light
6
+ * volumes, four kinds of effect batch and four kinds of overlay — and past any of them it skips the
7
+ * work and writes one `console.warn` for the lifetime of the renderer. WebGL2 holds none of them and
8
+ * draws everything. So a scene over a ceiling renders differently on the two backends, silently,
9
+ * and a consumer developing against WebGL2 had no way to see it coming — which is why WebGL2 counts
10
+ * the same fifteen lines by the same rules, and reports the number the other backend rations.
10
11
  *
11
12
  * **The cost of that was measured from outside.** A consumer spent weeks on ground that
12
13
  * vanished and reappeared as the camera moved; its own report still lists, as the decisive
@@ -1,6 +1,38 @@
1
1
  import { type RenderQualityOptions } from '../renderQuality.ts';
2
2
  import type { RenderBackend, RendererApi } from './api.ts';
3
3
  import { type SplashOptions } from '../../ui/splash.ts';
4
+ /**
5
+ * Which of the two pipelines is drawing.
6
+ *
7
+ * A union rather than a boolean because a third is foreseeable and a boolean named for one of them
8
+ * is what makes the third awkward — `ROADMAP.md`'s own note about `hdrScene` starting life as
9
+ * `bool hdr`.
10
+ */
11
+ export type RenderPipeline = 'forward' | 'gpu-driven';
12
+ /**
13
+ * What a caller who says nothing gets.
14
+ *
15
+ * **A named constant rather than a literal in the `??`**, because the literal is unreachable from
16
+ * a test here: nothing in this environment resolves a renderer, so flipping it changed no answer
17
+ * and no test noticed. The constant is where the decision lives and it is asserted directly.
18
+ *
19
+ * Forward, and it stays forward until the second pipeline has drawn the six published scenes.
20
+ */
21
+ export declare const DEFAULT_PIPELINE: RenderPipeline;
22
+ /**
23
+ * Why a requested pipeline cannot run on the backend that is about to draw, or null where it can.
24
+ *
25
+ * **Its own function because it is the only part of the decision a test in this environment can
26
+ * reach.** Nothing here can resolve a renderer — there is no GL context and no adapter — so every
27
+ * test of `createRenderer` ends in a rejection, and a check that lives only inside the factory is
28
+ * a check nothing exercises. `built` is this function's one caller and every return from the
29
+ * factory passes through it.
30
+ *
31
+ * **The backend is the one that will draw, not the one that was asked for.** Three paths into
32
+ * `built` arrive having fallen back from WebGPU, and a check written against the request passes on
33
+ * all three.
34
+ */
35
+ export declare function pipelineRefusal(pipeline: RenderPipeline, backend: RenderBackend, reason: string): string | null;
4
36
  /** Everything about selection a caller may want to decide instead of inherit. */
5
37
  export interface CreateRendererOptions {
6
38
  /**
@@ -19,6 +51,23 @@ export interface CreateRendererOptions {
19
51
  * shows that, and the fallback is silent when it happens.
20
52
  */
21
53
  readonly preferWebGpu?: boolean;
54
+ /**
55
+ * Which pipeline to draw with. **Defaults to `'forward'`.**
56
+ *
57
+ * `'gpu-driven'` selects the cluster pipeline: instances and clusters culled on the device
58
+ * against a depth pyramid built this frame, a visibility buffer, and one shading dispatch per
59
+ * material. It needs indirect draws and dispatches, which WebGL2 does not have.
60
+ *
61
+ * **Asking for it where it cannot run throws.** Not a warning and not a fallback: a silent
62
+ * fallback means a consumer ships believing they have a pipeline they do not, and the difference
63
+ * only shows as a frame time on somebody else's machine. The throw carries the reason in words,
64
+ * from `gpuDrivenRefusal`.
65
+ *
66
+ * **This includes a WebGPU request that fell back**, which is the case a check written against
67
+ * the *asked-for* backend would miss: every fallback path here is a path where the pipeline
68
+ * became unavailable after the choice was made.
69
+ */
70
+ readonly pipeline?: RenderPipeline;
22
71
  /**
23
72
  * The query string to read `?backend=` from. Defaults to the document's own.
24
73
  *
@@ -116,6 +165,14 @@ export interface CreatedRenderer {
116
165
  * renderer knows.
117
166
  */
118
167
  readonly reversedDepth: boolean;
168
+ /**
169
+ * Which pipeline is drawing: the forward path, or the one driven from buffers the GPU wrote.
170
+ *
171
+ * Reported for the same reason `backend` is — a consumer who asked for one and got the other
172
+ * has to be able to find out. They cannot, here: asking for `gpu-driven` on a backend that
173
+ * cannot run it throws rather than answering `forward`. See `CreateRendererOptions.pipeline`.
174
+ */
175
+ readonly pipeline: RenderPipeline;
119
176
  }
120
177
  /**
121
178
  * Build a renderer on the best backend this browser will actually give us.
@@ -3,6 +3,35 @@ import { resolveRenderQuality } from '../renderQuality.js';
3
3
  import { BACKEND_TIMEOUT_MS, forcedBackend, selectBackend } from './select.js';
4
4
  import { TIMED_OUT, withDeadline } from './deadline.js';
5
5
  import { mountSplash } from '../../ui/splash.js';
6
+ import { gpuDrivenRefusal, gpuDrivenSupported } from '../gpudriven/pipeline.js';
7
+ /**
8
+ * What a caller who says nothing gets.
9
+ *
10
+ * **A named constant rather than a literal in the `??`**, because the literal is unreachable from
11
+ * a test here: nothing in this environment resolves a renderer, so flipping it changed no answer
12
+ * and no test noticed. The constant is where the decision lives and it is asserted directly.
13
+ *
14
+ * Forward, and it stays forward until the second pipeline has drawn the six published scenes.
15
+ */
16
+ export const DEFAULT_PIPELINE = 'forward';
17
+ /**
18
+ * Why a requested pipeline cannot run on the backend that is about to draw, or null where it can.
19
+ *
20
+ * **Its own function because it is the only part of the decision a test in this environment can
21
+ * reach.** Nothing here can resolve a renderer — there is no GL context and no adapter — so every
22
+ * test of `createRenderer` ends in a rejection, and a check that lives only inside the factory is
23
+ * a check nothing exercises. `built` is this function's one caller and every return from the
24
+ * factory passes through it.
25
+ *
26
+ * **The backend is the one that will draw, not the one that was asked for.** Three paths into
27
+ * `built` arrive having fallen back from WebGPU, and a check written against the request passes on
28
+ * all three.
29
+ */
30
+ export function pipelineRefusal(pipeline, backend, reason) {
31
+ if (pipeline !== 'gpu-driven' || gpuDrivenSupported(backend))
32
+ return null;
33
+ return `[driftengine] ${gpuDrivenRefusal(backend)} (${reason})`;
34
+ }
6
35
  /**
7
36
  * Hand the badge the one fact it is waiting for: a frame reached the screen.
8
37
  *
@@ -60,7 +89,22 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
60
89
  * the two failure paths — a fallback still paints, and a badge that outlived a fallback would
61
90
  * sit on the screen until the cap for a game that was running perfectly well underneath it.
62
91
  */
92
+ const pipeline = options.pipeline ?? DEFAULT_PIPELINE;
63
93
  const built = (result) => {
94
+ /*
95
+ * **Checked here rather than at the top, because every return passes through here.** The
96
+ * question is not which backend was *asked for* — it is which one is about to draw, and three
97
+ * of the paths into this function arrive having fallen back. A check against the request would
98
+ * pass on all three and hand back a forward renderer with `pipeline: 'gpu-driven'` on it.
99
+ *
100
+ * The splash goes down first. A page that throws out of `createRenderer` with a badge mounted
101
+ * leaves it on screen over nothing, for as long as the tab is open.
102
+ */
103
+ const refused = pipelineRefusal(pipeline, result.backend, result.reason);
104
+ if (refused !== null) {
105
+ splash?.present();
106
+ throw new Error(refused);
107
+ }
64
108
  if (splash !== null)
65
109
  presentOnFirstFrame(result.renderer, splash);
66
110
  /*
@@ -80,6 +124,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
80
124
  ...result,
81
125
  rendererName: result.renderer.rendererName,
82
126
  reversedDepth: result.renderer.reversedDepth,
127
+ pipeline,
83
128
  };
84
129
  };
85
130
  /*
@@ -93,7 +138,11 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
93
138
  * the promise the deadline was racing.
94
139
  */
95
140
  const budgetMs = options.backendTimeoutMs ?? BACKEND_TIMEOUT_MS;
96
- const startedAt = Date.now();
141
+ /* Monotonic, and it has to be: `budgetMs - spent` below subtracts two readings. The wall clock
142
+ steps — daylight saving, an NTP correction, a laptop resuming with a stale clock — and a
143
+ forward step makes `spent` exceed the budget, so the engine falls back to WebGL2 reporting
144
+ "WebGPU stalled" about a device that was fine. */
145
+ const startedAt = performance.now();
97
146
  const choice = await selectBackend(search, options.preferWebGpu ?? true, quality.gpuTiming ?? false, options.probeShaders ?? [], budgetMs);
98
147
  if (choice.backend === 'webgpu' && choice.device !== null) {
99
148
  /*
@@ -131,7 +180,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
131
180
  stage = 'constructing the renderer';
132
181
  return { surface, WebGPURenderer };
133
182
  })();
134
- const spent = Date.now() - startedAt;
183
+ const spent = performance.now() - startedAt;
135
184
  const settled = await withDeadline(construction, budgetMs - spent);
136
185
  if (settled === TIMED_OUT) {
137
186
  device.destroy();