@driftengine/core 3.61.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 (955) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/README.md +9 -0
  4. package/dist/behavior/behaviorTree.d.ts +140 -0
  5. package/dist/behavior/behaviorTree.js +289 -0
  6. package/dist/build/shaderComments.d.ts +64 -0
  7. package/dist/build/shaderComments.js +0 -0
  8. package/dist/cinematic/player.d.ts +80 -0
  9. package/dist/cinematic/player.js +184 -0
  10. package/dist/cinematic/script.d.ts +63 -0
  11. package/dist/cinematic/script.js +141 -0
  12. package/dist/core/bootGate.d.ts +37 -0
  13. package/dist/core/bootGate.js +47 -0
  14. package/dist/core/loadTracker.d.ts +78 -0
  15. package/dist/core/loadTracker.js +106 -0
  16. package/dist/core/loop.d.ts +118 -0
  17. package/dist/core/loop.js +84 -0
  18. package/dist/core/messageQueue.d.ts +61 -0
  19. package/dist/core/messageQueue.js +104 -0
  20. package/dist/core/onceSet.d.ts +27 -0
  21. package/dist/core/onceSet.js +62 -0
  22. package/dist/core/preferences.d.ts +47 -0
  23. package/dist/core/preferences.js +140 -0
  24. package/dist/core/remoteSave.d.ts +154 -0
  25. package/dist/core/remoteSave.js +249 -0
  26. package/dist/core/rng.d.ts +64 -0
  27. package/dist/core/rng.js +72 -0
  28. package/dist/core/stepBudget.d.ts +91 -0
  29. package/dist/core/stepBudget.js +105 -0
  30. package/dist/core/storage.d.ts +52 -0
  31. package/dist/core/storage.js +85 -0
  32. package/dist/core/tickTrace.d.ts +72 -0
  33. package/dist/core/tickTrace.js +102 -0
  34. package/dist/core/timeCurve.d.ts +83 -0
  35. package/dist/core/timeCurve.js +107 -0
  36. package/dist/core/withDefaults.d.ts +21 -0
  37. package/dist/core/withDefaults.js +29 -0
  38. package/dist/dev/contactProbe.d.ts +41 -0
  39. package/dist/dev/contactProbe.js +58 -0
  40. package/dist/dev/fpsMeter.d.ts +45 -0
  41. package/dist/dev/fpsMeter.js +86 -0
  42. package/dist/environment/celestialClock.d.ts +141 -0
  43. package/dist/environment/celestialClock.js +262 -0
  44. package/dist/geometry/decal.d.ts +61 -0
  45. package/dist/geometry/decal.js +178 -0
  46. package/dist/geometry/filmPatch.d.ts +35 -0
  47. package/dist/geometry/filmPatch.js +112 -0
  48. package/dist/geometry/growable.d.ts +70 -0
  49. package/dist/geometry/growable.js +167 -0
  50. package/dist/geometry/lightVolume.d.ts +76 -0
  51. package/dist/geometry/lightVolume.js +65 -0
  52. package/dist/geometry/meshBuilder.d.ts +426 -0
  53. package/dist/geometry/meshBuilder.js +1184 -0
  54. package/dist/geometry/pixelFont.d.ts +59 -0
  55. package/dist/geometry/pixelFont.js +179 -0
  56. package/dist/geometry/ribbon.d.ts +101 -0
  57. package/dist/geometry/ribbon.js +546 -0
  58. package/dist/geometry/shellFill.d.ts +101 -0
  59. package/dist/geometry/shellFill.js +203 -0
  60. package/dist/geometry/spline.d.ts +162 -0
  61. package/dist/geometry/spline.js +527 -0
  62. package/dist/geometry/tangents.d.ts +30 -0
  63. package/dist/geometry/tangents.js +142 -0
  64. package/dist/geometry/textMesh.d.ts +51 -0
  65. package/dist/geometry/textMesh.js +57 -0
  66. package/dist/geometry/treeBuilder.d.ts +37 -0
  67. package/dist/geometry/treeBuilder.js +56 -0
  68. package/dist/host/display.d.ts +135 -0
  69. package/dist/host/display.js +114 -0
  70. package/dist/host/files.d.ts +25 -0
  71. package/dist/host/files.js +44 -0
  72. package/dist/host/lifecycle.d.ts +45 -0
  73. package/dist/host/lifecycle.js +28 -0
  74. package/dist/host/platformServices.d.ts +23 -0
  75. package/dist/host/platformServices.js +1 -0
  76. package/dist/host/screen.d.ts +49 -0
  77. package/dist/host/screen.js +90 -0
  78. package/dist/index.d.ts +289 -0
  79. package/dist/index.js +320 -0
  80. package/dist/input/actionMap.d.ts +181 -0
  81. package/dist/input/actionMap.js +314 -0
  82. package/dist/input/activeDevice.d.ts +55 -0
  83. package/dist/input/activeDevice.js +83 -0
  84. package/dist/input/gamepadIdentity.d.ts +43 -0
  85. package/dist/input/gamepadIdentity.js +108 -0
  86. package/dist/input/gamepadMapping.d.ts +56 -0
  87. package/dist/input/gamepadMapping.js +91 -0
  88. package/dist/input/input.d.ts +281 -0
  89. package/dist/input/input.js +703 -0
  90. package/dist/input/inputHarness.d.ts +42 -0
  91. package/dist/input/inputHarness.js +193 -0
  92. package/dist/input/rightGesture.d.ts +57 -0
  93. package/dist/input/rightGesture.js +49 -0
  94. package/dist/input/rumble.d.ts +71 -0
  95. package/dist/input/rumble.js +119 -0
  96. package/dist/input/touchControls.d.ts +138 -0
  97. package/dist/input/touchControls.js +352 -0
  98. package/dist/input/typingTarget.d.ts +6 -0
  99. package/dist/input/typingTarget.js +27 -0
  100. package/dist/math/bounds.d.ts +61 -0
  101. package/dist/math/bounds.js +121 -0
  102. package/dist/math/color.d.ts +8 -0
  103. package/dist/math/color.js +35 -0
  104. package/dist/math/exact.d.ts +66 -0
  105. package/dist/math/exact.js +262 -0
  106. package/dist/math/frustum.d.ts +44 -0
  107. package/dist/math/frustum.js +90 -0
  108. package/dist/math/intersect.d.ts +76 -0
  109. package/dist/math/intersect.js +185 -0
  110. package/dist/math/scalar.d.ts +51 -0
  111. package/dist/math/scalar.js +99 -0
  112. package/dist/math/spring.d.ts +59 -0
  113. package/dist/math/spring.js +88 -0
  114. package/dist/nav/navGraph.d.ts +71 -0
  115. package/dist/nav/navGraph.js +111 -0
  116. package/dist/nav/navPath.d.ts +93 -0
  117. package/dist/nav/navPath.js +162 -0
  118. package/dist/nav/navSearch.d.ts +74 -0
  119. package/dist/nav/navSearch.js +198 -0
  120. package/dist/physics/boxSurface.d.ts +48 -0
  121. package/dist/physics/boxSurface.js +73 -0
  122. package/dist/physics/colliderSurface.d.ts +46 -0
  123. package/dist/physics/colliderSurface.js +146 -0
  124. package/dist/physics/compositeSurface.d.ts +33 -0
  125. package/dist/physics/compositeSurface.js +108 -0
  126. package/dist/physics/heightSurface.d.ts +103 -0
  127. package/dist/physics/heightSurface.js +153 -0
  128. package/dist/physics/ribbonSurface.d.ts +239 -0
  129. package/dist/physics/ribbonSurface.js +522 -0
  130. package/dist/render/ambientOcclusionPass.d.ts +53 -0
  131. package/dist/render/ambientOcclusionPass.js +179 -0
  132. package/dist/render/areaLights.d.ts +116 -0
  133. package/dist/render/areaLights.js +91 -0
  134. package/dist/render/areaShadowSet.d.ts +184 -0
  135. package/dist/render/areaShadowSet.js +277 -0
  136. package/dist/render/atmosphere.d.ts +94 -0
  137. package/dist/render/atmosphere.js +91 -0
  138. package/dist/render/backend/api.d.ts +496 -0
  139. package/dist/render/backend/api.js +1 -0
  140. package/dist/render/backend/budget.d.ts +82 -0
  141. package/dist/render/backend/budget.js +99 -0
  142. package/dist/render/backend/createRenderer.d.ts +135 -0
  143. package/dist/render/backend/createRenderer.js +201 -0
  144. package/dist/render/backend/deadline.d.ts +24 -0
  145. package/dist/render/backend/deadline.js +38 -0
  146. package/dist/render/backend/probe.d.ts +30 -0
  147. package/dist/render/backend/probe.js +129 -0
  148. package/dist/render/backend/select.d.ts +70 -0
  149. package/dist/render/backend/select.js +249 -0
  150. package/dist/render/backend/timer.d.ts +50 -0
  151. package/dist/render/backend/timer.js +1 -0
  152. package/dist/render/backend/webgl2/instanced.d.ts +21 -0
  153. package/dist/render/backend/webgl2/instanced.js +42 -0
  154. package/dist/render/backend/webgl2/morphTexture.d.ts +21 -0
  155. package/dist/render/backend/webgl2/morphTexture.js +55 -0
  156. package/dist/render/backend/webgl2/renderer.d.ts +3027 -0
  157. package/dist/render/backend/webgl2/renderer.js +6041 -0
  158. package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +32 -0
  159. package/dist/render/backend/webgl2/skinPaletteTexture.js +68 -0
  160. package/dist/render/backend/webgpu/boltPass.d.ts +42 -0
  161. package/dist/render/backend/webgpu/boltPass.js +160 -0
  162. package/dist/render/backend/webgpu/buffers.d.ts +159 -0
  163. package/dist/render/backend/webgpu/buffers.js +402 -0
  164. package/dist/render/backend/webgpu/causticsPass.d.ts +36 -0
  165. package/dist/render/backend/webgpu/causticsPass.js +138 -0
  166. package/dist/render/backend/webgpu/clusterBinner.d.ts +51 -0
  167. package/dist/render/backend/webgpu/clusterBinner.js +206 -0
  168. package/dist/render/backend/webgpu/depthPass.d.ts +114 -0
  169. package/dist/render/backend/webgpu/depthPass.js +228 -0
  170. package/dist/render/backend/webgpu/device.d.ts +52 -0
  171. package/dist/render/backend/webgpu/device.js +121 -0
  172. package/dist/render/backend/webgpu/drawCommand.d.ts +43 -0
  173. package/dist/render/backend/webgpu/drawCommand.js +54 -0
  174. package/dist/render/backend/webgpu/environmentTexels.d.ts +28 -0
  175. package/dist/render/backend/webgpu/environmentTexels.js +79 -0
  176. package/dist/render/backend/webgpu/filmPass.d.ts +29 -0
  177. package/dist/render/backend/webgpu/filmPass.js +97 -0
  178. package/dist/render/backend/webgpu/flatPass.d.ts +213 -0
  179. package/dist/render/backend/webgpu/flatPass.js +482 -0
  180. package/dist/render/backend/webgpu/flockPass.d.ts +34 -0
  181. package/dist/render/backend/webgpu/flockPass.js +129 -0
  182. package/dist/render/backend/webgpu/gpuTimestamps.d.ts +94 -0
  183. package/dist/render/backend/webgpu/gpuTimestamps.js +213 -0
  184. package/dist/render/backend/webgpu/insetPass.d.ts +19 -0
  185. package/dist/render/backend/webgpu/insetPass.js +108 -0
  186. package/dist/render/backend/webgpu/instanced.d.ts +27 -0
  187. package/dist/render/backend/webgpu/instanced.js +49 -0
  188. package/dist/render/backend/webgpu/lightVolumePass.d.ts +75 -0
  189. package/dist/render/backend/webgpu/lightVolumePass.js +154 -0
  190. package/dist/render/backend/webgpu/linePass.d.ts +90 -0
  191. package/dist/render/backend/webgpu/linePass.js +220 -0
  192. package/dist/render/backend/webgpu/morphTexture.d.ts +18 -0
  193. package/dist/render/backend/webgpu/morphTexture.js +51 -0
  194. package/dist/render/backend/webgpu/panelPass.d.ts +37 -0
  195. package/dist/render/backend/webgpu/panelPass.js +114 -0
  196. package/dist/render/backend/webgpu/particlePass.d.ts +89 -0
  197. package/dist/render/backend/webgpu/particlePass.js +280 -0
  198. package/dist/render/backend/webgpu/pipelineCache.d.ts +93 -0
  199. package/dist/render/backend/webgpu/pipelineCache.js +140 -0
  200. package/dist/render/backend/webgpu/plumePass.d.ts +69 -0
  201. package/dist/render/backend/webgpu/plumePass.js +213 -0
  202. package/dist/render/backend/webgpu/pointShadowPass.d.ts +88 -0
  203. package/dist/render/backend/webgpu/pointShadowPass.js +280 -0
  204. package/dist/render/backend/webgpu/postPass.d.ts +342 -0
  205. package/dist/render/backend/webgpu/postPass.js +366 -0
  206. package/dist/render/backend/webgpu/probePass.d.ts +108 -0
  207. package/dist/render/backend/webgpu/probePass.js +188 -0
  208. package/dist/render/backend/webgpu/reflectionPass.d.ts +29 -0
  209. package/dist/render/backend/webgpu/reflectionPass.js +87 -0
  210. package/dist/render/backend/webgpu/renderer.d.ts +3082 -0
  211. package/dist/render/backend/webgpu/renderer.js +10911 -0
  212. package/dist/render/backend/webgpu/scatterPass.d.ts +95 -0
  213. package/dist/render/backend/webgpu/scatterPass.js +266 -0
  214. package/dist/render/backend/webgpu/sdfTextPass.d.ts +86 -0
  215. package/dist/render/backend/webgpu/sdfTextPass.js +190 -0
  216. package/dist/render/backend/webgpu/shaderModules.d.ts +9 -0
  217. package/dist/render/backend/webgpu/shaderModules.js +45 -0
  218. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +23 -0
  219. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +208 -0
  220. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +67 -0
  221. package/dist/render/backend/webgpu/skinPaletteRing.js +97 -0
  222. package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +17 -0
  223. package/dist/render/backend/webgpu/skinPaletteTexture.js +68 -0
  224. package/dist/render/backend/webgpu/skyPass.d.ts +102 -0
  225. package/dist/render/backend/webgpu/skyPass.js +70 -0
  226. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +41 -0
  227. package/dist/render/backend/webgpu/surfaceTexturePass.js +228 -0
  228. package/dist/render/backend/webgpu/textPass.d.ts +73 -0
  229. package/dist/render/backend/webgpu/textPass.js +190 -0
  230. package/dist/render/backend/webgpu/uniformRing.d.ts +133 -0
  231. package/dist/render/backend/webgpu/uniformRing.js +208 -0
  232. package/dist/render/backend/webgpu/waterPass.d.ts +73 -0
  233. package/dist/render/backend/webgpu/waterPass.js +160 -0
  234. package/dist/render/backend/webgpu/windStreakPass.d.ts +46 -0
  235. package/dist/render/backend/webgpu/windStreakPass.js +153 -0
  236. package/dist/render/billboard.d.ts +27 -0
  237. package/dist/render/billboard.js +79 -0
  238. package/dist/render/bloomChain.d.ts +66 -0
  239. package/dist/render/bloomChain.js +83 -0
  240. package/dist/render/bloomPass.d.ts +54 -0
  241. package/dist/render/bloomPass.js +219 -0
  242. package/dist/render/boltBatch.d.ts +39 -0
  243. package/dist/render/boltBatch.js +121 -0
  244. package/dist/render/boltPool.d.ts +135 -0
  245. package/dist/render/boltPool.js +259 -0
  246. package/dist/render/boom.d.ts +46 -0
  247. package/dist/render/boom.js +81 -0
  248. package/dist/render/camera.d.ts +119 -0
  249. package/dist/render/camera.js +304 -0
  250. package/dist/render/causticsRenderer.d.ts +63 -0
  251. package/dist/render/causticsRenderer.js +119 -0
  252. package/dist/render/cinematicCamera.d.ts +102 -0
  253. package/dist/render/cinematicCamera.js +227 -0
  254. package/dist/render/clusteredLights.d.ts +260 -0
  255. package/dist/render/clusteredLights.js +479 -0
  256. package/dist/render/colourGrade.d.ts +62 -0
  257. package/dist/render/colourGrade.js +91 -0
  258. package/dist/render/compute.d.ts +74 -0
  259. package/dist/render/compute.js +8 -0
  260. package/dist/render/contextLoss.d.ts +32 -0
  261. package/dist/render/contextLoss.js +46 -0
  262. package/dist/render/debugLines.d.ts +75 -0
  263. package/dist/render/debugLines.js +281 -0
  264. package/dist/render/decalPass.d.ts +34 -0
  265. package/dist/render/decalPass.js +103 -0
  266. package/dist/render/decalProjector.d.ts +140 -0
  267. package/dist/render/decalProjector.js +282 -0
  268. package/dist/render/decalQueue.d.ts +53 -0
  269. package/dist/render/decalQueue.js +87 -0
  270. package/dist/render/depthConvention.d.ts +314 -0
  271. package/dist/render/depthConvention.js +346 -0
  272. package/dist/render/drawingBuffer.d.ts +52 -0
  273. package/dist/render/drawingBuffer.js +67 -0
  274. package/dist/render/emptyTexture.d.ts +60 -0
  275. package/dist/render/emptyTexture.js +103 -0
  276. package/dist/render/envProbeArray.d.ts +85 -0
  277. package/dist/render/envProbeArray.js +164 -0
  278. package/dist/render/equirectToCube.d.ts +54 -0
  279. package/dist/render/equirectToCube.js +123 -0
  280. package/dist/render/flockGeometry.d.ts +23 -0
  281. package/dist/render/flockGeometry.js +43 -0
  282. package/dist/render/flockRenderer.d.ts +37 -0
  283. package/dist/render/flockRenderer.js +70 -0
  284. package/dist/render/frame/arena.d.ts +32 -0
  285. package/dist/render/frame/arena.js +65 -0
  286. package/dist/render/frame/index.d.ts +18 -0
  287. package/dist/render/frame/index.js +4 -0
  288. package/dist/render/frame/replay.d.ts +34 -0
  289. package/dist/render/frame/replay.js +48 -0
  290. package/dist/render/frame/resources.d.ts +25 -0
  291. package/dist/render/frame/resources.js +55 -0
  292. package/dist/render/frame/schedule.d.ts +37 -0
  293. package/dist/render/frame/schedule.js +61 -0
  294. package/dist/render/frameView.d.ts +19 -0
  295. package/dist/render/frameView.js +1 -0
  296. package/dist/render/gizmo.d.ts +236 -0
  297. package/dist/render/gizmo.js +727 -0
  298. package/dist/render/globalMedium.d.ts +124 -0
  299. package/dist/render/globalMedium.js +100 -0
  300. package/dist/render/globalMediumPass.d.ts +101 -0
  301. package/dist/render/globalMediumPass.js +250 -0
  302. package/dist/render/gpuCapability.d.ts +111 -0
  303. package/dist/render/gpuCapability.js +194 -0
  304. package/dist/render/gpuTimer.d.ts +87 -0
  305. package/dist/render/gpuTimer.js +145 -0
  306. package/dist/render/halfFloat.d.ts +4 -0
  307. package/dist/render/halfFloat.js +38 -0
  308. package/dist/render/handleRegistry.d.ts +54 -0
  309. package/dist/render/handleRegistry.js +84 -0
  310. package/dist/render/iesProfile.d.ts +64 -0
  311. package/dist/render/iesProfile.js +179 -0
  312. package/dist/render/imageTexels.d.ts +50 -0
  313. package/dist/render/imageTexels.js +91 -0
  314. package/dist/render/instancedMesh.d.ts +48 -0
  315. package/dist/render/instancedMesh.js +127 -0
  316. package/dist/render/instances.d.ts +69 -0
  317. package/dist/render/instances.js +52 -0
  318. package/dist/render/lightBudget.d.ts +397 -0
  319. package/dist/render/lightBudget.js +524 -0
  320. package/dist/render/lightMatrix.d.ts +3 -0
  321. package/dist/render/lightMatrix.js +45 -0
  322. package/dist/render/lightVolumeDraw.d.ts +132 -0
  323. package/dist/render/lightVolumeDraw.js +181 -0
  324. package/dist/render/lineBatch.d.ts +60 -0
  325. package/dist/render/lineBatch.js +160 -0
  326. package/dist/render/linePoints.d.ts +33 -0
  327. package/dist/render/linePoints.js +46 -0
  328. package/dist/render/livePointShadowSet.d.ts +72 -0
  329. package/dist/render/livePointShadowSet.js +258 -0
  330. package/dist/render/lod.d.ts +35 -0
  331. package/dist/render/lod.js +65 -0
  332. package/dist/render/mesh.d.ts +177 -0
  333. package/dist/render/mesh.js +466 -0
  334. package/dist/render/occlusion.d.ts +81 -0
  335. package/dist/render/occlusion.js +378 -0
  336. package/dist/render/oitPass.d.ts +67 -0
  337. package/dist/render/oitPass.js +213 -0
  338. package/dist/render/orderIndependent.d.ts +92 -0
  339. package/dist/render/orderIndependent.js +108 -0
  340. package/dist/render/particleBatch.d.ts +140 -0
  341. package/dist/render/particleBatch.js +186 -0
  342. package/dist/render/particleMaterial.d.ts +54 -0
  343. package/dist/render/particleMaterial.js +42 -0
  344. package/dist/render/particlePool.d.ts +124 -0
  345. package/dist/render/particlePool.js +182 -0
  346. package/dist/render/pass.d.ts +195 -0
  347. package/dist/render/pass.js +9 -0
  348. package/dist/render/passTarget.d.ts +86 -0
  349. package/dist/render/passTarget.js +121 -0
  350. package/dist/render/pickable.d.ts +31 -0
  351. package/dist/render/pickable.js +172 -0
  352. package/dist/render/planarReflection.d.ts +59 -0
  353. package/dist/render/planarReflection.js +194 -0
  354. package/dist/render/planarReflectionDraw.d.ts +31 -0
  355. package/dist/render/planarReflectionDraw.js +65 -0
  356. package/dist/render/plumeGeometry.d.ts +25 -0
  357. package/dist/render/plumeGeometry.js +61 -0
  358. package/dist/render/plumeMaterial.d.ts +31 -0
  359. package/dist/render/plumeMaterial.js +64 -0
  360. package/dist/render/plumeRenderer.d.ts +96 -0
  361. package/dist/render/plumeRenderer.js +185 -0
  362. package/dist/render/pointLightSelection.d.ts +175 -0
  363. package/dist/render/pointLightSelection.js +301 -0
  364. package/dist/render/pointShadowArray.d.ts +95 -0
  365. package/dist/render/pointShadowArray.js +219 -0
  366. package/dist/render/pointShadowBudget.d.ts +118 -0
  367. package/dist/render/pointShadowBudget.js +221 -0
  368. package/dist/render/pointShadowImage.d.ts +265 -0
  369. package/dist/render/pointShadowImage.js +339 -0
  370. package/dist/render/pointShadowMap.d.ts +93 -0
  371. package/dist/render/pointShadowMap.js +167 -0
  372. package/dist/render/pointShadowSystem.d.ts +195 -0
  373. package/dist/render/pointShadowSystem.js +336 -0
  374. package/dist/render/prefilterEnvMap.d.ts +124 -0
  375. package/dist/render/prefilterEnvMap.js +146 -0
  376. package/dist/render/prefilterPass.d.ts +44 -0
  377. package/dist/render/prefilterPass.js +98 -0
  378. package/dist/render/probeGrid.d.ts +122 -0
  379. package/dist/render/probeGrid.js +174 -0
  380. package/dist/render/rainField.d.ts +99 -0
  381. package/dist/render/rainField.js +168 -0
  382. package/dist/render/reflectionProbe.d.ts +188 -0
  383. package/dist/render/reflectionProbe.js +437 -0
  384. package/dist/render/renderQuality.d.ts +699 -0
  385. package/dist/render/renderQuality.js +293 -0
  386. package/dist/render/rendererHarness.d.ts +39 -0
  387. package/dist/render/rendererHarness.js +185 -0
  388. package/dist/render/resolutionGovernor.d.ts +107 -0
  389. package/dist/render/resolutionGovernor.js +144 -0
  390. package/dist/render/scatterDeform.d.ts +17 -0
  391. package/dist/render/scatterDeform.js +46 -0
  392. package/dist/render/sceneTarget.d.ts +288 -0
  393. package/dist/render/sceneTarget.js +856 -0
  394. package/dist/render/screenSpaceReflection.d.ts +233 -0
  395. package/dist/render/screenSpaceReflection.js +415 -0
  396. package/dist/render/sdfFont.d.ts +77 -0
  397. package/dist/render/sdfFont.js +86 -0
  398. package/dist/render/sdfTextLayout.d.ts +46 -0
  399. package/dist/render/sdfTextLayout.js +145 -0
  400. package/dist/render/sdfTextRenderer.d.ts +75 -0
  401. package/dist/render/sdfTextRenderer.js +194 -0
  402. package/dist/render/seaState.d.ts +25 -0
  403. package/dist/render/seaState.js +34 -0
  404. package/dist/render/segmentQuads.d.ts +29 -0
  405. package/dist/render/segmentQuads.js +75 -0
  406. package/dist/render/shader.d.ts +5 -0
  407. package/dist/render/shader.js +172 -0
  408. package/dist/render/shaders/ambientOcclusion.d.ts +45 -0
  409. package/dist/render/shaders/ambientOcclusion.js +352 -0
  410. package/dist/render/shaders/arcane.d.ts +19 -0
  411. package/dist/render/shaders/arcane.js +102 -0
  412. package/dist/render/shaders/bloom.d.ts +70 -0
  413. package/dist/render/shaders/bloom.js +227 -0
  414. package/dist/render/shaders/bolt.d.ts +17 -0
  415. package/dist/render/shaders/bolt.js +161 -0
  416. package/dist/render/shaders/caustics.d.ts +38 -0
  417. package/dist/render/shaders/caustics.js +167 -0
  418. package/dist/render/shaders/conditionals.d.ts +21 -0
  419. package/dist/render/shaders/conditionals.js +55 -0
  420. package/dist/render/shaders/decalProject.d.ts +25 -0
  421. package/dist/render/shaders/decalProject.js +125 -0
  422. package/dist/render/shaders/depth.d.ts +14 -0
  423. package/dist/render/shaders/depth.js +114 -0
  424. package/dist/render/shaders/depthOfField.d.ts +41 -0
  425. package/dist/render/shaders/depthOfField.js +139 -0
  426. package/dist/render/shaders/film.d.ts +15 -0
  427. package/dist/render/shaders/film.js +283 -0
  428. package/dist/render/shaders/fire.d.ts +12 -0
  429. package/dist/render/shaders/fire.js +178 -0
  430. package/dist/render/shaders/flat/directionalShadow.d.ts +1 -0
  431. package/dist/render/shaders/flat/directionalShadow.js +195 -0
  432. package/dist/render/shaders/flat/index.d.ts +135 -0
  433. package/dist/render/shaders/flat/index.js +387 -0
  434. package/dist/render/shaders/flat/lobes.d.ts +1 -0
  435. package/dist/render/shaders/flat/lobes.js +398 -0
  436. package/dist/render/shaders/flat/main.d.ts +2 -0
  437. package/dist/render/shaders/flat/main.js +1630 -0
  438. package/dist/render/shaders/flat/pointShadow.d.ts +1 -0
  439. package/dist/render/shaders/flat/pointShadow.js +322 -0
  440. package/dist/render/shaders/flat/preamble.d.ts +15 -0
  441. package/dist/render/shaders/flat/preamble.js +864 -0
  442. package/dist/render/shaders/flat/probeGrid.d.ts +21 -0
  443. package/dist/render/shaders/flat/probeGrid.js +151 -0
  444. package/dist/render/shaders/flat/surface.d.ts +2 -0
  445. package/dist/render/shaders/flat/surface.js +40 -0
  446. package/dist/render/shaders/flock.d.ts +11 -0
  447. package/dist/render/shaders/flock.js +102 -0
  448. package/dist/render/shaders/fog.d.ts +37 -0
  449. package/dist/render/shaders/fog.js +98 -0
  450. package/dist/render/shaders/fullscreen.d.ts +16 -0
  451. package/dist/render/shaders/fullscreen.js +27 -0
  452. package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +65 -0
  453. package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +71 -0
  454. package/dist/render/shaders/generated/arcane.wgsl.d.ts +90 -0
  455. package/dist/render/shaders/generated/arcane.wgsl.js +96 -0
  456. package/dist/render/shaders/generated/bloom.wgsl.d.ts +69 -0
  457. package/dist/render/shaders/generated/bloom.wgsl.js +75 -0
  458. package/dist/render/shaders/generated/bolt.wgsl.d.ts +118 -0
  459. package/dist/render/shaders/generated/bolt.wgsl.js +124 -0
  460. package/dist/render/shaders/generated/caustics.wgsl.d.ts +118 -0
  461. package/dist/render/shaders/generated/caustics.wgsl.js +124 -0
  462. package/dist/render/shaders/generated/decalProject.wgsl.d.ts +61 -0
  463. package/dist/render/shaders/generated/decalProject.wgsl.js +67 -0
  464. package/dist/render/shaders/generated/depth.wgsl.d.ts +131 -0
  465. package/dist/render/shaders/generated/depth.wgsl.js +137 -0
  466. package/dist/render/shaders/generated/film.wgsl.d.ts +134 -0
  467. package/dist/render/shaders/generated/film.wgsl.js +140 -0
  468. package/dist/render/shaders/generated/fire.wgsl.d.ts +128 -0
  469. package/dist/render/shaders/generated/fire.wgsl.js +134 -0
  470. package/dist/render/shaders/generated/flat.wgsl.d.ts +9163 -0
  471. package/dist/render/shaders/generated/flat.wgsl.js +9192 -0
  472. package/dist/render/shaders/generated/flock.wgsl.d.ts +73 -0
  473. package/dist/render/shaders/generated/flock.wgsl.js +79 -0
  474. package/dist/render/shaders/generated/fullscreen.wgsl.d.ts +12 -0
  475. package/dist/render/shaders/generated/fullscreen.wgsl.js +18 -0
  476. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +130 -0
  477. package/dist/render/shaders/generated/globalMedium.wgsl.js +136 -0
  478. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +230 -0
  479. package/dist/render/shaders/generated/lightVolume.wgsl.js +239 -0
  480. package/dist/render/shaders/generated/line.wgsl.d.ts +128 -0
  481. package/dist/render/shaders/generated/line.wgsl.js +134 -0
  482. package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +51 -0
  483. package/dist/render/shaders/generated/octahedralResolve.wgsl.js +57 -0
  484. package/dist/render/shaders/generated/oitResolve.wgsl.d.ts +23 -0
  485. package/dist/render/shaders/generated/oitResolve.wgsl.js +29 -0
  486. package/dist/render/shaders/generated/panel.wgsl.d.ts +48 -0
  487. package/dist/render/shaders/generated/panel.wgsl.js +54 -0
  488. package/dist/render/shaders/generated/particle.wgsl.d.ts +332 -0
  489. package/dist/render/shaders/generated/particle.wgsl.js +338 -0
  490. package/dist/render/shaders/generated/prefilter.wgsl.d.ts +61 -0
  491. package/dist/render/shaders/generated/prefilter.wgsl.js +67 -0
  492. package/dist/render/shaders/generated/rush.wgsl.d.ts +131 -0
  493. package/dist/render/shaders/generated/rush.wgsl.js +137 -0
  494. package/dist/render/shaders/generated/scatter.wgsl.d.ts +195 -0
  495. package/dist/render/shaders/generated/scatter.wgsl.js +201 -0
  496. package/dist/render/shaders/generated/sdfText.wgsl.d.ts +69 -0
  497. package/dist/render/shaders/generated/sdfText.wgsl.js +75 -0
  498. package/dist/render/shaders/generated/sky.wgsl.d.ts +100 -0
  499. package/dist/render/shaders/generated/sky.wgsl.js +106 -0
  500. package/dist/render/shaders/generated/smoke.wgsl.d.ts +85 -0
  501. package/dist/render/shaders/generated/smoke.wgsl.js +91 -0
  502. package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +18 -0
  503. package/dist/render/shaders/generated/ssrResolve.wgsl.js +24 -0
  504. package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +86 -0
  505. package/dist/render/shaders/generated/ssrTrace.wgsl.js +92 -0
  506. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +46 -0
  507. package/dist/render/shaders/generated/temporalResolve.wgsl.js +52 -0
  508. package/dist/render/shaders/generated/text.wgsl.d.ts +98 -0
  509. package/dist/render/shaders/generated/text.wgsl.js +104 -0
  510. package/dist/render/shaders/generated/water.wgsl.d.ts +247 -0
  511. package/dist/render/shaders/generated/water.wgsl.js +253 -0
  512. package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +73 -0
  513. package/dist/render/shaders/generated/windStreaks.wgsl.js +79 -0
  514. package/dist/render/shaders/gerstner.d.ts +21 -0
  515. package/dist/render/shaders/gerstner.js +110 -0
  516. package/dist/render/shaders/globalMedium.d.ts +56 -0
  517. package/dist/render/shaders/globalMedium.js +393 -0
  518. package/dist/render/shaders/lightVolume.d.ts +61 -0
  519. package/dist/render/shaders/lightVolume.js +527 -0
  520. package/dist/render/shaders/line.d.ts +18 -0
  521. package/dist/render/shaders/line.js +122 -0
  522. package/dist/render/shaders/morph.d.ts +26 -0
  523. package/dist/render/shaders/morph.js +61 -0
  524. package/dist/render/shaders/octahedral.d.ts +76 -0
  525. package/dist/render/shaders/octahedral.js +161 -0
  526. package/dist/render/shaders/octahedralResolve.d.ts +25 -0
  527. package/dist/render/shaders/octahedralResolve.js +81 -0
  528. package/dist/render/shaders/oitResolve.d.ts +17 -0
  529. package/dist/render/shaders/oitResolve.js +42 -0
  530. package/dist/render/shaders/outputTransform.d.ts +37 -0
  531. package/dist/render/shaders/outputTransform.js +106 -0
  532. package/dist/render/shaders/panel.d.ts +17 -0
  533. package/dist/render/shaders/panel.js +50 -0
  534. package/dist/render/shaders/particle.d.ts +82 -0
  535. package/dist/render/shaders/particle.js +431 -0
  536. package/dist/render/shaders/prefilter.d.ts +37 -0
  537. package/dist/render/shaders/prefilter.js +276 -0
  538. package/dist/render/shaders/rush.d.ts +21 -0
  539. package/dist/render/shaders/rush.js +355 -0
  540. package/dist/render/shaders/scatter.d.ts +14 -0
  541. package/dist/render/shaders/scatter.js +206 -0
  542. package/dist/render/shaders/sdfText.d.ts +9 -0
  543. package/dist/render/shaders/sdfText.js +65 -0
  544. package/dist/render/shaders/skinning.d.ts +17 -0
  545. package/dist/render/shaders/skinning.js +59 -0
  546. package/dist/render/shaders/sky.d.ts +10 -0
  547. package/dist/render/shaders/sky.js +242 -0
  548. package/dist/render/shaders/smoke.d.ts +8 -0
  549. package/dist/render/shaders/smoke.js +88 -0
  550. package/dist/render/shaders/ssrResolve.d.ts +15 -0
  551. package/dist/render/shaders/ssrResolve.js +28 -0
  552. package/dist/render/shaders/ssrTrace.d.ts +22 -0
  553. package/dist/render/shaders/ssrTrace.js +230 -0
  554. package/dist/render/shaders/tangentFrame.d.ts +17 -0
  555. package/dist/render/shaders/tangentFrame.js +70 -0
  556. package/dist/render/shaders/temporalResolve.d.ts +1 -0
  557. package/dist/render/shaders/temporalResolve.js +150 -0
  558. package/dist/render/shaders/text.d.ts +17 -0
  559. package/dist/render/shaders/text.js +155 -0
  560. package/dist/render/shaders/vertexChannel.d.ts +39 -0
  561. package/dist/render/shaders/vertexChannel.js +69 -0
  562. package/dist/render/shaders/water.d.ts +18 -0
  563. package/dist/render/shaders/water.js +354 -0
  564. package/dist/render/shaders/windStreaks.d.ts +14 -0
  565. package/dist/render/shaders/windStreaks.js +129 -0
  566. package/dist/render/shadowCasters.d.ts +107 -0
  567. package/dist/render/shadowCasters.js +1 -0
  568. package/dist/render/shadowMap.d.ts +10 -0
  569. package/dist/render/shadowMap.js +80 -0
  570. package/dist/render/shotPlacement.d.ts +80 -0
  571. package/dist/render/shotPlacement.js +183 -0
  572. package/dist/render/skinPalette.d.ts +90 -0
  573. package/dist/render/skinPalette.js +136 -0
  574. package/dist/render/ssrPass.d.ts +59 -0
  575. package/dist/render/ssrPass.js +196 -0
  576. package/dist/render/surfaceSheet.d.ts +52 -0
  577. package/dist/render/surfaceSheet.js +99 -0
  578. package/dist/render/surfaceTexture.d.ts +197 -0
  579. package/dist/render/surfaceTexture.js +116 -0
  580. package/dist/render/temporalAa.d.ts +104 -0
  581. package/dist/render/temporalAa.js +194 -0
  582. package/dist/render/temporalPass.d.ts +54 -0
  583. package/dist/render/temporalPass.js +135 -0
  584. package/dist/render/textLayout.d.ts +88 -0
  585. package/dist/render/textLayout.js +201 -0
  586. package/dist/render/textRenderer.d.ts +32 -0
  587. package/dist/render/textRenderer.js +176 -0
  588. package/dist/render/thirdPersonCamera.d.ts +272 -0
  589. package/dist/render/thirdPersonCamera.js +479 -0
  590. package/dist/render/trample.d.ts +57 -0
  591. package/dist/render/trample.js +134 -0
  592. package/dist/render/translucentQueue.d.ts +76 -0
  593. package/dist/render/translucentQueue.js +90 -0
  594. package/dist/render/uniformVectorBudget.d.ts +105 -0
  595. package/dist/render/uniformVectorBudget.js +201 -0
  596. package/dist/render/uploadStep.d.ts +14 -0
  597. package/dist/render/uploadStep.js +14 -0
  598. package/dist/render/vertexDefaults.d.ts +48 -0
  599. package/dist/render/vertexDefaults.js +111 -0
  600. package/dist/render/visibility.d.ts +22 -0
  601. package/dist/render/visibility.js +47 -0
  602. package/dist/render/waterDraw.d.ts +57 -0
  603. package/dist/render/waterDraw.js +102 -0
  604. package/dist/render/waterGrid.d.ts +62 -0
  605. package/dist/render/waterGrid.js +151 -0
  606. package/dist/render/waterRenderer.d.ts +163 -0
  607. package/dist/render/waterRenderer.js +165 -0
  608. package/dist/render/wind.d.ts +45 -0
  609. package/dist/render/wind.js +32 -0
  610. package/dist/render/windField.d.ts +34 -0
  611. package/dist/render/windField.js +13 -0
  612. package/dist/render/windStreakDraw.d.ts +73 -0
  613. package/dist/render/windStreakDraw.js +86 -0
  614. package/dist/render/windStreakRenderer.d.ts +37 -0
  615. package/dist/render/windStreakRenderer.js +86 -0
  616. package/dist/scene/node.d.ts +128 -0
  617. package/dist/scene/node.js +319 -0
  618. package/dist/scene/visit.d.ts +38 -0
  619. package/dist/scene/visit.js +43 -0
  620. package/dist/ui/clipMime.d.ts +46 -0
  621. package/dist/ui/clipMime.js +88 -0
  622. package/dist/ui/exportTarget.d.ts +305 -0
  623. package/dist/ui/exportTarget.js +368 -0
  624. package/dist/ui/frameOverlay.d.ts +59 -0
  625. package/dist/ui/frameOverlay.js +76 -0
  626. package/dist/ui/framePacer.d.ts +142 -0
  627. package/dist/ui/framePacer.js +284 -0
  628. package/dist/ui/frameRecorder.d.ts +188 -0
  629. package/dist/ui/frameRecorder.js +221 -0
  630. package/dist/ui/fullscreen.d.ts +72 -0
  631. package/dist/ui/fullscreen.js +92 -0
  632. package/dist/ui/pixelCursor.d.ts +28 -0
  633. package/dist/ui/pixelCursor.js +66 -0
  634. package/dist/ui/splash.d.ts +86 -0
  635. package/dist/ui/splash.js +300 -0
  636. package/dist/ui/stillFrame.d.ts +22 -0
  637. package/dist/ui/stillFrame.js +40 -0
  638. package/package.json +60 -0
  639. package/src/behavior/behaviorTree.ts +346 -0
  640. package/src/build/shaderComments.ts +0 -0
  641. package/src/cinematic/player.ts +209 -0
  642. package/src/cinematic/script.ts +231 -0
  643. package/src/core/bootGate.ts +49 -0
  644. package/src/core/loadTracker.ts +144 -0
  645. package/src/core/loop.ts +211 -0
  646. package/src/core/messageQueue.ts +145 -0
  647. package/src/core/onceSet.ts +65 -0
  648. package/src/core/preferences.ts +177 -0
  649. package/src/core/remoteSave.ts +347 -0
  650. package/src/core/rng.ts +101 -0
  651. package/src/core/stepBudget.ts +136 -0
  652. package/src/core/storage.ts +114 -0
  653. package/src/core/tickTrace.ts +129 -0
  654. package/src/core/timeCurve.ts +175 -0
  655. package/src/core/withDefaults.ts +28 -0
  656. package/src/dev/contactProbe.ts +115 -0
  657. package/src/dev/fpsMeter.ts +101 -0
  658. package/src/environment/celestialClock.ts +385 -0
  659. package/src/geometry/decal.ts +260 -0
  660. package/src/geometry/filmPatch.ts +158 -0
  661. package/src/geometry/growable.ts +165 -0
  662. package/src/geometry/lightVolume.ts +161 -0
  663. package/src/geometry/meshBuilder.ts +1397 -0
  664. package/src/geometry/pixelFont.ts +189 -0
  665. package/src/geometry/ribbon.ts +790 -0
  666. package/src/geometry/shellFill.ts +265 -0
  667. package/src/geometry/spline.ts +659 -0
  668. package/src/geometry/tangents.ts +173 -0
  669. package/src/geometry/textMesh.ts +96 -0
  670. package/src/geometry/treeBuilder.ts +114 -0
  671. package/src/host/display.ts +180 -0
  672. package/src/host/files.ts +77 -0
  673. package/src/host/lifecycle.ts +63 -0
  674. package/src/host/platformServices.ts +23 -0
  675. package/src/host/screen.ts +134 -0
  676. package/src/index.ts +730 -0
  677. package/src/input/actionMap.ts +377 -0
  678. package/src/input/activeDevice.ts +86 -0
  679. package/src/input/gamepadIdentity.ts +131 -0
  680. package/src/input/gamepadMapping.ts +121 -0
  681. package/src/input/input.ts +872 -0
  682. package/src/input/inputHarness.ts +226 -0
  683. package/src/input/rightGesture.ts +76 -0
  684. package/src/input/rumble.ts +138 -0
  685. package/src/input/touchControls.ts +451 -0
  686. package/src/input/typingTarget.ts +26 -0
  687. package/src/math/bounds.ts +153 -0
  688. package/src/math/color.ts +37 -0
  689. package/src/math/exact.ts +274 -0
  690. package/src/math/frustum.ts +115 -0
  691. package/src/math/intersect.ts +228 -0
  692. package/src/math/scalar.ts +109 -0
  693. package/src/math/spring.ts +106 -0
  694. package/src/nav/navGraph.ts +168 -0
  695. package/src/nav/navPath.ts +217 -0
  696. package/src/nav/navSearch.ts +200 -0
  697. package/src/physics/boxSurface.ts +96 -0
  698. package/src/physics/colliderSurface.ts +213 -0
  699. package/src/physics/compositeSurface.ts +111 -0
  700. package/src/physics/heightSurface.ts +234 -0
  701. package/src/physics/ribbonSurface.ts +642 -0
  702. package/src/render/ambientOcclusionPass.ts +200 -0
  703. package/src/render/areaLights.ts +194 -0
  704. package/src/render/areaShadowSet.ts +405 -0
  705. package/src/render/atmosphere.ts +186 -0
  706. package/src/render/backend/api.ts +802 -0
  707. package/src/render/backend/budget.ts +139 -0
  708. package/src/render/backend/createRenderer.ts +343 -0
  709. package/src/render/backend/deadline.ts +37 -0
  710. package/src/render/backend/probe.ts +152 -0
  711. package/src/render/backend/select.ts +288 -0
  712. package/src/render/backend/timer.ts +59 -0
  713. package/src/render/backend/webgl2/instanced.ts +46 -0
  714. package/src/render/backend/webgl2/morphTexture.ts +58 -0
  715. package/src/render/backend/webgl2/renderer.ts +7484 -0
  716. package/src/render/backend/webgl2/skinPaletteTexture.ts +70 -0
  717. package/src/render/backend/webgpu/boltPass.ts +205 -0
  718. package/src/render/backend/webgpu/buffers.ts +553 -0
  719. package/src/render/backend/webgpu/causticsPass.ts +174 -0
  720. package/src/render/backend/webgpu/clusterBinner.ts +259 -0
  721. package/src/render/backend/webgpu/depthPass.ts +261 -0
  722. package/src/render/backend/webgpu/device.ts +148 -0
  723. package/src/render/backend/webgpu/drawCommand.ts +79 -0
  724. package/src/render/backend/webgpu/environmentTexels.ts +96 -0
  725. package/src/render/backend/webgpu/filmPass.ts +123 -0
  726. package/src/render/backend/webgpu/flatPass.ts +635 -0
  727. package/src/render/backend/webgpu/flockPass.ts +163 -0
  728. package/src/render/backend/webgpu/gpuTimestamps.ts +255 -0
  729. package/src/render/backend/webgpu/insetPass.ts +123 -0
  730. package/src/render/backend/webgpu/instanced.ts +55 -0
  731. package/src/render/backend/webgpu/lightVolumePass.ts +203 -0
  732. package/src/render/backend/webgpu/linePass.ts +270 -0
  733. package/src/render/backend/webgpu/morphTexture.ts +61 -0
  734. package/src/render/backend/webgpu/panelPass.ts +138 -0
  735. package/src/render/backend/webgpu/particlePass.ts +370 -0
  736. package/src/render/backend/webgpu/pipelineCache.ts +152 -0
  737. package/src/render/backend/webgpu/plumePass.ts +292 -0
  738. package/src/render/backend/webgpu/pointShadowPass.ts +368 -0
  739. package/src/render/backend/webgpu/postPass.ts +470 -0
  740. package/src/render/backend/webgpu/probePass.ts +218 -0
  741. package/src/render/backend/webgpu/reflectionPass.ts +137 -0
  742. package/src/render/backend/webgpu/renderer.ts +13004 -0
  743. package/src/render/backend/webgpu/scatterPass.ts +354 -0
  744. package/src/render/backend/webgpu/sdfTextPass.ts +220 -0
  745. package/src/render/backend/webgpu/shaderModules.ts +49 -0
  746. package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +219 -0
  747. package/src/render/backend/webgpu/skinPaletteRing.ts +105 -0
  748. package/src/render/backend/webgpu/skinPaletteTexture.ts +79 -0
  749. package/src/render/backend/webgpu/skyPass.ts +85 -0
  750. package/src/render/backend/webgpu/surfaceTexturePass.ts +257 -0
  751. package/src/render/backend/webgpu/textPass.ts +224 -0
  752. package/src/render/backend/webgpu/uniformRing.ts +228 -0
  753. package/src/render/backend/webgpu/waterPass.ts +211 -0
  754. package/src/render/backend/webgpu/windStreakPass.ts +196 -0
  755. package/src/render/billboard.ts +108 -0
  756. package/src/render/bloomChain.ts +101 -0
  757. package/src/render/bloomPass.ts +256 -0
  758. package/src/render/boltBatch.ts +141 -0
  759. package/src/render/boltPool.ts +360 -0
  760. package/src/render/boom.ts +123 -0
  761. package/src/render/camera.ts +348 -0
  762. package/src/render/causticsRenderer.ts +171 -0
  763. package/src/render/cinematicCamera.ts +278 -0
  764. package/src/render/clusteredLights.ts +598 -0
  765. package/src/render/colourGrade.ts +109 -0
  766. package/src/render/compute.ts +83 -0
  767. package/src/render/contextLoss.ts +50 -0
  768. package/src/render/debugLines.ts +411 -0
  769. package/src/render/decalPass.ts +124 -0
  770. package/src/render/decalProjector.ts +390 -0
  771. package/src/render/decalQueue.ts +110 -0
  772. package/src/render/depthConvention.ts +383 -0
  773. package/src/render/drawingBuffer.ts +89 -0
  774. package/src/render/emptyTexture.ts +130 -0
  775. package/src/render/envProbeArray.ts +201 -0
  776. package/src/render/equirectToCube.ts +160 -0
  777. package/src/render/flockGeometry.ts +53 -0
  778. package/src/render/flockRenderer.ts +111 -0
  779. package/src/render/frame/arena.ts +93 -0
  780. package/src/render/frame/index.ts +29 -0
  781. package/src/render/frame/replay.ts +50 -0
  782. package/src/render/frame/resources.ts +61 -0
  783. package/src/render/frame/schedule.ts +85 -0
  784. package/src/render/frameView.ts +20 -0
  785. package/src/render/gizmo.ts +923 -0
  786. package/src/render/globalMedium.ts +154 -0
  787. package/src/render/globalMediumPass.ts +323 -0
  788. package/src/render/gpuCapability.ts +244 -0
  789. package/src/render/gpuTimer.ts +182 -0
  790. package/src/render/halfFloat.ts +39 -0
  791. package/src/render/handleRegistry.ts +96 -0
  792. package/src/render/iesProfile.ts +215 -0
  793. package/src/render/imageTexels.ts +109 -0
  794. package/src/render/instancedMesh.ts +187 -0
  795. package/src/render/instances.ts +92 -0
  796. package/src/render/lightBudget.ts +655 -0
  797. package/src/render/lightMatrix.ts +69 -0
  798. package/src/render/lightVolumeDraw.ts +216 -0
  799. package/src/render/lineBatch.ts +180 -0
  800. package/src/render/linePoints.ts +61 -0
  801. package/src/render/livePointShadowSet.ts +285 -0
  802. package/src/render/lod.ts +86 -0
  803. package/src/render/mesh.ts +536 -0
  804. package/src/render/occlusion.ts +406 -0
  805. package/src/render/oitPass.ts +230 -0
  806. package/src/render/orderIndependent.ts +136 -0
  807. package/src/render/particleBatch.ts +299 -0
  808. package/src/render/particleMaterial.ts +84 -0
  809. package/src/render/particlePool.ts +291 -0
  810. package/src/render/pass.ts +203 -0
  811. package/src/render/passTarget.ts +225 -0
  812. package/src/render/pickable.ts +222 -0
  813. package/src/render/planarReflection.ts +233 -0
  814. package/src/render/planarReflectionDraw.ts +87 -0
  815. package/src/render/plumeGeometry.ts +75 -0
  816. package/src/render/plumeMaterial.ts +99 -0
  817. package/src/render/plumeRenderer.ts +272 -0
  818. package/src/render/pointLightSelection.ts +447 -0
  819. package/src/render/pointShadowArray.ts +276 -0
  820. package/src/render/pointShadowBudget.ts +305 -0
  821. package/src/render/pointShadowImage.ts +470 -0
  822. package/src/render/pointShadowMap.ts +228 -0
  823. package/src/render/pointShadowSystem.ts +408 -0
  824. package/src/render/prefilterEnvMap.ts +162 -0
  825. package/src/render/prefilterPass.ts +115 -0
  826. package/src/render/probeGrid.ts +248 -0
  827. package/src/render/rainField.ts +240 -0
  828. package/src/render/reflectionProbe.ts +530 -0
  829. package/src/render/renderQuality.ts +1054 -0
  830. package/src/render/rendererHarness.ts +214 -0
  831. package/src/render/resolutionGovernor.ts +189 -0
  832. package/src/render/scatterDeform.ts +72 -0
  833. package/src/render/sceneTarget.ts +1032 -0
  834. package/src/render/screenSpaceReflection.ts +524 -0
  835. package/src/render/sdfFont.ts +157 -0
  836. package/src/render/sdfTextLayout.ts +206 -0
  837. package/src/render/sdfTextRenderer.ts +233 -0
  838. package/src/render/seaState.ts +55 -0
  839. package/src/render/segmentQuads.ts +92 -0
  840. package/src/render/shader.ts +190 -0
  841. package/src/render/shaders/ambientOcclusion.ts +354 -0
  842. package/src/render/shaders/arcane.ts +103 -0
  843. package/src/render/shaders/bloom.ts +232 -0
  844. package/src/render/shaders/bolt.ts +164 -0
  845. package/src/render/shaders/caustics.ts +169 -0
  846. package/src/render/shaders/conditionals.ts +58 -0
  847. package/src/render/shaders/decalProject.ts +127 -0
  848. package/src/render/shaders/depth.ts +131 -0
  849. package/src/render/shaders/depthOfField.ts +141 -0
  850. package/src/render/shaders/film.ts +285 -0
  851. package/src/render/shaders/fire.ts +180 -0
  852. package/src/render/shaders/flat/directionalShadow.ts +196 -0
  853. package/src/render/shaders/flat/index.ts +502 -0
  854. package/src/render/shaders/flat/lobes.ts +399 -0
  855. package/src/render/shaders/flat/main.ts +1631 -0
  856. package/src/render/shaders/flat/pointShadow.ts +323 -0
  857. package/src/render/shaders/flat/preamble.ts +875 -0
  858. package/src/render/shaders/flat/probeGrid.ts +152 -0
  859. package/src/render/shaders/flat/surface.ts +41 -0
  860. package/src/render/shaders/flock.ts +103 -0
  861. package/src/render/shaders/fog.ts +99 -0
  862. package/src/render/shaders/fullscreen.ts +28 -0
  863. package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +74 -0
  864. package/src/render/shaders/generated/arcane.wgsl.ts +98 -0
  865. package/src/render/shaders/generated/bloom.wgsl.ts +79 -0
  866. package/src/render/shaders/generated/bolt.wgsl.ts +127 -0
  867. package/src/render/shaders/generated/caustics.wgsl.ts +127 -0
  868. package/src/render/shaders/generated/decalProject.wgsl.ts +69 -0
  869. package/src/render/shaders/generated/depth.wgsl.ts +142 -0
  870. package/src/render/shaders/generated/film.wgsl.ts +143 -0
  871. package/src/render/shaders/generated/fire.wgsl.ts +137 -0
  872. package/src/render/shaders/generated/flat.wgsl.ts +9195 -0
  873. package/src/render/shaders/generated/flock.wgsl.ts +82 -0
  874. package/src/render/shaders/generated/fullscreen.wgsl.ts +20 -0
  875. package/src/render/shaders/generated/globalMedium.wgsl.ts +139 -0
  876. package/src/render/shaders/generated/lightVolume.wgsl.ts +242 -0
  877. package/src/render/shaders/generated/line.wgsl.ts +137 -0
  878. package/src/render/shaders/generated/octahedralResolve.wgsl.ts +60 -0
  879. package/src/render/shaders/generated/oitResolve.wgsl.ts +31 -0
  880. package/src/render/shaders/generated/panel.wgsl.ts +57 -0
  881. package/src/render/shaders/generated/particle.wgsl.ts +343 -0
  882. package/src/render/shaders/generated/prefilter.wgsl.ts +69 -0
  883. package/src/render/shaders/generated/rush.wgsl.ts +139 -0
  884. package/src/render/shaders/generated/scatter.wgsl.ts +205 -0
  885. package/src/render/shaders/generated/sdfText.wgsl.ts +78 -0
  886. package/src/render/shaders/generated/sky.wgsl.ts +109 -0
  887. package/src/render/shaders/generated/smoke.wgsl.ts +93 -0
  888. package/src/render/shaders/generated/ssrResolve.wgsl.ts +26 -0
  889. package/src/render/shaders/generated/ssrTrace.wgsl.ts +94 -0
  890. package/src/render/shaders/generated/temporalResolve.wgsl.ts +54 -0
  891. package/src/render/shaders/generated/text.wgsl.ts +107 -0
  892. package/src/render/shaders/generated/water.wgsl.ts +256 -0
  893. package/src/render/shaders/generated/windStreaks.wgsl.ts +82 -0
  894. package/src/render/shaders/gerstner.ts +110 -0
  895. package/src/render/shaders/globalMedium.ts +396 -0
  896. package/src/render/shaders/lightVolume.ts +546 -0
  897. package/src/render/shaders/line.ts +125 -0
  898. package/src/render/shaders/morph.ts +62 -0
  899. package/src/render/shaders/octahedral.ts +170 -0
  900. package/src/render/shaders/octahedralResolve.ts +83 -0
  901. package/src/render/shaders/oitResolve.ts +42 -0
  902. package/src/render/shaders/outputTransform.ts +107 -0
  903. package/src/render/shaders/panel.ts +51 -0
  904. package/src/render/shaders/particle.ts +438 -0
  905. package/src/render/shaders/prefilter.ts +278 -0
  906. package/src/render/shaders/rush.ts +357 -0
  907. package/src/render/shaders/scatter.ts +211 -0
  908. package/src/render/shaders/sdfText.ts +68 -0
  909. package/src/render/shaders/skinning.ts +59 -0
  910. package/src/render/shaders/sky.ts +243 -0
  911. package/src/render/shaders/smoke.ts +89 -0
  912. package/src/render/shaders/ssrResolve.ts +28 -0
  913. package/src/render/shaders/ssrTrace.ts +233 -0
  914. package/src/render/shaders/tangentFrame.ts +70 -0
  915. package/src/render/shaders/temporalResolve.ts +151 -0
  916. package/src/render/shaders/text.ts +156 -0
  917. package/src/render/shaders/vertexChannel.ts +71 -0
  918. package/src/render/shaders/water.ts +356 -0
  919. package/src/render/shaders/windStreaks.ts +130 -0
  920. package/src/render/shadowCasters.ts +124 -0
  921. package/src/render/shadowMap.ts +89 -0
  922. package/src/render/shotPlacement.ts +266 -0
  923. package/src/render/skinPalette.ts +157 -0
  924. package/src/render/ssrPass.ts +241 -0
  925. package/src/render/surfaceSheet.ts +158 -0
  926. package/src/render/surfaceTexture.ts +310 -0
  927. package/src/render/temporalAa.ts +221 -0
  928. package/src/render/temporalPass.ts +153 -0
  929. package/src/render/textLayout.ts +239 -0
  930. package/src/render/textRenderer.ts +201 -0
  931. package/src/render/thirdPersonCamera.ts +578 -0
  932. package/src/render/trample.ts +140 -0
  933. package/src/render/translucentQueue.ts +161 -0
  934. package/src/render/uniformVectorBudget.ts +246 -0
  935. package/src/render/uploadStep.ts +14 -0
  936. package/src/render/vertexDefaults.ts +115 -0
  937. package/src/render/visibility.ts +56 -0
  938. package/src/render/waterDraw.ts +167 -0
  939. package/src/render/waterGrid.ts +180 -0
  940. package/src/render/waterRenderer.ts +352 -0
  941. package/src/render/wind.ts +79 -0
  942. package/src/render/windField.ts +50 -0
  943. package/src/render/windStreakDraw.ts +131 -0
  944. package/src/render/windStreakRenderer.ts +130 -0
  945. package/src/scene/node.ts +336 -0
  946. package/src/scene/visit.ts +82 -0
  947. package/src/ui/clipMime.ts +109 -0
  948. package/src/ui/exportTarget.ts +491 -0
  949. package/src/ui/frameOverlay.ts +159 -0
  950. package/src/ui/framePacer.ts +351 -0
  951. package/src/ui/frameRecorder.ts +333 -0
  952. package/src/ui/fullscreen.ts +113 -0
  953. package/src/ui/pixelCursor.ts +99 -0
  954. package/src/ui/splash.ts +347 -0
  955. package/src/ui/stillFrame.ts +44 -0
@@ -0,0 +1,1054 @@
1
+ /** Construction-time GPU quality controls shared by every renderer resource. */
2
+
3
+ import { MAX_AREA_LIGHTS } from './areaLights.ts';
4
+ import { MAX_GLOBAL_MEDIUM_STEPS } from './globalMedium.ts';
5
+ import { MAX_POINT_LIGHTS } from './lightBudget.ts';
6
+ import { PREFILTER_SAMPLE_COUNTS } from './prefilterEnvMap.ts';
7
+
8
+ /**
9
+ * What happens to a shaded colour on its way to the framebuffer.
10
+ *
11
+ * `none` writes it unchanged, which is what this renderer has always done and what its
12
+ * worlds are authored against.
13
+ *
14
+ * `srgb` applies the sRGB transfer function. This is not a stylistic choice: shading
15
+ * maths is linear and a display is not, so writing linear values into an 8-bit
16
+ * framebuffer crushes the midtones — a surface at 0.2 linear should read as 0.48 and
17
+ * instead reads as 0.2. It is why an untransformed render looks dark and muddy in
18
+ * exactly the places a lit one should look ordinary.
19
+ *
20
+ * `aces` adds filmic tone mapping before that, rolling highlights off instead of
21
+ * clipping them flat. Together they are what three.js does by default, which is why a
22
+ * world ported from it looks wrong until this exists.
23
+ */
24
+ export type OutputTransform = 'none' | 'srgb' | 'aces';
25
+
26
+ /**
27
+ * The three settings whose accepted values are a closed set, written as one.
28
+ *
29
+ * Each of these already threw at construction with a message naming the allowed values, which is
30
+ * the right refusal at the wrong moment: it survives `tsc` and lands as a blank page. A union moves
31
+ * the same failure to the call site and costs nothing, because these are decisions rather than
32
+ * quantities and a caller computing one is choosing between named tiers either way.
33
+ *
34
+ * Exported so a consumer building a quality profile can name the type of the field it is filling.
35
+ */
36
+ export type ShadowFilterTaps = 4 | 8 | 12;
37
+ export type DirectionalShadowDepthLayers = 1 | 2;
38
+ export type WaterReflectionFilterTaps = 1 | 5 | 9;
39
+
40
+ export interface RenderQuality {
41
+ /**
42
+ * The transfer curve applied at the end of every shaded pass.
43
+ *
44
+ * Construction-time, like every other quality control here, and `none` by default so
45
+ * no existing world changes by a single bit.
46
+ *
47
+ * **The symptom, written down because nobody searches for a transfer curve they do not know
48
+ * exists.** With `none`, values above 1 clip flat rather than rolling off, so a scene with
49
+ * bright sources against dark surroundings reads as crushed and desaturated: the highlights
50
+ * go to a hard white with no colour left in them and the midtones look muddy. That is
51
+ * reported by eye as "dark", "flat" or "not vivid", which sounds like a lighting problem, so
52
+ * that is where people look. A consumer built, tuned and shipped six worlds before anybody
53
+ * said the word. If a scene looks like that, try `outputTransform: 'aces'` with an
54
+ * `outputExposure` before touching a single light.
55
+ *
56
+ * The default stays `none`, and that is not the fault: a curve that changed every existing
57
+ * consumer's output would be far worse than one nobody found.
58
+ */
59
+ readonly outputTransform: OutputTransform;
60
+ /**
61
+ * How far the scene is scaled into the tone curve before it is applied. 1 is neutral.
62
+ *
63
+ * A tone curve is only meaningful relative to an exposure, and the reference ACES
64
+ * transform is graded for a dark cinema. Renderers that ship it therefore scale their
65
+ * input to suit the room the image will actually be seen in, and the factor each one
66
+ * chooses is a look rather than a standard — three.js uses 1/0.6 and says so. This
67
+ * engine holds no opinion and takes the number from whoever is authoring the world, so
68
+ * that matching another renderer, or simply preferring a different grade, is a setting
69
+ * rather than a patch. Ignored when `outputTransform` is not `aces`.
70
+ */
71
+ readonly outputExposure: number;
72
+ /**
73
+ * How a point light fades with distance.
74
+ *
75
+ * `smooth` shapes the curve to the light's own radius — zero exactly at the edge, gentle
76
+ * near the source — which is what makes a light cullable without a seam and is what
77
+ * every world built on this engine is authored against. `inverseSquare` is the physical
78
+ * law, windowed by the radius so it still ends where it says it does; it is far brighter
79
+ * close in, which matters when a source sits centimetres from a surface. Neither is more
80
+ * correct than the other for a stylised world, so this engine ships both and holds no
81
+ * opinion about which a game should want.
82
+ */
83
+ readonly pointLightFalloff: 'smooth' | 'inverseSquare';
84
+ /** Drawing-buffer pixel density cap. */
85
+ readonly maxDevicePixelRatio: number;
86
+ /**
87
+ * Drawing-buffer *area* cap, in pixels. Zero is uncapped.
88
+ *
89
+ * The companion to `maxDevicePixelRatio` and not a duplicate of it: density answers
90
+ * "is this panel high-DPI", area answers "how much frame is this". With only the
91
+ * density cap, the cost of a frame is whatever area the window happens to be, which
92
+ * makes the size of somebody's window an uncontrolled multiplier on a renderer that is
93
+ * roughly 90% fragment-bound. See `drawingBuffer.ts` for why vsync turns that into a
94
+ * halved frame rate rather than a slightly slower one.
95
+ */
96
+ readonly maxDrawingBufferPixels: number;
97
+ readonly directionalShadows: boolean;
98
+ readonly pointShadows: boolean;
99
+ /**
100
+ * The most point lights the lit shader will be built to shade at once. A ceiling, not a promise.
101
+ *
102
+ * **What it is for is fitting a device, not tuning a picture.** Ten of the lit shader's uniform
103
+ * arrays are sized by this with point shadows off and twenty with them on, and GLSL ES spends a
104
+ * whole row of the fragment uniform grid per array *element* whatever its base type — so the
105
+ * full budget declares 440 rows where an Adreno 740 offers 256 and WebGL2 guarantees 224. A
106
+ * shader that does not link is not a slower frame, it is no frame at all.
107
+ *
108
+ * **The renderer already lowers this on its own when the part is short**, counting the shader it
109
+ * is about to compile against what the device reports and saying so in the console. So a
110
+ * consumer never has to set it to boot — this is here for the one who wants the arrays smaller
111
+ * than the device would force, to spend the rows on something else or to hold a scene to a
112
+ * budget they have measured.
113
+ *
114
+ * Lowering it costs lights. `Renderer.shadedLights` reports what was actually resolved, and a
115
+ * `PointLightBuffer` should be sized from that: the selection evicts the weakest when the buffer
116
+ * is full, so a buffer wider than the shader leaves an arbitrary subset lit rather than the
117
+ * nearest ones.
118
+ *
119
+ * **WebGL2 only.** The generated WGSL is built and committed at the full budget, and WebGPU has
120
+ * no per-stage uniform-vector ceiling to be short of. A consumer that lowers this and lands on
121
+ * WebGPU gets all sixteen, which is both the better picture and the one that device can afford.
122
+ */
123
+ readonly maxLights: number;
124
+ /** The most rectangular emitters the lit shader will be built to shade at once. See `maxLights`. */
125
+ readonly maxAreaLights: number;
126
+ readonly directionalShadowMapSize: number;
127
+ /** Side length of each of the six point-shadow cubemap faces. */
128
+ readonly pointShadowFaceSize: number;
129
+ /**
130
+ * Shared PCF budget for directional and point-light shadows.
131
+ *
132
+ * A closed set written as one, so a value outside it is a red squiggle rather than a blank
133
+ * page. **Reported from outside**: `shadowFilterTaps: 9` type-checked and then threw at
134
+ * construction, which is the right refusal arriving at the worst moment. The runtime check
135
+ * stays for JavaScript consumers, which have no types to be helped by.
136
+ */
137
+ readonly shadowFilterTaps: ShadowFilterTaps;
138
+ /**
139
+ * How many samples a volume of light takes along each view ray. See `drawLightVolume`.
140
+ *
141
+ * The pass integrates the air rather than drawing sheets through it, so this is the dial
142
+ * between banding and cost, and it is the only quality control the volume has. Thirty-two is
143
+ * clean at the size a shaft usually occupies because the march is dithered per pixel, which
144
+ * turns what would be concentric shells into grain the effect wants anyway. Below about
145
+ * eight that grain becomes the picture; above thirty-two nothing here could see a change.
146
+ *
147
+ * It costs nothing when no volume is drawn, which is most frames in most worlds.
148
+ */
149
+ readonly lightVolumeSamples: number;
150
+ /** Independently composited static sun depths; two preserves common overlaps. */
151
+ readonly directionalShadowDepthLayers: DirectionalShadowDepthLayers;
152
+ /** Horizontal world-space reach over which a directional shadow dissolves. */
153
+ readonly directionalShadowMaxDistance: number;
154
+ /** Maximum horizontal projection per vertical metre before low-angle shadows vanish. */
155
+ readonly directionalShadowMaxSlope: number;
156
+ /**
157
+ * Metres a point light may drift from where its shadow was baked before re-baking.
158
+ *
159
+ * Zero is the old behaviour and it was the wrong default. See
160
+ * `PointShadowMap.matchesSource`: a light that wanders to look alive invalidated
161
+ * its map every frame, and a re-bake is six passes over the static world. Eight
162
+ * sampled lights flickering at once accounted for 174 of the frame's 296 draw
163
+ * calls, and for the game being unplayable exactly where lamps cluster.
164
+ *
165
+ * The default clears a flame's own wander with room to spare, because drift is
166
+ * measured from the baked origin and a wander can be caught at either extreme
167
+ * of its travel. A light that really moves still re-bakes; it just does so once
168
+ * per this much movement instead of once per frame.
169
+ */
170
+ readonly pointShadowRebakeDistance: number;
171
+ /**
172
+ * Cubemap faces of point-shadow bake the renderer may spend in one frame.
173
+ *
174
+ * A face is a full pass over the static casters, so six of them is one light. Baking
175
+ * every stale light in the frame it goes stale is fine in the steady state and ruinous
176
+ * on the frame that stops being true: walking into a courtyard makes eight lights stale at
177
+ * once, and 48 passes measured as two consecutive frames of 89 ms and 99 ms against an
178
+ * 8.3 ms budget. That is the hitch a second after a page load.
179
+ *
180
+ * Two faces is about 6 ms of the same work, and the backlog drains over the next
181
+ * handful of frames while shadows resolve progressively. Raising it trades that
182
+ * smoothness for lamps that light sooner.
183
+ */
184
+ readonly pointShadowFacesPerFrame: number;
185
+ /**
186
+ * Cubemap faces of *live* point-shadow bake the renderer may spend in one frame.
187
+ *
188
+ * The companion to `pointShadowFacesPerFrame` and not a duplicate of it. That one budgets the
189
+ * static maps, which go stale when a lamp drifts; this budgets the live maps, which hold the
190
+ * movers and are stale every frame by definition — a character is somewhere new each frame, and
191
+ * no `matchesSource` tolerance will ever say otherwise.
192
+ *
193
+ * **It defaults to a whole cubemap because that is what the renderer did before this existed,
194
+ * and that default is wrong for a phone.** The live loop had no budget at all: it asked for
195
+ * all six faces per live map per frame, outside the static budget. Measured as
196
+ * `pointShadow.face` six times a frame in the consumer and in three of the engine's own
197
+ * demos, in frames that were otherwise nine to fourteen passes. There are two live maps and
198
+ * the second wakes during an ownership handoff, so running past a row of lamps costs twelve
199
+ * full passes over the dynamic casters every frame.
200
+ *
201
+ * Lowering it spreads a mover's shadow across two or three frames instead of finishing it in
202
+ * one. The shadow then trails a fast character slightly, which is a real cost and a smaller one
203
+ * than the frame it was taking. Six keeps the old behaviour exactly.
204
+ */
205
+ readonly liveShadowFacesPerFrame: number;
206
+ readonly water: boolean;
207
+ /** Cells per side; the vertex count is this value plus one, squared. */
208
+ readonly waterResolution: number;
209
+ /** Full planar scene reflection sampled by water; false keeps the sky fallback. */
210
+ readonly waterReflections: boolean;
211
+ /** Reflection-target dimensions relative to the drawing buffer. */
212
+ readonly waterReflectionScale: number;
213
+ /** Water-material samples used to broaden the otherwise sharp planar image. */
214
+ readonly waterReflectionFilterTaps: WaterReflectionFilterTaps;
215
+ /**
216
+ * Allocate the planar reflection target even where there is no water to sample it.
217
+ *
218
+ * **The reflection was a water feature by accident of its wiring rather than by design.** The
219
+ * target existed only when `water` and `waterReflections` were both on, so a scene whose ground
220
+ * is a mesh slab with wet film over it, which is what a street at night is, could not mirror
221
+ * anything into it however it asked. A consumer attempted exactly that on the strength of
222
+ * `beginPlanarReflection`'s name and had to do without.
223
+ *
224
+ * Off by default, because the target is a second colour buffer sized from the drawing one and
225
+ * a scene that does not sample it should not pay for it. `water && waterReflections` still
226
+ * turns it on by itself, so nothing that had a reflection loses one.
227
+ */
228
+ readonly planarReflections: boolean;
229
+ /**
230
+ * Keep the scene's real brightness through the composite, and grade at the end instead of in
231
+ * the mesh pass.
232
+ *
233
+ * **Off by default and it has to be, because it is not neutral.** With it on, the scene target
234
+ * holds half floats, so a value above 1 survives to the composite instead of being clamped on
235
+ * the way in, and every effect there works on what the scene actually emitted. Measured on the
236
+ * gilded chamber, held: pixels the scene had already driven near white changed **19.4% of the
237
+ * time with a mean delta of 3.21**, while every other band moved by 0.02 to 0.04, which is
238
+ * rounding between eight bits and a half float. That is the change being correct rather than
239
+ * the change being small, and it is still a change to a shipped picture.
240
+ *
241
+ * **What it is for.** Nothing downstream can tell a star at five times white from a sheet of
242
+ * white paper once the buffer has clamped both to 1, so a brightness threshold cannot exist.
243
+ * This is the prerequisite for one. It also moves the tone curve to the resolve, which fixes an
244
+ * inconsistency that predates it: the mesh pass was the only pass that graded, so the sky, the
245
+ * particles, the wet film and the water were composited ungraded beside a world that was.
246
+ *
247
+ * Needs `screenEffects`, since without a composite there is nothing at the end to grade in, and
248
+ * `EXT_color_buffer_float`, which is asked for rather than assumed: without it the target stays
249
+ * eight-bit and this buys only the consistent grading.
250
+ */
251
+ readonly hdrScene: boolean;
252
+ /** Camera-depth water tint and scattering across every visible pass. */
253
+ readonly underwaterAtmosphere: boolean;
254
+ /** Procedural noise octaves evaluated by plume shaders. */
255
+ readonly plumeNoiseOctaves: number;
256
+ /**
257
+ * Whether a GPU family known to struggle may have its pixel terms clamped at construction.
258
+ *
259
+ * True by default, because the overwhelming majority of players never open a settings
260
+ * screen and a phone opening at a desktop profile is how `NFD6QQ` happened.
261
+ *
262
+ * **A caller passes false to mean "this person chose these numbers themselves."** A player
263
+ * who has deliberately asked for the good profile on a part that cannot hold it is entitled
264
+ * to have it, and to the frame rate that comes with it. Guessing over the top of an explicit
265
+ * choice is worse than a slow game, because it is a setting that silently does not apply.
266
+ */
267
+ readonly capabilityClamp: boolean;
268
+ /**
269
+ * Throw away a multisampled attachment once it has been resolved, instead of writing it back.
270
+ *
271
+ * True is correct and is what the engine wants: the resolve happens either way, and no shader
272
+ * can read the four-sample texture because it carries no `TEXTURE_BINDING` usage. It is worth
273
+ * 115 MB a frame at a phone-sized frame with four samples.
274
+ *
275
+ * **It is a switch because it cannot be verified anywhere but on a tile-based GPU.** On an
276
+ * immediate-mode desktop part `discard` costs nothing and changes nothing — the samples have
277
+ * nowhere else to be — so a screenshot gate cannot tell a correct discard from a wrong one. A
278
+ * tiler really drops them. If a device flashes black or shows a stale frame, turn this off
279
+ * first: it is the one change in this area whose blast radius is a whole frame.
280
+ */
281
+ /**
282
+ * Measure GPU time with timestamp queries. **Off by default, and that is the lesson.**
283
+ *
284
+ * A frame timer is a diagnostic, and a diagnostic must never be able to break the thing it
285
+ * observes. This one could: enabling it attaches a `timestampWrites` block to **every render
286
+ * pass in the frame**, so an implementation that disagrees about any part of it invalidates
287
+ * the whole command buffer, and an invalid command buffer draws nothing at all. That is a
288
+ * black canvas caused by a profiler.
289
+ *
290
+ * It shipped on by default and had only ever run against one implementation. Turning it on
291
+ * costs two queries a pass and is worth it while measuring; paying that risk on every
292
+ * consumer's frame for a number nobody is reading is not.
293
+ *
294
+ * Requires the adapter's `timestamp-query` feature. Without it this reports `available: false`
295
+ * and measures nothing, which is the honest answer rather than a silent zero.
296
+ */
297
+ readonly gpuTiming: boolean;
298
+ readonly discardResolvedAttachments: boolean;
299
+ /**
300
+ * Open the frame's render pass on the first draw that wants it, rather than in `beginFrame`.
301
+ *
302
+ * True avoids closing and reloading the frame's attachment around every planar reflection,
303
+ * measured at 155 MB a frame on a scene with one mirror. False restores the eager open.
304
+ *
305
+ * A switch for the same reason as the one above: it moves *when* a pass is opened relative to
306
+ * everything else a consumer does in a frame, and the failure it could cause is a frame that
307
+ * does not present rather than a pixel that is wrong.
308
+ */
309
+ readonly deferFramePass: boolean;
310
+ /**
311
+ * Route the verbs that have been migrated through the frame graph rather than issuing them
312
+ * directly.
313
+ *
314
+ * **On by default as of 2026-08-25.** The graph records a draw instead of executing it and
315
+ * schedules what accumulated at each boundary. `graphVerbFlushes` is zero — no verb flushes to
316
+ * issue its own calls any more — and the seven published scenes are **pixel-identical with it on
317
+ * and with it off**, 0 of 921,600 each at delta 16, measured on an AMD RX 9070 XT with no device
318
+ * errors on either setting.
319
+ *
320
+ * What kept it off was two defects that only recording could expose, both fixed the same day:
321
+ * a draw took the pipeline of whichever pass happened to be open rather than the one it would
322
+ * land in, and a probe bake never replayed its records, so it baked an empty cube and leaked six
323
+ * draws into the next pass to open. `IMPROVEMENTS.md` carries both.
324
+ *
325
+ * It remains a switch on the same reasoning as the two above: it changes *when* work reaches the
326
+ * GPU relative to everything else a consumer does, so a regression wants to be bisectable to this
327
+ * rather than to a release. `?graph=0` turns it off in one reload.
328
+ */
329
+ readonly frameGraph: boolean;
330
+ /**
331
+ * Light the world from a froxel table rather than from a fixed set of uniform-array slots.
332
+ *
333
+ * **Off, and off is what every published scene is gated at.** With it off the clustered lines
334
+ * are not in the compiled shader at all — `resolveConditionals` cuts them — so a consumer that
335
+ * does not ask for this compiles and runs exactly the shader it did before, which is what makes
336
+ * the zero-pixel gate on the published scenes mean something.
337
+ *
338
+ * On, the point-light budget stops being `MAX_POINT_LIGHTS` and becomes `MAX_CLUSTERED_LIGHTS`,
339
+ * and a fragment shades against the lights in its own froxel rather than against every light the
340
+ * CPU chose for the whole scene.
341
+ *
342
+ * **What it gives up.** One texture unit on WebGL2, permanently, for the table. A per-frame
343
+ * binning cost that is on the main thread on WebGL2 and on the GPU on WebGPU — measured in
344
+ * `clusteredLights.ts`, 0.411 ms a frame at sixteen lights and 2.6 ms at 256. And the froxel
345
+ * bounds are the AABB of a truncated pyramid, so a light is occasionally shaded against a
346
+ * fragment it only nearly reaches.
347
+ *
348
+ * **What would make it wrong.** A scene whose lights are few and enormous: binning cost scales
349
+ * with a light's screen area rather than with the light count, so sixteen lights each covering
350
+ * the frame is the shape that pays most and gains least. The fixed path is still there and is
351
+ * still the right answer for it.
352
+ */
353
+ readonly clusteredLights: boolean;
354
+ /**
355
+ * Skip a mesh draw whose bounds are outside the frame.
356
+ *
357
+ * **Off, and it is a behaviour change rather than a switch between two right answers.** A
358
+ * correct cull is invisible: the pixels are identical and the work is not done. A cull with
359
+ * wrong bounds is a missing object, and bounds come from vertex positions the renderer was
360
+ * handed — so a mesh whose geometry is displaced in its vertex shader, as foliage under wind
361
+ * is, occupies more space than its positions describe.
362
+ *
363
+ * A consumer that knows its own world is better placed to cull than this is: `visible` lets it
364
+ * skip the model matrix, the animation update and the material switch as well, none of which
365
+ * the renderer can avoid once it has been called. This flag exists to prove the test is right
366
+ * and to serve a consumer for whom that restructuring is not worth it.
367
+ */
368
+ readonly cullDraws: boolean;
369
+ /**
370
+ * Resolve the scene through an off-screen target so screen-space effects can run.
371
+ *
372
+ * Off is not "no blur" — it is *no post-process stage at all*: the scene draws straight
373
+ * to the canvas as it always did, and the extra colour target and full-viewport pass are
374
+ * never allocated. That is the honest low-end setting, because the cost is one write and
375
+ * one read of every pixel and it does not shrink with a smaller effect.
376
+ */
377
+ readonly screenEffects: boolean;
378
+ /**
379
+ * Multisample the off-screen scene target: 1 is off, 4 is the usual asked-for figure.
380
+ *
381
+ * **This is the missing half of a decision that was only half made.** The renderer asks
382
+ * the canvas for `antialias: !screenEffects`, and that reasoning is sound and measured:
383
+ * with the scene drawn into an off-screen target, the only thing reaching the default
384
+ * framebuffer is one fullscreen triangle, which has no interior edges to multisample.
385
+ * Forcing it off moved `gl.SAMPLES` from 4 to 0 with identical screenshots and saved a
386
+ * multisampled backbuffer and a resolve every frame. What never happened is anything
387
+ * replacing it, so the default configuration — every screen effect on — has had no
388
+ * anti-aliasing at all, and it shows on an imported model as hard-stepped edges along
389
+ * anything seen at a shallow angle.
390
+ *
391
+ * True multisampling rather than a post filter, because it works on geometry edges and
392
+ * does not touch texture detail: FXAA is cheaper and softens a 4K base colour map, which
393
+ * is a real loss on exactly the assets this matters for. It costs memory bandwidth
394
+ * proportional to the sample count and nothing else.
395
+ *
396
+ * **Defaults to 1, so nothing changes for anyone who does not ask.** Clamped to what the
397
+ * driver reports through `MAX_SAMPLES`, since asking for more than a part supports is a
398
+ * framebuffer that never completes.
399
+ */
400
+ readonly sceneSamples: number;
401
+ /**
402
+ * Camera motion blur, 0 to 1. Off by default.
403
+ *
404
+ * Camera rather than per-object, and that is a decision rather than a stage. Per-object
405
+ * blur needs a velocity buffer: every mesh writing its own screen-space motion into a
406
+ * second render target, so a second set of matrices per draw and a wider G-buffer, which
407
+ * is a structural change to a forward renderer that writes one colour target. Camera blur
408
+ * needs only the previous view-projection, which is one matrix, and it covers the case
409
+ * that actually matters — a camera whipping round a turntable or through a world.
410
+ *
411
+ * Runs inside the composite pass, so it costs a depth sample and eight taps on the pixels
412
+ * that are moving and nothing on a still frame. Needs `screenEffects`, since without the
413
+ * off-screen target there is no finished image or depth to sample.
414
+ */
415
+ readonly cameraMotionBlur: number;
416
+ /**
417
+ * Temporal antialiasing: an edge stops crawling as the camera moves. Off by default.
418
+ *
419
+ * **Antialiasing across frames instead of inside one.** The projection is jittered a fraction of
420
+ * a pixel each frame and the result is blended into where the last frame was, so an edge that
421
+ * fell one side of a pixel centre falls the other side next frame. What MSAA buys per frame this
422
+ * buys over eight of them, for one texture and one fullscreen pass instead of a multiplied fill
423
+ * rate — which is the trade a browser target wants, where MSAA on a float target is not free.
424
+ *
425
+ * **Off by default, and that is not timidity.** Jittering the projection moves every pixel of
426
+ * every frame by construction, so turning it on by default would change every capture in the
427
+ * repository and every consumer's reference images with them.
428
+ *
429
+ * The motion is the camera's: reprojection is exact for a static world under a moving camera and
430
+ * wrong for a moving object under a still one, which the neighbourhood clip rejects rather than
431
+ * corrects. A velocity buffer is what fixes that, and the README carries it as its own gap.
432
+ *
433
+ * Needs `screenEffects`, since without the off-screen target there is no finished image to
434
+ * resolve or depth to reproject through.
435
+ */
436
+ readonly temporalAa: boolean;
437
+ /**
438
+ * Order-independent transparency: two panes of glass stop depending on submission order. Off by
439
+ * default.
440
+ *
441
+ * **Sorted alpha blending is order-dependent by construction** — `over` does not commute — so a
442
+ * translucent set is drawn back to front and anything the sort cannot separate wins arbitrarily
443
+ * or flickers: two panes that intersect, a pane containing another, a pane and the smoke inside
444
+ * it. Sorting harder cannot fix an intersection at all.
445
+ *
446
+ * Weighted blending replaces the ordering with a sum and a product, both of which commute. It is
447
+ * **exact for a single layer** and an approximation of the ordering for several, where near
448
+ * layers count for more than far ones — which is what a pane of glass needs and what a
449
+ * stained-glass window of eight overlapping leaves does not.
450
+ *
451
+ * The cost is two extra targets and a **second submission of the translucent geometry**: the
452
+ * accumulation and the revealage are separate blend states, and this renderer draws immediately
453
+ * rather than into a G-buffer. That was chosen over writing both from one pass, which would need
454
+ * a second fragment output and therefore another `flatFrag` permutation — measured at about
455
+ * 247 KB gzipped, paid by every consumer whether or not they enable this.
456
+ *
457
+ * Needs `screenEffects`, since the resolve composites over the finished scene.
458
+ */
459
+ readonly orderIndependent: boolean;
460
+ /**
461
+ * Depth of field: how wide the blur may reach, as a fraction of the frame's height. Off by
462
+ * default.
463
+ *
464
+ * **A ceiling rather than the effect**, the same split `cameraMotionBlur` takes: this says how
465
+ * far a defocused point may spread and therefore what the pass may cost, and
466
+ * `setDepthOfField` says where this frame's lens is focused and how much of the ceiling it
467
+ * takes. A camera focuses on a subject; a quality profile decides how expensive that is
468
+ * allowed to be, and a device that cannot afford eight extra taps caps it in one place.
469
+ *
470
+ * Runs inside the composite pass, so it costs a depth sample and eight taps on the pixels that
471
+ * are out of focus and one comparison on a frame that has not asked for it. Needs
472
+ * `screenEffects`, since without the off-screen target there is no finished image or depth to
473
+ * sample.
474
+ *
475
+ * **0.02 is a strong, visible defocus** — two per cent of the frame's height is about twenty
476
+ * pixels at 1080 — and 1 is the top of the range rather than a value anybody wants.
477
+ */
478
+ readonly depthOfField: number;
479
+ /**
480
+ * Occlusion culling: how many texels wide the occlusion buffer is. **0 is off and is the
481
+ * default.**
482
+ *
483
+ * A width rather than a boolean, because the only dial this has is its resolution and a second
484
+ * option for it would be a second thing to keep in step. 256 is a reasonable frame's worth: at
485
+ * 16:9 that is a buffer of 256 by 144, which rasterises a handful of occluder boxes in well under
486
+ * a millisecond and answers a rectangle test in a few reads.
487
+ *
488
+ * **It culls nothing until a consumer declares an occluder**, which is what `addOccluder` is for.
489
+ * Nothing is inferred from the scene: an occluder is the box you may safely be hidden by, and
490
+ * only the consumer knows which of its objects that is true of. See `OcclusionBuffer`.
491
+ *
492
+ * Costs nothing on the GPU at all — the whole thing is arithmetic on the CPU, which is what lets
493
+ * it be identical on both backends and asserted without one.
494
+ */
495
+ readonly occlusionCulling: number;
496
+ /**
497
+ * Ambient occlusion, 0 to 1. Off by default.
498
+ *
499
+ * Contact shading where geometry meets: a wheel arch against a tyre, a plinth against a
500
+ * floor, the inside of a panel gap. It is most of what makes an imported model sit in a
501
+ * room rather than float in it, and its absence does not read as a missing feature — it
502
+ * reads as the model being pasted over the picture.
503
+ *
504
+ * Depth compared against its neighbours, in the pass that already holds the depth, so it
505
+ * costs no extra target and no second submission of the scene. Needs `screenEffects`,
506
+ * since without the off-screen target there is no depth to sample; on a driver that
507
+ * refuses to resolve multisampled depth it turns itself off rather than sampling a
508
+ * texture holding whatever was there before.
509
+ *
510
+ * **1 is not the intended look.** It is the top of the range, and a value that dark is
511
+ * useful mostly for seeing where the effect is landing while tuning it.
512
+ */
513
+ readonly ambientOcclusion: number;
514
+ /**
515
+ * Compile the night-side emissive term into the surface shader. Off by default.
516
+ *
517
+ * The amount is `Environment.nightEmissive` and is per frame; this decides whether the term
518
+ * exists at all, and it is construction-time because it changes the shader that gets compiled
519
+ * rather than a value uploaded to one.
520
+ *
521
+ * **It is two options rather than one because the term is not free when it is switched off**,
522
+ * and that was measured rather than assumed. It names `emissiveTint` and `vEmissive`, which
523
+ * the ordinary emissive line also names, so its mere presence lets the compiler re-plan the
524
+ * arithmetic they share: held on the gilded chamber with the amount at 0, **109 pixels of
525
+ * 750,080 moved** against the build before the term existed, where a shadow tap sat exactly on
526
+ * its boundary and flipped. Cut out of the source, the same scene is identical.
527
+ *
528
+ * So a consumer that wants city lights on a rotating planet asks for it and accepts that its
529
+ * pictures move by that much, and every consumer that does not is charged nothing and sees
530
+ * nothing. See `shaders/flat.ts` for the elimination that established which half cost what.
531
+ */
532
+ readonly nightEmissive: boolean;
533
+ /**
534
+ * Bloom, 0 to 1. Off by default.
535
+ *
536
+ * How far a bright thing spreads past its own pixels. Without it an emissive surface is
537
+ * exactly as bright as the pixels it covers and not one wider, so anything meant to
538
+ * overwhelm the eye — a lamp, a star, a neon strip, a shaft of daylight — has to be built
539
+ * out of geometry that imitates a halo. A consumer asked for this after building one star
540
+ * from a core sphere, a second sphere at 1.22 times the radius and fifty-four additive
541
+ * particles, which is a hundred lines standing in for one pass.
542
+ *
543
+ * **Composed with `outputTransform` rather than replacing it.** The curve decides how a
544
+ * bright pixel rolls off; this decides how far it spreads. The bloom is added in linear
545
+ * scene units and the curve then rolls off the sum.
546
+ *
547
+ * **It wants `hdrScene`, and it says so at construction if it does not have it.** The
548
+ * threshold below is in scene units, and with an eight-bit target the scene has already been
549
+ * clipped to 0..1 by the time the composite sees it: a star and a sheet of white paper are
550
+ * the same colour there, so a threshold can only mean whiteness. Needs `screenEffects` too,
551
+ * since without the off-screen target there is no finished image to threshold.
552
+ *
553
+ * Deliberately absent, because they were asked against by name: lens dirt, anamorphic
554
+ * streaks and ghosting. One threshold, one radius, one strength.
555
+ */
556
+ readonly bloom: number;
557
+ /**
558
+ * How bright a pixel has to be before it blooms, in scene units.
559
+ *
560
+ * 1.0 means "brighter than white", which is the useful place to start with a tone curve and
561
+ * an exposure: everything a surface reflects sits below it and only sources of light climb
562
+ * past. Lower it to bloom bright paint as well as lamps.
563
+ *
564
+ * **Subtracted rather than cut**, so there is no second knee knob and no visible edge where
565
+ * a gradient crosses the threshold: a pixel just over it contributes almost nothing and one
566
+ * far over contributes nearly all of itself.
567
+ *
568
+ * Only consulted while `bloom` is non-zero. It is not clamped to any range because a scene
569
+ * is free to define its own units, though it must be positive: a threshold of zero blooms
570
+ * the entire frame including the parts of it that are meant to be dark.
571
+ */
572
+ readonly bloomThreshold: number;
573
+ /**
574
+ * How far the occlusion sampling reaches, in metres.
575
+ *
576
+ * A world-space radius rather than a pixel one, because contact shading is a fact about
577
+ * the geometry: a gap of two centimetres should darken by the same amount from across the
578
+ * room as from a metre away, and a radius in pixels does the opposite. It is projected to
579
+ * a screen radius per pixel from the depth there.
580
+ *
581
+ * The scale to match is the size of the gaps that matter. Half a metre suits a room and a
582
+ * vehicle; a landscape wants more, a model of a watch wants very much less.
583
+ */
584
+ readonly ambientOcclusionRadius: number;
585
+ /**
586
+ * How many steps a global-medium march takes per pixel. **0 is off, and is the default.**
587
+ *
588
+ * A ceiling rather than the effect, in the shape `depthOfField` and `bloom` already use: this
589
+ * says what the pass may cost and `setGlobalMedium` says how thick this frame's air is. At 0 no
590
+ * target is allocated, no program is built and no composite runs, so a consumer who never asks
591
+ * for weather pays nothing — which is the property `scripts/medium-check.mjs` asserts by
592
+ * photographing a frame at density 0 against a frame with the ceiling at 0 and demanding they
593
+ * be identical rather than close.
594
+ *
595
+ * **It is the only thing here that costs linearly.** Each step is a shadow lookup and an
596
+ * exponential; the march is otherwise a fixed setup. 24 is a room, 48 is a landscape where the
597
+ * sun is low enough to make the steps visible as banding at fewer, and above about 48 the
598
+ * picture stops changing. Clamped to 64, which is the shader's own loop bound.
599
+ *
600
+ * What the medium *is* — a body of light inside a hull, or the air itself — is the distinction
601
+ * `globalMedium.ts` opens with: `drawLightVolume` is a shaft somebody placed, and this is
602
+ * everything between the camera and the wall.
603
+ */
604
+ readonly globalMediumSteps: number;
605
+ /**
606
+ * Whether the march runs at half the frame each way. On by default, and it should stay on.
607
+ *
608
+ * Half is a quarter of the march, and what pays for it is that a homogeneous medium is smooth
609
+ * everywhere except at a silhouette — which is the one thing the depth-aware upsample is built
610
+ * to handle. Full resolution is here for a capture that has to rule the upsample out as the
611
+ * cause of something, and for a part with pixels to spare.
612
+ */
613
+ readonly globalMediumHalfResolution: boolean;
614
+ /**
615
+ * Cubemap face size for a baked reflection probe. Zero is off, and is the default.
616
+ *
617
+ * A probe is how a reflective surface shows the *room* rather than a sky-and-ground gradient:
618
+ * a car body carrying the light panels above it and the walls around it. It is baked by the
619
+ * caller through `bakeReflectionProbe`, once, so it costs six submissions of the scene at that
620
+ * moment and one cubemap fetch per reflective pixel afterwards. Nothing per frame.
621
+ *
622
+ * **It needs a seventeenth texture unit**, and WebGL2 guarantees sixteen. On a device at the
623
+ * guarantee the probe is declined with a warning and reflective surfaces keep the
624
+ * approximation, rather than point shadows being dropped to make room. See
625
+ * `ENVIRONMENT_TEXTURE_UNIT`.
626
+ */
627
+ readonly reflectionProbeSize: number;
628
+ /**
629
+ * Whether a surface may reflect its surroundings at all. On by default.
630
+ *
631
+ * **The switch beside the size, in the shape `water`/`waterReflections` and
632
+ * `pointShadows`/`pointShadowFaceSize` already use.** `reflectionProbeSize` says how good the
633
+ * reflection is and this says whether there is one, which is what a settings screen needs: a
634
+ * player turning reflections off should not have to know that a cubemap of zero pixels is the
635
+ * spelling for it, and a consumer scaling a quality preset should be able to drop the whole
636
+ * feature in one field rather than remembering which number means absent.
637
+ *
638
+ * **What it costs to leave on**, since that is the question this answers: one cubemap fetch per
639
+ * pixel of every surface that reflects anything, plus six submissions of the scene and a blur
640
+ * chain each time a caller bakes. Nothing per frame beyond the fetch. What it costs to turn off
641
+ * is the room: a metal has no diffuse term, so what it shows *is* its reflection.
642
+ *
643
+ * **Off is a defined picture rather than an absence**, which is the half worth stating. With no
644
+ * probe the mesh shader keeps the sky-and-ground gradient it had before probes existed —
645
+ * `uAmbient` above, `uAmbientGround` below, mixed by the mirror direction — so a reflective
646
+ * surface still reads as reflective and still varies with the view, it just carries an
647
+ * approximation of the sky instead of an image of the room. Nothing renders black and no caller
648
+ * has to branch: `bakeReflectionProbe` answers false and may be issued unconditionally.
649
+ *
650
+ * What would make this wrong: image-based lighting. With a real irradiance term and a
651
+ * prefiltered environment the gradient stops being the honest fallback, because there would be
652
+ * a cheaper *correct* answer to fall back to.
653
+ */
654
+ readonly environmentReflections: boolean;
655
+ /**
656
+ * Samples per texel in the environment prefilter's GGX convolution.
657
+ *
658
+ * **A quality option because a phone and a workstation should not agree on it**, and it is
659
+ * affordable at all only because a bake happens once per scene rather than once per frame. The
660
+ * named tiers live in `prefilterEnvMap.ts`; this is the number one of them resolved to, so a
661
+ * consumer can also state its own.
662
+ *
663
+ * **What it costs:** the convolution is this many cube fetches per texel per level, against the
664
+ * single fetch the box-filtered chain it replaces cost. **What would make a low count wrong** is
665
+ * a small very bright source in an otherwise dark environment, which is the worst case for
666
+ * variance and is where a rough level shows the samples separately rather than as a lobe.
667
+ *
668
+ * Consulted only when a probe exists, so at the default `reflectionProbeSize` of zero this
669
+ * changes nothing at all.
670
+ */
671
+ readonly environmentPrefilterSamples: number;
672
+ /**
673
+ * Whether the lit pass reads the **GGX-prefiltered** cube rather than the capture's box chain.
674
+ *
675
+ * **Off by default, and that default is a correction rather than a preference.** The prefilter
676
+ * shipped in 3.2.0 wired straight into the lit pass, so it changed the picture of every consumer
677
+ * that had a probe — which this file's own rule forbids: every feature's default reproduces
678
+ * today's picture, and a scene that changes because a feature was added is a regression however
679
+ * good it looks. It was reported as metals reading opaque, twice, before anybody connected it to
680
+ * a feature nobody had asked for.
681
+ *
682
+ * **What the two chains are.** A box level is a smaller picture of the room; a prefiltered level
683
+ * is the room convolved with the lobe for the roughness that level stands for. At the same
684
+ * material roughness the prefiltered one is far blurrier — which is the physically correct
685
+ * answer and is why it exists — so a surface authored against the box chain reads as a wash.
686
+ *
687
+ * **On is the better construction and costs a cube of memory plus the bake.** Turn it on when a
688
+ * scene's materials were authored for it, and note that `envLod` changes meaning with it: the
689
+ * texel-footprint floor is right for a box chain and a roughness combined in quadrature is right
690
+ * for a lobe chain, and the shader picks by this flag rather than by a guess.
691
+ */
692
+ readonly environmentPrefilter: boolean;
693
+ }
694
+
695
+ /** Callers override only the levers selected by a future settings profile. */
696
+ export type RenderQualityOptions = Partial<RenderQuality>;
697
+
698
+ export const MAX_SHADOW_FILTER_TAPS = 12;
699
+ export const MAX_WATER_REFLECTION_FILTER_TAPS = 9;
700
+ export const POINT_SHADOW_FADE_START = 0.35;
701
+ export const DIRECTIONAL_SHADOW_FADE_START = 0.65;
702
+
703
+ /**
704
+ * Current fidelity target. Different shadow projections use different texture
705
+ * dimensions for comparable visible detail: a cubemap spends its allocation
706
+ * six times, while the directional map spends all of it on one focused area.
707
+ */
708
+ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
709
+ outputTransform: 'none',
710
+ outputExposure: 1,
711
+ pointLightFalloff: 'smooth',
712
+ /**
713
+ * Render at the display's own density, up to 2×.
714
+ *
715
+ * It was 1.75, which is a number that renders *nothing* at native resolution: every
716
+ * retina panel reports 2, so the drawing buffer was 87% of the pixels the screen has and
717
+ * the browser stretched the difference. It was found by comparing a small figure in a
718
+ * box against the world behind it: both were blurred, and for the same reason.
719
+ *
720
+ * 2 is where the ceiling belongs. It is what the overwhelming majority of high-density
721
+ * displays report, so it is the point at which a game stops being upscaled; past it the
722
+ * cost is quadratic for detail almost nobody can resolve, which is why there is a cap at
723
+ * all. A device that cannot hold its rate at 2 has the Low profile, which is a decision
724
+ * about pixels rather than a blur applied to everyone.
725
+ */
726
+ maxDevicePixelRatio: 2,
727
+ /**
728
+ * 12 megapixels, which is a guard rail rather than a haircut.
729
+ *
730
+ * At a density cap of 2 the drawing buffer is the panel's own pixels, so this does
731
+ * nothing at all up to and including 4K (8.3 MP) — the resolutions almost everybody is
732
+ * on keep every pixel they have. It starts holding at 5K and above, and on the
733
+ * high-density laptop panels whose logical size is large enough to ask for more than a
734
+ * 4K frame, which are exactly the cases where the density cap has stopped meaning
735
+ * anything about cost.
736
+ *
737
+ * A ceiling that never binds on common hardware is the point: the failure it exists to
738
+ * prevent is a frame that quietly grew past a vsync slot, and a cap only prevents that
739
+ * if it is above where people actually are. Consumers wanting the pixels set it to 0.
740
+ */
741
+ maxDrawingBufferPixels: 12_000_000,
742
+ directionalShadows: true,
743
+ pointShadows: true,
744
+ /* The engine's own budgets, which the renderer lowers per device when it has to. */
745
+ maxLights: MAX_POINT_LIGHTS,
746
+ maxAreaLights: MAX_AREA_LIGHTS,
747
+ directionalShadowMapSize: 2048,
748
+ pointShadowFaceSize: 512,
749
+ shadowFilterTaps: MAX_SHADOW_FILTER_TAPS,
750
+ lightVolumeSamples: 32,
751
+ directionalShadowDepthLayers: 2,
752
+ directionalShadowMaxDistance: 6,
753
+ directionalShadowMaxSlope: 3,
754
+ pointShadowRebakeDistance: 0.4,
755
+ pointShadowFacesPerFrame: 2,
756
+ /*
757
+ * Twelve, which is `LIVE_POINT_SHADOW_MAPS` cubemaps of six faces: exactly what the live
758
+ * loop took before it had a budget at all, so no existing consumer's shadows arrive at a
759
+ * different moment.
760
+ *
761
+ * **Six would have been the wrong default and looked like the right one.** The budget is
762
+ * shared across every live map rather than granted to each, so at six the first map takes
763
+ * the whole cubemap and the second — the one that exists only during an ownership handoff —
764
+ * gets nothing and never bakes. That is a mover's shadow vanishing exactly while a character
765
+ * crosses between two lamps, which is the moment the handoff exists to smooth over.
766
+ */
767
+ liveShadowFacesPerFrame: 12,
768
+ water: true,
769
+ screenEffects: true,
770
+ sceneSamples: 1,
771
+ planarReflections: false,
772
+ hdrScene: false,
773
+ cameraMotionBlur: 0,
774
+ temporalAa: false,
775
+ orderIndependent: false,
776
+ depthOfField: 0,
777
+ occlusionCulling: 0,
778
+ ambientOcclusion: 0,
779
+ nightEmissive: false,
780
+ bloom: 0,
781
+ /* Brighter than white, which is where a source of light sits and a reflecting surface does
782
+ not. Only consulted once the strength above is non-zero, and positive for the same reason
783
+ the occlusion radius is: a zero left sitting here would look legal and bloom the whole
784
+ frame the moment somebody turned the effect on. */
785
+ bloomThreshold: 1,
786
+ /* Off: a probe only exists once a caller bakes one, so nothing changes by default. */
787
+ reflectionProbeSize: 0,
788
+ /* On, because the cost of the feature is the probe and this only says whether one is allowed:
789
+ with the size at its own default of zero, leaving this true changes nothing at all. */
790
+ environmentReflections: true,
791
+ /* The medium tier. Powers of two only; see PREFILTER_SAMPLE_COUNTS for why. */
792
+ environmentPrefilterSamples: PREFILTER_SAMPLE_COUNTS.medium,
793
+ /* Off: the shipped look is the box chain. See the field for why the default is this way round. */
794
+ environmentPrefilter: false,
795
+ /* Half a metre, which is the scale of the gaps in a room and around a vehicle. Only
796
+ consulted when the strength above is non-zero, so it changes nothing by default. */
797
+ ambientOcclusionRadius: 0.5,
798
+ /* Off, so the medium costs nothing until a consumer asks for it. See the field. */
799
+ globalMediumSteps: 0,
800
+ /* Half, which is the resolution the upsample was designed against. */
801
+ globalMediumHalfResolution: true,
802
+ waterResolution: 128,
803
+ waterReflections: true,
804
+ /*
805
+ * Full, and deliberately not the half the GPU-budget design proposed as a free win.
806
+ *
807
+ * It is not free. The reflection is a second full submission of the scene, but with the
808
+ * GPU timer finally armed it measures **0.50 ms of an 18.00 ms frame** — the same 3%
809
+ * category the 72% shadow claim collapsed into. Trading a visibly softer reflection on
810
+ * every machine for 3% none of them needed is not a win, and it is worse than that in
811
+ * one place: this is construction-time, so a clip export cannot ask for full scale back,
812
+ * and an export is the one frame somebody keeps.
813
+ *
814
+ * The devices that genuinely cannot afford the target get it halved by the capability
815
+ * clamp in `renderer.ts` instead, where the cost is paid by the parts that need it paid.
816
+ */
817
+ waterReflectionScale: 1,
818
+ waterReflectionFilterTaps: MAX_WATER_REFLECTION_FILTER_TAPS,
819
+ underwaterAtmosphere: true,
820
+ plumeNoiseOctaves: 3,
821
+ capabilityClamp: true,
822
+ /*
823
+ * **Both back ON in 1.1.2, because the black screen they were turned off for was not them.**
824
+ *
825
+ * These are the only two changes in this engine whose correctness an immediate-mode desktop
826
+ * GPU physically cannot express: a discarded attachment costs nothing and changes nothing
827
+ * where the samples have nowhere else to be, and taking the swap chain late is
828
+ * indistinguishable from taking it early until a browser disagrees about when a frame is
829
+ * presented. So when all three consumers came back completely black on an iPhone 16 Pro,
830
+ * these two were the obvious suspects and both were defaulted off.
831
+ *
832
+ * They were not the cause and turning them off never lifted the black screen. It was a
833
+ * uniform array striding by four bytes where WGSL requires sixteen, which WebKit enforces
834
+ * and Dawn does not, so every shader that draws geometry failed to compile on iOS and
835
+ * nowhere else. Fixed in 1.1.1; the iOS black-screen investigation is
836
+ * the investigation, and the retreat here is the clearest thing it cost.
837
+ *
838
+ * **What leaving them off costs, measured on the gilded chamber at a phone viewport with
839
+ * `npm run frame-audit`:** 75.6 MB a frame against 49.7, which is 4.43 GB/s against 2.91 at
840
+ * 60 fps, and thirteen passes against twelve. Nearly all of it is the deferral — off it is
841
+ * 51.2 MB on its own, because opening the frame's pass eagerly forces a load and a store of
842
+ * the attachment for every mirror. The discard adds the last 1.5 MB and takes the frame's
843
+ * unreadable writes to zero. That is the entire mobile bandwidth result of 1.1.0, and it was
844
+ * being paid on exactly the devices it was measured for.
845
+ *
846
+ * **Still unverified on a tiler, and that has not changed.** What changed is that there is no
847
+ * longer an observed failure to attribute to them. `?discard=0` and `?defer=0` turn them off
848
+ * one at a time in all three consumers, so a device that misbehaves still names its own cause
849
+ * in two reloads.
850
+ */
851
+ discardResolvedAttachments: true,
852
+ deferFramePass: true,
853
+ frameGraph: true,
854
+ clusteredLights: false,
855
+ cullDraws: false,
856
+ /*
857
+ * The profiler stays off, and for its own reason rather than that one: it attaches a
858
+ * timestamp block to every render pass in the frame, which is a cost nobody who did not ask
859
+ * for a measurement should pay. `?gputiming=1` arms it.
860
+ */
861
+ gpuTiming: false,
862
+ });
863
+
864
+ /** Resolve and validate once at renderer construction, never in a hot path. */
865
+ export function resolveRenderQuality(options: RenderQualityOptions = {}): Readonly<RenderQuality> {
866
+ const quality: RenderQuality = {
867
+ outputTransform: options.outputTransform ?? DEFAULT_RENDER_QUALITY.outputTransform,
868
+ outputExposure: options.outputExposure ?? DEFAULT_RENDER_QUALITY.outputExposure,
869
+ pointLightFalloff: options.pointLightFalloff ?? DEFAULT_RENDER_QUALITY.pointLightFalloff,
870
+ maxDevicePixelRatio: options.maxDevicePixelRatio ?? DEFAULT_RENDER_QUALITY.maxDevicePixelRatio,
871
+ maxDrawingBufferPixels:
872
+ options.maxDrawingBufferPixels ?? DEFAULT_RENDER_QUALITY.maxDrawingBufferPixels,
873
+ directionalShadows: options.directionalShadows ?? DEFAULT_RENDER_QUALITY.directionalShadows,
874
+ pointShadows: options.pointShadows ?? DEFAULT_RENDER_QUALITY.pointShadows,
875
+ /* Whole slots, at least one, never above what the shader is written for: these two are
876
+ interpolated into the source as array sizes, so a fractional or zero one is a shader that
877
+ does not compile and a larger one is arrays the uploads never fill. */
878
+ maxLights: Math.min(
879
+ MAX_POINT_LIGHTS,
880
+ Math.max(1, Math.round(options.maxLights ?? DEFAULT_RENDER_QUALITY.maxLights)),
881
+ ),
882
+ maxAreaLights: Math.min(
883
+ MAX_AREA_LIGHTS,
884
+ Math.max(1, Math.round(options.maxAreaLights ?? DEFAULT_RENDER_QUALITY.maxAreaLights)),
885
+ ),
886
+ directionalShadowMapSize:
887
+ options.directionalShadowMapSize ?? DEFAULT_RENDER_QUALITY.directionalShadowMapSize,
888
+ pointShadowFaceSize: options.pointShadowFaceSize ?? DEFAULT_RENDER_QUALITY.pointShadowFaceSize,
889
+ shadowFilterTaps: options.shadowFilterTaps ?? DEFAULT_RENDER_QUALITY.shadowFilterTaps,
890
+ lightVolumeSamples: options.lightVolumeSamples ?? DEFAULT_RENDER_QUALITY.lightVolumeSamples,
891
+ directionalShadowDepthLayers:
892
+ options.directionalShadowDepthLayers ?? DEFAULT_RENDER_QUALITY.directionalShadowDepthLayers,
893
+ directionalShadowMaxDistance:
894
+ options.directionalShadowMaxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance,
895
+ directionalShadowMaxSlope:
896
+ options.directionalShadowMaxSlope ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxSlope,
897
+ pointShadowRebakeDistance:
898
+ options.pointShadowRebakeDistance ?? DEFAULT_RENDER_QUALITY.pointShadowRebakeDistance,
899
+ pointShadowFacesPerFrame:
900
+ options.pointShadowFacesPerFrame ?? DEFAULT_RENDER_QUALITY.pointShadowFacesPerFrame,
901
+ liveShadowFacesPerFrame:
902
+ options.liveShadowFacesPerFrame ?? DEFAULT_RENDER_QUALITY.liveShadowFacesPerFrame,
903
+ water: options.water ?? DEFAULT_RENDER_QUALITY.water,
904
+ screenEffects: options.screenEffects ?? DEFAULT_RENDER_QUALITY.screenEffects,
905
+ sceneSamples: Math.max(
906
+ 1,
907
+ Math.round(options.sceneSamples ?? DEFAULT_RENDER_QUALITY.sceneSamples),
908
+ ),
909
+ planarReflections: options.planarReflections ?? DEFAULT_RENDER_QUALITY.planarReflections,
910
+ hdrScene: options.hdrScene ?? DEFAULT_RENDER_QUALITY.hdrScene,
911
+ cameraMotionBlur: Math.min(
912
+ 1,
913
+ Math.max(0, options.cameraMotionBlur ?? DEFAULT_RENDER_QUALITY.cameraMotionBlur),
914
+ ),
915
+ temporalAa: options.temporalAa ?? DEFAULT_RENDER_QUALITY.temporalAa,
916
+ orderIndependent: options.orderIndependent ?? DEFAULT_RENDER_QUALITY.orderIndependent,
917
+ depthOfField: Math.min(
918
+ 1,
919
+ Math.max(0, options.depthOfField ?? DEFAULT_RENDER_QUALITY.depthOfField),
920
+ ),
921
+ occlusionCulling: Math.max(
922
+ 0,
923
+ Math.round(options.occlusionCulling ?? DEFAULT_RENDER_QUALITY.occlusionCulling),
924
+ ),
925
+ ambientOcclusion: Math.min(
926
+ 1,
927
+ Math.max(0, options.ambientOcclusion ?? DEFAULT_RENDER_QUALITY.ambientOcclusion),
928
+ ),
929
+ nightEmissive: options.nightEmissive ?? DEFAULT_RENDER_QUALITY.nightEmissive,
930
+ bloom: Math.min(1, Math.max(0, options.bloom ?? DEFAULT_RENDER_QUALITY.bloom)),
931
+ bloomThreshold: options.bloomThreshold ?? DEFAULT_RENDER_QUALITY.bloomThreshold,
932
+ reflectionProbeSize: Math.max(
933
+ 0,
934
+ Math.round(options.reflectionProbeSize ?? DEFAULT_RENDER_QUALITY.reflectionProbeSize),
935
+ ),
936
+ environmentReflections:
937
+ options.environmentReflections ?? DEFAULT_RENDER_QUALITY.environmentReflections,
938
+ /* At least one sample: zero would divide by an accumulated weight of zero and answer NaN,
939
+ which a half-float target spreads across every rough level rather than reporting. */
940
+ environmentPrefilterSamples: Math.max(
941
+ 1,
942
+ Math.round(
943
+ options.environmentPrefilterSamples ?? DEFAULT_RENDER_QUALITY.environmentPrefilterSamples,
944
+ ),
945
+ ),
946
+ environmentPrefilter:
947
+ options.environmentPrefilter ?? DEFAULT_RENDER_QUALITY.environmentPrefilter,
948
+ ambientOcclusionRadius:
949
+ options.ambientOcclusionRadius ?? DEFAULT_RENDER_QUALITY.ambientOcclusionRadius,
950
+ /* Whole steps, and never past the shader's own loop bound: a uniform above it would make the
951
+ clamp inside the shader disagree with the step length computed from it, which is a march
952
+ that stops short of where it divided its distance. */
953
+ globalMediumSteps: Math.min(
954
+ MAX_GLOBAL_MEDIUM_STEPS,
955
+ Math.max(
956
+ 0,
957
+ Math.round(options.globalMediumSteps ?? DEFAULT_RENDER_QUALITY.globalMediumSteps),
958
+ ),
959
+ ),
960
+ globalMediumHalfResolution:
961
+ options.globalMediumHalfResolution ?? DEFAULT_RENDER_QUALITY.globalMediumHalfResolution,
962
+ waterResolution: options.waterResolution ?? DEFAULT_RENDER_QUALITY.waterResolution,
963
+ waterReflections: options.waterReflections ?? DEFAULT_RENDER_QUALITY.waterReflections,
964
+ waterReflectionScale:
965
+ options.waterReflectionScale ?? DEFAULT_RENDER_QUALITY.waterReflectionScale,
966
+ capabilityClamp: options.capabilityClamp ?? DEFAULT_RENDER_QUALITY.capabilityClamp,
967
+ gpuTiming: options.gpuTiming ?? DEFAULT_RENDER_QUALITY.gpuTiming,
968
+ discardResolvedAttachments:
969
+ options.discardResolvedAttachments ?? DEFAULT_RENDER_QUALITY.discardResolvedAttachments,
970
+ deferFramePass: options.deferFramePass ?? DEFAULT_RENDER_QUALITY.deferFramePass,
971
+ frameGraph: options.frameGraph ?? DEFAULT_RENDER_QUALITY.frameGraph,
972
+ clusteredLights: options.clusteredLights ?? DEFAULT_RENDER_QUALITY.clusteredLights,
973
+ cullDraws: options.cullDraws ?? DEFAULT_RENDER_QUALITY.cullDraws,
974
+ waterReflectionFilterTaps:
975
+ options.waterReflectionFilterTaps ?? DEFAULT_RENDER_QUALITY.waterReflectionFilterTaps,
976
+ underwaterAtmosphere:
977
+ options.underwaterAtmosphere ?? DEFAULT_RENDER_QUALITY.underwaterAtmosphere,
978
+ plumeNoiseOctaves: options.plumeNoiseOctaves ?? DEFAULT_RENDER_QUALITY.plumeNoiseOctaves,
979
+ };
980
+
981
+ positive('maxDevicePixelRatio', quality.maxDevicePixelRatio);
982
+ // Zero is legal and means uncapped, so this is the non-negative check rather than
983
+ // the positive one.
984
+ nonNegative('maxDrawingBufferPixels', quality.maxDrawingBufferPixels);
985
+ positiveInteger('directionalShadowMapSize', quality.directionalShadowMapSize);
986
+ positiveInteger('pointShadowFaceSize', quality.pointShadowFaceSize);
987
+ positiveInteger('shadowFilterTaps', quality.shadowFilterTaps);
988
+ positiveInteger('lightVolumeSamples', quality.lightVolumeSamples);
989
+ positiveInteger('directionalShadowDepthLayers', quality.directionalShadowDepthLayers);
990
+ positive('directionalShadowMaxDistance', quality.directionalShadowMaxDistance);
991
+ positive('directionalShadowMaxSlope', quality.directionalShadowMaxSlope);
992
+ nonNegative('pointShadowRebakeDistance', quality.pointShadowRebakeDistance);
993
+ positiveInteger('pointShadowFacesPerFrame', quality.pointShadowFacesPerFrame);
994
+ positiveInteger('liveShadowFacesPerFrame', quality.liveShadowFacesPerFrame);
995
+ positiveInteger('waterResolution', quality.waterResolution);
996
+ positive('waterReflectionScale', quality.waterReflectionScale);
997
+ positiveInteger('waterReflectionFilterTaps', quality.waterReflectionFilterTaps);
998
+ positiveInteger('plumeNoiseOctaves', quality.plumeNoiseOctaves);
999
+ /* A radius of zero would ask every tap to land on the pixel it started from, which is not
1000
+ "no occlusion" — it is a division by nothing in the estimator. Off is the strength. */
1001
+ positive('ambientOcclusionRadius', quality.ambientOcclusionRadius);
1002
+ /* Same shape as the radius above: a threshold of zero is not "bloom everything a little",
1003
+ it is every pixel in the frame contributing its whole self. Off is the strength. */
1004
+ positive('bloomThreshold', quality.bloomThreshold);
1005
+ if (
1006
+ quality.shadowFilterTaps !== 4 &&
1007
+ quality.shadowFilterTaps !== 8 &&
1008
+ quality.shadowFilterTaps !== MAX_SHADOW_FILTER_TAPS
1009
+ ) {
1010
+ throw new Error(
1011
+ `RenderQuality.shadowFilterTaps must be 4, 8 or ${MAX_SHADOW_FILTER_TAPS}, got ${quality.shadowFilterTaps}`,
1012
+ );
1013
+ }
1014
+ if (quality.directionalShadowDepthLayers !== 1 && quality.directionalShadowDepthLayers !== 2) {
1015
+ throw new Error(
1016
+ `RenderQuality.directionalShadowDepthLayers must be 1 or 2, got ${quality.directionalShadowDepthLayers}`,
1017
+ );
1018
+ }
1019
+ if (quality.plumeNoiseOctaves > 3) {
1020
+ throw new Error(
1021
+ `RenderQuality.plumeNoiseOctaves must be <= 3, got ${quality.plumeNoiseOctaves}`,
1022
+ );
1023
+ }
1024
+ if (
1025
+ quality.waterReflectionFilterTaps !== 1 &&
1026
+ quality.waterReflectionFilterTaps !== 5 &&
1027
+ quality.waterReflectionFilterTaps !== MAX_WATER_REFLECTION_FILTER_TAPS
1028
+ ) {
1029
+ throw new Error(
1030
+ `RenderQuality.waterReflectionFilterTaps must be 1, 5 or ${MAX_WATER_REFLECTION_FILTER_TAPS}, got ${quality.waterReflectionFilterTaps}`,
1031
+ );
1032
+ }
1033
+ return Object.freeze(quality);
1034
+ }
1035
+
1036
+ function positive(name: string, value: number): void {
1037
+ if (!Number.isFinite(value) || value <= 0) {
1038
+ throw new Error(`RenderQuality.${name} must be a positive finite number, got ${value}`);
1039
+ }
1040
+ }
1041
+
1042
+ /** Zero is meaningful for a tolerance: it asks for the exact comparison. */
1043
+ function nonNegative(name: string, value: number): void {
1044
+ if (!Number.isFinite(value) || value < 0) {
1045
+ throw new Error(`RenderQuality.${name} must be a non-negative finite number, got ${value}`);
1046
+ }
1047
+ }
1048
+
1049
+ function positiveInteger(name: string, value: number): void {
1050
+ positive(name, value);
1051
+ if (!Number.isInteger(value)) {
1052
+ throw new Error(`RenderQuality.${name} must be an integer, got ${value}`);
1053
+ }
1054
+ }