@forgeax/engine-render 0.1.33 → 0.1.34

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 (518) hide show
  1. package/README.md +1010 -124
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  11. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  12. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  14. package/dist/assembly/factory.d.ts +1 -1
  15. package/dist/assembly/factory.d.ts.map +1 -1
  16. package/dist/assembly/host-contract.d.ts +3 -3
  17. package/dist/assembly/host-contract.d.ts.map +1 -1
  18. package/dist/assembly/material/assembly.d.ts.map +1 -1
  19. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  20. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  21. package/dist/assembly/material-shader-policy.d.ts +16 -2
  22. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  23. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  25. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  27. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  28. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  32. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-inspection.d.ts +11 -0
  35. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  36. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  37. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  38. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  39. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +1 -1
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  42. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  43. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  44. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  45. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  46. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  47. package/dist/authoring.mjs +1 -1
  48. package/dist/barrel-distortion.d.ts +47 -0
  49. package/dist/barrel-distortion.d.ts.map +1 -0
  50. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  51. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  52. package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
  53. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
  54. package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
  55. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  56. package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
  57. package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  58. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  59. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  60. package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
  61. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  62. package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
  63. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  64. package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
  65. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  66. package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
  67. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  68. package/dist/cloud/density.d.ts +55 -0
  69. package/dist/cloud/density.d.ts.map +1 -0
  70. package/dist/cloud/extract.d.ts +25 -0
  71. package/dist/cloud/extract.d.ts.map +1 -0
  72. package/dist/cloud/feature.d.ts +57 -0
  73. package/dist/cloud/feature.d.ts.map +1 -0
  74. package/dist/cloud/frame-context.d.ts +8 -0
  75. package/dist/cloud/frame-context.d.ts.map +1 -0
  76. package/dist/cloud/inspection.d.ts +59 -0
  77. package/dist/cloud/inspection.d.ts.map +1 -0
  78. package/dist/cloud/optics.d.ts +56 -0
  79. package/dist/cloud/optics.d.ts.map +1 -0
  80. package/dist/cloud/parameters.d.ts +73 -0
  81. package/dist/cloud/parameters.d.ts.map +1 -0
  82. package/dist/cloud/resources.d.ts +60 -0
  83. package/dist/cloud/resources.d.ts.map +1 -0
  84. package/dist/cloud/shadow.d.ts +42 -0
  85. package/dist/cloud/shadow.d.ts.map +1 -0
  86. package/dist/cloud/temporal.d.ts +74 -0
  87. package/dist/cloud/temporal.d.ts.map +1 -0
  88. package/dist/components/barrel-distortion.d.ts +13 -0
  89. package/dist/components/barrel-distortion.d.ts.map +1 -0
  90. package/dist/components/cloud-layer.d.ts +29 -0
  91. package/dist/components/cloud-layer.d.ts.map +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/instances.d.ts +20 -6
  95. package/dist/components/instances.d.ts.map +1 -1
  96. package/dist/construct-renderer.d.ts +1 -1
  97. package/dist/construct-renderer.d.ts.map +1 -1
  98. package/dist/construct-renderer.mjs +6759 -2875
  99. package/dist/construct-renderer.mjs.map +1 -1
  100. package/dist/dynamic-geometry.d.ts +5 -1
  101. package/dist/dynamic-geometry.d.ts.map +1 -1
  102. package/dist/errors/cloud.d.ts +59 -0
  103. package/dist/errors/cloud.d.ts.map +1 -0
  104. package/dist/errors/render.d.ts +18 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  107. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  108. package/dist/extract/camera.d.ts.map +1 -1
  109. package/dist/extract/contracts.d.ts +5 -1
  110. package/dist/extract/contracts.d.ts.map +1 -1
  111. package/dist/features/barrel-distortion.d.ts +29 -0
  112. package/dist/features/barrel-distortion.d.ts.map +1 -0
  113. package/dist/features/error-reporting.d.ts +6 -2
  114. package/dist/features/error-reporting.d.ts.map +1 -1
  115. package/dist/features/host.d.ts +10 -0
  116. package/dist/features/host.d.ts.map +1 -1
  117. package/dist/features/plan.d.ts +8 -0
  118. package/dist/features/plan.d.ts.map +1 -1
  119. package/dist/features/render-graph-contribution.d.ts +5 -0
  120. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  121. package/dist/features/render-graph-raster.d.ts +1 -0
  122. package/dist/features/render-graph-raster.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +2 -0
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +44 -0
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  128. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  129. package/dist/gpu-dirty-ranges.d.ts +11 -0
  130. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  131. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  132. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  133. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  134. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  135. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  136. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  137. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  138. package/dist/gpu-driven/production-raster.d.ts +47 -3
  139. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  140. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  141. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  142. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  143. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  144. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  145. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  146. package/dist/gpu-scene.d.ts +5 -0
  147. package/dist/gpu-scene.d.ts.map +1 -1
  148. package/dist/hdrp-buffers.d.ts +2 -2
  149. package/dist/hdrp-buffers.d.ts.map +1 -1
  150. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +27 -7
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +258 -8
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +135 -1
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instance-buffer-cache.d.ts +4 -4
  159. package/dist/instance-buffer-cache.d.ts.map +1 -1
  160. package/dist/instances.d.ts +48 -100
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.mjs +7 -7
  163. package/dist/pbr-pipeline.d.ts +19 -1
  164. package/dist/pbr-pipeline.d.ts.map +1 -1
  165. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  166. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  169. package/dist/pipeline/standard-output/types.d.ts +4 -2
  170. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  171. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  172. package/dist/pipeline/standard-post.d.ts.map +1 -1
  173. package/dist/pipeline-builder.d.ts +1 -1
  174. package/dist/pipeline-builder.d.ts.map +1 -1
  175. package/dist/plugin.d.ts.map +1 -1
  176. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  177. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  178. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  179. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  180. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  181. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  182. package/dist/record/fold-buckets.d.ts +95 -0
  183. package/dist/record/fold-buckets.d.ts.map +1 -0
  184. package/dist/record/fold-instance-buffer.d.ts +6 -0
  185. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  186. package/dist/record/frame-lighting.d.ts +1 -0
  187. package/dist/record/frame-lighting.d.ts.map +1 -1
  188. package/dist/record/frame-snapshot.d.ts +37 -3
  189. package/dist/record/frame-snapshot.d.ts.map +1 -1
  190. package/dist/record/frame.d.ts +10 -61
  191. package/dist/record/frame.d.ts.map +1 -1
  192. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  193. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  194. package/dist/record/gpu-timing.d.ts +8 -0
  195. package/dist/record/gpu-timing.d.ts.map +1 -1
  196. package/dist/record/main-pass-geometry.d.ts +21 -5
  197. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  198. package/dist/record/main-pass-material.d.ts +7 -1
  199. package/dist/record/main-pass-material.d.ts.map +1 -1
  200. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  201. package/dist/record/main-pass.d.ts +13 -2
  202. package/dist/record/main-pass.d.ts.map +1 -1
  203. package/dist/record/motion-blur-receipt.d.ts +11 -0
  204. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  205. package/dist/record/probe-blend-buffer.d.ts +16 -0
  206. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  207. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  208. package/dist/record/render-context.d.ts +22 -3
  209. package/dist/record/render-context.d.ts.map +1 -1
  210. package/dist/record/shadow-pass.d.ts +2 -0
  211. package/dist/record/shadow-pass.d.ts.map +1 -1
  212. package/dist/record/skybox-post-pass.d.ts +1 -1
  213. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  214. package/dist/record/typed-frame-graph.d.ts +22 -2
  215. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  216. package/dist/record/view-ubo.d.ts +11 -3
  217. package/dist/record/view-ubo.d.ts.map +1 -1
  218. package/dist/record/volume-params.d.ts +9 -0
  219. package/dist/record/volume-params.d.ts.map +1 -0
  220. package/dist/recovery/render-system-candidate.d.ts +10 -0
  221. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  222. package/dist/reflection/record-owner.d.ts.map +1 -1
  223. package/dist/render-contract.d.ts +42 -4
  224. package/dist/render-contract.d.ts.map +1 -1
  225. package/dist/render-graph-primitives.d.ts.map +1 -1
  226. package/dist/render-pipeline.d.ts +103 -2
  227. package/dist/render-pipeline.d.ts.map +1 -1
  228. package/dist/render-system-extract-tail.d.ts +3 -2
  229. package/dist/render-system-extract-tail.d.ts.map +1 -1
  230. package/dist/render-system-extract.d.ts +16 -9
  231. package/dist/render-system-extract.d.ts.map +1 -1
  232. package/dist/render-system-presentation.d.ts +23 -0
  233. package/dist/render-system-presentation.d.ts.map +1 -0
  234. package/dist/render-system-producer-roots.d.ts +10 -0
  235. package/dist/render-system-producer-roots.d.ts.map +1 -0
  236. package/dist/render-system-residency.d.ts +12 -0
  237. package/dist/render-system-residency.d.ts.map +1 -0
  238. package/dist/render-system.d.ts +19 -14
  239. package/dist/render-system.d.ts.map +1 -1
  240. package/dist/scene/probe-blend.d.ts +27 -0
  241. package/dist/scene/probe-blend.d.ts.map +1 -1
  242. package/dist/scene/render-scene.d.ts +12 -5
  243. package/dist/scene/render-scene.d.ts.map +1 -1
  244. package/dist/ssao-buffers.d.ts +9 -0
  245. package/dist/ssao-buffers.d.ts.map +1 -1
  246. package/dist/surface/dynamic-input.d.ts +133 -0
  247. package/dist/surface/dynamic-input.d.ts.map +1 -0
  248. package/dist/surface/gpu-driven.d.ts +41 -0
  249. package/dist/surface/gpu-driven.d.ts.map +1 -0
  250. package/dist/surface/submission-observation.d.ts +136 -0
  251. package/dist/surface/submission-observation.d.ts.map +1 -0
  252. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  253. package/dist/temporal/gpu.d.ts +13 -1
  254. package/dist/temporal/gpu.d.ts.map +1 -1
  255. package/dist/temporal/index.mjs +5 -5
  256. package/dist/temporal/inspection.d.ts.map +1 -1
  257. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  258. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  259. package/dist/transmission/single-layer-medium.d.ts +89 -0
  260. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  261. package/dist/typed-render-graph-primitives.d.ts +14 -2
  262. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  263. package/dist/volume/component.d.ts +9 -4
  264. package/dist/volume/component.d.ts.map +1 -1
  265. package/dist/volume/extract.d.ts +1 -1
  266. package/dist/volume/extract.d.ts.map +1 -1
  267. package/dist/volume/inspection.d.ts +2 -0
  268. package/dist/volume/inspection.d.ts.map +1 -1
  269. package/dist/volume/passes.d.ts +4 -1
  270. package/dist/volume/passes.d.ts.map +1 -1
  271. package/dist/volume/resources.d.ts.map +1 -1
  272. package/package.json +22 -21
  273. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  274. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  275. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  276. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  277. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  278. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  279. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  280. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  281. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  282. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  283. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  284. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  285. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  286. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  287. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  288. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  289. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  290. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  291. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  292. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  293. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  294. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  295. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  296. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  297. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  298. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  299. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  300. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  301. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  302. package/src/__tests__/instances-store.unit.test.ts +97 -305
  303. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  304. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  305. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  306. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  307. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  308. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  309. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  310. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  311. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  312. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  313. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  314. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  315. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  316. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  317. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  318. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  319. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  320. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  321. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  322. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  323. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  324. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  325. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  326. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  327. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  328. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  329. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  330. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  331. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  332. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  333. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  334. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  335. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  336. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  337. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  338. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  339. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  340. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  341. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  342. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  343. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  344. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  345. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  346. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  347. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  348. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  349. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  350. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  351. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  352. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  353. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  354. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  355. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  356. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  357. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  358. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  359. package/src/assembly/backend-contract.ts +30 -0
  360. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  361. package/src/assembly/canvas-draw-guard.ts +11 -0
  362. package/src/assembly/cloud-shadow-entry.ts +22 -0
  363. package/src/assembly/dynamic-geometry-host.ts +65 -37
  364. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  365. package/src/assembly/factory.ts +2 -30
  366. package/src/assembly/host-contract.ts +3 -3
  367. package/src/assembly/material/assembly.ts +25 -13
  368. package/src/assembly/material/pipeline-helpers.ts +53 -12
  369. package/src/assembly/material-shader-policy.ts +55 -0
  370. package/src/assembly/material-shader-prewarm.ts +21 -10
  371. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  372. package/src/assembly/recovery/renderer-recover.ts +41 -18
  373. package/src/assembly/render-feature-post-processes.ts +54 -0
  374. package/src/assembly/renderer-facade.ts +4 -1
  375. package/src/assembly/renderer-feature-inspection.ts +8 -2
  376. package/src/assembly/renderer-frame-transaction.ts +23 -0
  377. package/src/assembly/renderer-inspection.ts +28 -0
  378. package/src/assembly/skin-palette-owner.ts +1 -1
  379. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  380. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  381. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  382. package/src/assembly/webgpu-ready.ts +115 -61
  383. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  384. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  385. package/src/assembly/webgpu-renderer.ts +214 -252
  386. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  387. package/src/barrel-distortion.ts +247 -0
  388. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  389. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  390. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  391. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  392. package/src/cloud/density.ts +600 -0
  393. package/src/cloud/extract.ts +110 -0
  394. package/src/cloud/feature.ts +1810 -0
  395. package/src/cloud/frame-context.ts +42 -0
  396. package/src/cloud/inspection.ts +130 -0
  397. package/src/cloud/optics.ts +285 -0
  398. package/src/cloud/parameters.ts +255 -0
  399. package/src/cloud/resources.ts +122 -0
  400. package/src/cloud/shadow.ts +167 -0
  401. package/src/cloud/temporal.ts +226 -0
  402. package/src/components/barrel-distortion.ts +46 -0
  403. package/src/components/cloud-layer.ts +47 -0
  404. package/src/components/index.ts +2 -0
  405. package/src/components/instances.ts +18 -45
  406. package/src/components/sprite-instances.ts +1 -1
  407. package/src/construct-renderer.ts +1 -1
  408. package/src/dynamic-geometry.ts +12 -1
  409. package/src/errors/cloud.ts +103 -0
  410. package/src/errors/render.ts +44 -7
  411. package/src/examples/single-layer-medium-surface.ts +59 -0
  412. package/src/extract/camera.ts +15 -1
  413. package/src/extract/contracts.ts +5 -0
  414. package/src/features/barrel-distortion.ts +172 -0
  415. package/src/features/error-reporting.ts +26 -6
  416. package/src/features/host.ts +115 -14
  417. package/src/features/plan.ts +8 -0
  418. package/src/features/render-graph-contribution.ts +9 -0
  419. package/src/features/render-graph-raster.ts +45 -3
  420. package/src/features/targets.ts +66 -0
  421. package/src/features/types.ts +47 -0
  422. package/src/fullscreen-post-process-pass.ts +41 -9
  423. package/src/gpu-dirty-ranges.ts +48 -0
  424. package/src/gpu-driven/batch-topology.ts +53 -0
  425. package/src/gpu-driven/material-artifacts.ts +33 -25
  426. package/src/gpu-driven/prepared-draw.ts +12 -4
  427. package/src/gpu-driven/production-raster-material.ts +1894 -0
  428. package/src/gpu-driven/production-raster.ts +825 -784
  429. package/src/gpu-driven/resource-allocation.ts +142 -0
  430. package/src/gpu-driven/shadow-ownership.ts +71 -0
  431. package/src/gpu-driven/view-gpu.ts +164 -10
  432. package/src/gpu-scene.ts +75 -84
  433. package/src/hdrp-buffers.ts +4 -3
  434. package/src/ibl/skylight-bind-group.ts +49 -7
  435. package/src/index.ts +196 -9
  436. package/src/inspection-types.ts +162 -0
  437. package/src/instance-buffer-cache.ts +4 -4
  438. package/src/instances.ts +149 -569
  439. package/src/pbr-pipeline.ts +219 -13
  440. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  441. package/src/pipeline/standard-forward-lane.ts +313 -57
  442. package/src/pipeline/standard-output/graph.ts +8 -2
  443. package/src/pipeline/standard-output/types.ts +12 -1
  444. package/src/pipeline/standard-pipeline.ts +291 -18
  445. package/src/pipeline/standard-post.ts +90 -24
  446. package/src/pipeline-builder.ts +1 -1
  447. package/src/plugin.ts +4 -0
  448. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  449. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  450. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  451. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  452. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  453. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  454. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  455. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  456. package/src/record/barrel-distortion-frame.ts +110 -0
  457. package/src/record/dynamic-geometry-consumption.ts +39 -9
  458. package/src/record/fold-buckets.ts +852 -0
  459. package/src/record/fold-instance-buffer.ts +51 -0
  460. package/src/record/frame-lighting.ts +36 -2
  461. package/src/record/frame-snapshot.ts +39 -3
  462. package/src/record/frame.ts +217 -1084
  463. package/src/record/gpu-draw-receipts.ts +38 -0
  464. package/src/record/gpu-timing.ts +48 -5
  465. package/src/record/main-pass-geometry.ts +251 -82
  466. package/src/record/main-pass-material.ts +66 -4
  467. package/src/record/main-pass-sprite-draws.ts +7 -65
  468. package/src/record/main-pass.ts +156 -20
  469. package/src/record/motion-blur-receipt.ts +91 -0
  470. package/src/record/probe-blend-buffer.ts +180 -0
  471. package/src/record/recovery-pipeline.ts +35 -3
  472. package/src/record/render-context.ts +39 -3
  473. package/src/record/shadow-pass.ts +30 -1
  474. package/src/record/skybox-post-pass.ts +28 -4
  475. package/src/record/typed-frame-graph.ts +770 -134
  476. package/src/record/view-ubo.ts +26 -3
  477. package/src/record/volume-params.ts +225 -0
  478. package/src/recovery/render-system-candidate.ts +235 -42
  479. package/src/reflection/record-owner.ts +7 -3
  480. package/src/render-contract.ts +48 -4
  481. package/src/render-graph-primitives.ts +7 -1
  482. package/src/render-pipeline.ts +130 -0
  483. package/src/render-system-extract-tail.ts +57 -61
  484. package/src/render-system-extract.ts +74 -76
  485. package/src/render-system-presentation.ts +56 -0
  486. package/src/render-system-producer-roots.ts +96 -0
  487. package/src/render-system-residency.ts +159 -0
  488. package/src/render-system.ts +347 -363
  489. package/src/scene/probe-blend.ts +96 -4
  490. package/src/scene/render-scene.ts +349 -280
  491. package/src/ssao-buffers.ts +95 -2
  492. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  493. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  494. package/src/surface/dynamic-input.ts +658 -0
  495. package/src/surface/gpu-driven.ts +147 -0
  496. package/src/surface/submission-observation.ts +517 -0
  497. package/src/systems/skin-palette-allocator.ts +4 -1
  498. package/src/temporal/gpu.ts +101 -17
  499. package/src/temporal/inspection.ts +7 -1
  500. package/src/temporal/standard-scene-data.ts +5 -0
  501. package/src/temporal/target-coverage-attachment.ts +4 -0
  502. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  503. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  504. package/src/transmission/single-layer-medium.ts +322 -0
  505. package/src/typed-render-graph-primitives.ts +70 -2
  506. package/src/volume/component.ts +10 -9
  507. package/src/volume/extract.ts +11 -5
  508. package/src/volume/inspection.ts +3 -0
  509. package/src/volume/passes.ts +87 -4
  510. package/src/volume/resources.ts +2 -1
  511. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  512. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  513. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  514. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  515. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  516. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  517. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  518. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -23,6 +23,13 @@ export const TEMPORAL_HISTORY_FORMATS = Object.freeze({
23
23
  stability: 'r8unorm',
24
24
  } as const);
25
25
 
26
+ /** Cloud transport history shares the renderer temporal owner and ping-pong fence. */
27
+ export const CLOUD_HISTORY_FORMATS = Object.freeze({
28
+ radiance: 'rgba16float',
29
+ transmittance: 'rgba16float',
30
+ depth: 'rgba16float',
31
+ } as const);
32
+
26
33
  interface TemporalSurface {
27
34
  readonly texture: Texture;
28
35
  readonly view: TextureView;
@@ -40,6 +47,12 @@ export interface TemporalGpuState {
40
47
  readonly color: [TemporalSurface, TemporalSurface];
41
48
  readonly temporal: [TemporalSurface, TemporalSurface];
42
49
  readonly stability: [TemporalSurface, TemporalSurface];
50
+ /** Whether this candidate owns the optional cloud transport history MRT. */
51
+ readonly cloudHistoryEnabled: boolean;
52
+ /** Previous/current cloud radiance, transmittance and representative depth. */
53
+ readonly cloudRadiance: [TemporalSurface, TemporalSurface] | undefined;
54
+ readonly cloudTransmittance: [TemporalSurface, TemporalSurface] | undefined;
55
+ readonly cloudDepth: [TemporalSurface, TemporalSurface] | undefined;
43
56
  bindGroupLayout: BindGroupLayout | undefined;
44
57
  sampler: Sampler | undefined;
45
58
  temporalSampler: Sampler | undefined;
@@ -81,13 +94,22 @@ function createSurface(
81
94
  return { texture: texture.value, view: view.value };
82
95
  }
83
96
 
97
+ function cloudHistoryExtent(width: number, height: number): { width: number; height: number } {
98
+ return {
99
+ width: Math.max(1, Math.ceil(width / 2)),
100
+ height: Math.max(1, Math.ceil(height / 2)),
101
+ };
102
+ }
103
+
84
104
  function createState(
85
105
  device: RhiDevice,
86
106
  scope: DeviceScope,
87
107
  width: number,
88
108
  height: number,
109
+ cloudHistoryEnabled: boolean,
89
110
  ): TemporalGpuState {
90
111
  const childScope = scope.createChild(`${scope.owner}:temporal`);
112
+ const cloudExtent = cloudHistoryExtent(width, height);
91
113
  try {
92
114
  return {
93
115
  device,
@@ -138,6 +160,65 @@ function createState(
138
160
  TEMPORAL_HISTORY_FORMATS.stability,
139
161
  ),
140
162
  ],
163
+ cloudHistoryEnabled,
164
+ cloudRadiance: cloudHistoryEnabled
165
+ ? [
166
+ createSurface(
167
+ device,
168
+ childScope,
169
+ 'cloud-history-radiance-a',
170
+ cloudExtent.width,
171
+ cloudExtent.height,
172
+ ),
173
+ createSurface(
174
+ device,
175
+ childScope,
176
+ 'cloud-history-radiance-b',
177
+ cloudExtent.width,
178
+ cloudExtent.height,
179
+ ),
180
+ ]
181
+ : undefined,
182
+ cloudTransmittance: cloudHistoryEnabled
183
+ ? [
184
+ createSurface(
185
+ device,
186
+ childScope,
187
+ 'cloud-history-transmittance-a',
188
+ cloudExtent.width,
189
+ cloudExtent.height,
190
+ CLOUD_HISTORY_FORMATS.transmittance,
191
+ ),
192
+ createSurface(
193
+ device,
194
+ childScope,
195
+ 'cloud-history-transmittance-b',
196
+ cloudExtent.width,
197
+ cloudExtent.height,
198
+ CLOUD_HISTORY_FORMATS.transmittance,
199
+ ),
200
+ ]
201
+ : undefined,
202
+ cloudDepth: cloudHistoryEnabled
203
+ ? [
204
+ createSurface(
205
+ device,
206
+ childScope,
207
+ 'cloud-history-depth-a',
208
+ cloudExtent.width,
209
+ cloudExtent.height,
210
+ CLOUD_HISTORY_FORMATS.depth,
211
+ ),
212
+ createSurface(
213
+ device,
214
+ childScope,
215
+ 'cloud-history-depth-b',
216
+ cloudExtent.width,
217
+ cloudExtent.height,
218
+ CLOUD_HISTORY_FORMATS.depth,
219
+ ),
220
+ ]
221
+ : undefined,
141
222
  bindGroupLayout: undefined,
142
223
  sampler: undefined,
143
224
  temporalSampler: undefined,
@@ -180,26 +261,29 @@ export function getTemporalGpuState(
180
261
  scope: DeviceScope,
181
262
  width: number,
182
263
  height: number,
264
+ cloudHistoryRequested = false,
183
265
  ): TemporalGpuState {
266
+ // Graph preparation publishes this demand before any imported target is
267
+ // resolved. That makes the first TAA and cloud pass share one candidate,
268
+ // while a plain TAA frame allocates only its six TAA surfaces.
269
+ const wantsCloudHistory =
270
+ cloudHistoryRequested ||
271
+ frameState.pendingCloudHistoryActive === true ||
272
+ frameState.cloudHistoryActive === true;
273
+ const matches = (state: TemporalGpuState | undefined): state is TemporalGpuState =>
274
+ state !== undefined &&
275
+ state.scope === scope &&
276
+ state.width === width &&
277
+ state.height === height &&
278
+ // Cloud history is a demand-shaped part of the temporal allocation. Keep
279
+ // the two shapes distinct so turning CloudLayer off retires its six HDR
280
+ // surfaces instead of retaining them on an otherwise TAA-only frame.
281
+ state.cloudHistoryEnabled === wantsCloudHistory;
184
282
  const staged = frameState.temporalGpuState;
185
- if (
186
- staged !== undefined &&
187
- staged.scope === scope &&
188
- staged.width === width &&
189
- staged.height === height
190
- ) {
191
- return staged;
192
- }
283
+ if (matches(staged)) return staged;
193
284
  const existing = frameState.activeTemporalGpuState;
194
- if (
195
- existing !== undefined &&
196
- existing.scope === scope &&
197
- existing.width === width &&
198
- existing.height === height
199
- ) {
200
- return existing;
201
- }
202
- const next = createState(device, scope, width, height);
285
+ if (matches(existing)) return existing;
286
+ const next = createState(device, scope, width, height, wantsCloudHistory);
203
287
  frameState.temporalGpuState = next;
204
288
  return next;
205
289
  }
@@ -29,7 +29,13 @@ export interface TemporalInspection {
29
29
  }
30
30
 
31
31
  function gpuBytes(state: TemporalGpuState | undefined): number {
32
- return state === undefined ? 0 : createTemporalCoverage(state.width, state.height).bytes;
32
+ if (state === undefined) return 0;
33
+ const taaBytes = createTemporalCoverage(state.width, state.height).bytes;
34
+ // The cloud owner adds six rgba16float surfaces (8 bytes per pixel) only
35
+ // when the candidate was admitted with cloud history demand. This is derived
36
+ // from the live state shape rather than reported as a fixed cloud estimate.
37
+ const cloudBytes = state.cloudHistoryEnabled ? state.width * state.height * 6 * 8 : 0;
38
+ return taaBytes + cloudBytes;
33
39
  }
34
40
 
35
41
  function gpuResources(state: TemporalGpuState | undefined): number {
@@ -156,6 +156,11 @@ export function addStandardSceneDataPass(
156
156
  color: target,
157
157
  depth,
158
158
  selector: { LightMode: ['Deferred', 'Forward'] },
159
+ // The temporal producer runs before the Surface raw-depth/nearest-layer
160
+ // pair. Keep it on the ordinary opaque Standard lane rather than asking
161
+ // a medium material to assemble a bind group from resources that this
162
+ // pass cannot own yet.
163
+ recordMode: 'opaque',
159
164
  passKind: 'temporal',
160
165
  // The temporal producer re-rasterizes the current scene after the main
161
166
  // color pass has populated depth. Its output is a semantic motion target;
@@ -64,6 +64,10 @@ export function addTargetCoveragePass(
64
64
  colorTargets: [target.coverage],
65
65
  depth: target.depth,
66
66
  selector: { LightMode: ['Deferred', 'Forward'] },
67
+ // Coverage is a generic Standard raster producer. Surface medium pixels
68
+ // are owned by the later paired nearest/color passes and have no raw-depth
69
+ // input at this point, so keep this attachment on the opaque lane.
70
+ recordMode: 'opaque',
67
71
  passKind: 'temporal',
68
72
  clearColor: [0, 0, 0, 0],
69
73
  depthLoadOp: 'clear',
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ composeSingleLayerMediumColor,
4
+ integrateSingleLayerMedium,
5
+ isBelowSingleLayerMediumPlane,
6
+ resolveSingleLayerMediumBackground,
7
+ } from '../single-layer-medium.js';
8
+
9
+ const coefficients = {
10
+ absorption: [0.2, 0.4, 0.8] as const,
11
+ scattering: [0.1, 0.1, 0.1] as const,
12
+ ior: 1.333,
13
+ phaseG: 0.4,
14
+ };
15
+
16
+ describe('single-layer medium optics', () => {
17
+ it('uses Beer-Lambert transmission and the zero-extinction limit', () => {
18
+ const short = integrateSingleLayerMedium({ coefficients, distanceMeters: 1, cosTheta: 1 });
19
+ const long = integrateSingleLayerMedium({ coefficients, distanceMeters: 2, cosTheta: 1 });
20
+ expect(long.transmittance[0]).toBeLessThan(short.transmittance[0]);
21
+ expect(long.transmittance[1]).toBeLessThan(short.transmittance[1]);
22
+ expect(short.singleScatter[0]).toBeGreaterThan(0);
23
+ const empty = integrateSingleLayerMedium({
24
+ coefficients: { absorption: [0, 0, 0], scattering: [0, 0, 0], ior: 1.333 },
25
+ distanceMeters: 4,
26
+ cosTheta: 1,
27
+ });
28
+ expect(empty.transmittance).toEqual([1, 1, 1]);
29
+ expect(empty.singleScatter).toEqual([0, 0, 0]);
30
+ expect(empty.reflectance).toBeGreaterThan(0);
31
+ expect(empty.reflectance).toBeLessThan(1);
32
+ expect(
33
+ [...empty.transmittance, ...empty.singleScatter, empty.phase].every(Number.isFinite),
34
+ ).toBe(true);
35
+ });
36
+
37
+ it('keeps the zero-extinction limit and small-x RGB oracle continuous', () => {
38
+ const zeroExtinction = integrateSingleLayerMedium({
39
+ coefficients: {
40
+ absorption: [0, 0, 0],
41
+ scattering: [0, 0, 0],
42
+ ior: 1.333,
43
+ },
44
+ distanceMeters: 4,
45
+ cosTheta: 1,
46
+ });
47
+ expect(zeroExtinction.singleScatter).toEqual([0, 0, 0]);
48
+
49
+ const coefficients = {
50
+ absorption: [0, 0.000001, 0.25] as const,
51
+ scattering: [0.000001, 0.000001, 0.5] as const,
52
+ ior: 1.333,
53
+ };
54
+ const distanceMeters = 100000;
55
+ const optics = integrateSingleLayerMedium({
56
+ coefficients,
57
+ distanceMeters,
58
+ maxDistanceMeters: distanceMeters,
59
+ cosTheta: 1,
60
+ });
61
+ const sigmaT = [0.000001, 0.000002, 0.75];
62
+ const expected = sigmaT.map((extinction, index) => {
63
+ const x = extinction * distanceMeters;
64
+ const oneMinusExpNeg = x < 0.001 ? x * (1 - x / 2 + (x * x) / 6) : -Math.expm1(-x);
65
+ return ((coefficients.scattering[index] ?? 0) * oneMinusExpNeg) / extinction;
66
+ });
67
+ expect(optics.distanceMeters).toBe(distanceMeters);
68
+ expect(optics.singleScatter[0]).toBeCloseTo(expected[0] ?? 0, 12);
69
+ expect(optics.singleScatter[1]).toBeCloseTo(expected[1] ?? 0, 12);
70
+ expect(optics.singleScatter[2]).toBeCloseTo(expected[2] ?? 0, 12);
71
+ expect(optics.singleScatter.every(Number.isFinite)).toBe(true);
72
+ });
73
+
74
+ it('allocates Fresnel once and keeps coverage/foam as finite mixing weights', () => {
75
+ const optics = integrateSingleLayerMedium({ coefficients, distanceMeters: 1.5, cosTheta: 0.4 });
76
+ const color = composeSingleLayerMediumColor({
77
+ optics,
78
+ background: [0.2, 0.3, 0.4],
79
+ reflection: [1, 1, 1],
80
+ foamColor: [0.9, 0.9, 0.9],
81
+ coverage: 0.8,
82
+ foam: 0.25,
83
+ });
84
+ expect(color.every(Number.isFinite)).toBe(true);
85
+ expect(color.every((channel) => channel >= 0)).toBe(true);
86
+ expect(
87
+ composeSingleLayerMediumColor({
88
+ optics,
89
+ background: [0, 0, 0],
90
+ reflection: [0, 0, 0],
91
+ coverage: 0,
92
+ }),
93
+ ).toEqual([0, 0, 0]);
94
+ });
95
+
96
+ it('keeps endpoint admission on the undisturbed plane under a strongly tilted ripple', () => {
97
+ const surfacePosition = [0, 0, 0] as const;
98
+ const endpoint = [1, -0.1, 0] as const;
99
+ expect(
100
+ isBelowSingleLayerMediumPlane({
101
+ surfacePosition,
102
+ geometricNormal: [0, 1, 0],
103
+ endpoint,
104
+ }),
105
+ ).toBe(true);
106
+ // This shading normal would classify the same endpoint above water. It is
107
+ // deliberately excluded from the geometric-plane API and WGSL callsite.
108
+ expect(endpoint[0] * 0.995 + endpoint[1] * 0.1).toBeGreaterThan(0);
109
+ });
110
+
111
+ it('keeps refracted color and depth paired and reports conservative fallbacks', () => {
112
+ const base = {
113
+ original: { color: [0.1, 0.2, 0.3] as const, depthMeters: 8, uv: [0.5, 0.5] as const },
114
+ surfaceDepthMeters: 2,
115
+ maxDistanceMeters: 20,
116
+ };
117
+ expect(
118
+ resolveSingleLayerMediumBackground({
119
+ ...base,
120
+ refracted: { color: [0.4, 0.5, 0.6], depthMeters: 7, uv: [0.55, 0.5] },
121
+ }),
122
+ ).toMatchObject({ source: 'refracted', distanceMeters: 5 });
123
+ expect(
124
+ resolveSingleLayerMediumBackground({
125
+ ...base,
126
+ refracted: { color: [0.4, 0.5, 0.6], depthMeters: 1, uv: [0.55, 0.5] },
127
+ }),
128
+ ).toMatchObject({ source: 'unrefracted', reason: 'front', color: base.original.color });
129
+ expect(
130
+ resolveSingleLayerMediumBackground({
131
+ ...base,
132
+ refracted: { color: [0.4, 0.5, 0.6], depthMeters: 7, uv: [1.2, 0.5] },
133
+ }),
134
+ ).toMatchObject({ source: 'unrefracted', reason: 'edge' });
135
+ expect(
136
+ resolveSingleLayerMediumBackground({
137
+ ...base,
138
+ original: { color: [0, 0, 0], depthMeters: Number.NaN, uv: [0.5, 0.5] },
139
+ environment: [0.7, 0.8, 0.9],
140
+ }),
141
+ ).toMatchObject({ source: 'environment', reason: 'sky-miss' });
142
+ expect(
143
+ resolveSingleLayerMediumBackground({
144
+ ...base,
145
+ refracted: { color: [0.4, 0.5, 0.6], depthMeters: 7, uv: [-0.01, 0.5] },
146
+ }),
147
+ ).toMatchObject({ source: 'unrefracted', reason: 'edge', color: base.original.color });
148
+ });
149
+ });
@@ -8,7 +8,7 @@ import {
8
8
  } from '@forgeax/engine-rhi-webgpu';
9
9
  import { Transform } from '@forgeax/engine-scene';
10
10
  import type { TextureAsset } from '@forgeax/engine-types';
11
- import { describe, expect, it } from 'vitest';
11
+ import { afterAll, describe, expect, it } from 'vitest';
12
12
  import {
13
13
  Camera,
14
14
  DirectionalLight,
@@ -32,17 +32,18 @@ const GPU_MAP_MODE_READ = 0x0001;
32
32
  const TEST_REACTIVE = 0;
33
33
  const LIGHTWEIGHT_DAWN = process.env.FORGEAX_DAWN_LIGHTWEIGHT === '1';
34
34
  const ROSTER_SMOKE = process.env.FORGEAX_DAWN_ROSTER_SMOKE === '1';
35
- const requestedSmokeFrames = Number.parseInt(process.env.SMOKE_MIN_FRAMES ?? '300', 10);
35
+ const requestedSmokeFrames = Number.parseInt(process.env.SMOKE_MIN_FRAMES ?? '60', 10);
36
36
  const ROSTER_SMOKE_FRAMES =
37
- Number.isInteger(requestedSmokeFrames) && requestedSmokeFrames > 0 ? requestedSmokeFrames : 300;
37
+ Number.isInteger(requestedSmokeFrames) && requestedSmokeFrames > 0 ? requestedSmokeFrames : 60;
38
38
 
39
39
  const ENGINE_MANIFEST = await (async () => {
40
40
  const { buildEngineShaderManifest } = await import('@forgeax/engine-vite-plugin-shader');
41
41
  return buildEngineShaderManifest();
42
42
  })();
43
- const ENGINE_MANIFEST_URL = `data:application/json,${encodeURIComponent(
44
- JSON.stringify(ENGINE_MANIFEST),
45
- )}`;
43
+ const ENGINE_MANIFEST_URL = URL.createObjectURL(
44
+ new Blob([JSON.stringify(ENGINE_MANIFEST)], { type: 'application/json' }),
45
+ );
46
+ afterAll(() => URL.revokeObjectURL(ENGINE_MANIFEST_URL));
46
47
  const DAWN_BACKEND: RhiBackendPack = {
47
48
  rhi,
48
49
  createShaderModule,
@@ -360,7 +361,7 @@ function luma(pixel: readonly [number, number, number, number]): number {
360
361
  }
361
362
 
362
363
  describe('Standard transmission Dawn ROI', () => {
363
- it('completes a 300-frame transmission stream without renderer errors', async () => {
364
+ it('completes a 60-frame transmission stream without renderer errors', async () => {
364
365
  const result = await renderCase(
365
366
  {
366
367
  name: 'sustained-transmission',
@@ -372,9 +373,9 @@ describe('Standard transmission Dawn ROI', () => {
372
373
  attenuationDistance: 2,
373
374
  renderPath: 'forward',
374
375
  },
375
- 300,
376
+ 60,
376
377
  );
377
- expect(result.framesObserved).toBe(300);
378
+ expect(result.framesObserved).toBe(60);
378
379
  expect(result.errors).toEqual([]);
379
380
  expect(result.observation).toBe(true);
380
381
  expect(result.passNames).toContain('transmission-forward');
@@ -537,7 +538,7 @@ describe('Standard transmission Dawn ROI', () => {
537
538
  }, 120_000);
538
539
 
539
540
  if (ROSTER_SMOKE) {
540
- it('emits the canonical 300-frame Dawn roster receipt', async () => {
541
+ it('emits the canonical 60-frame Dawn roster receipt', async () => {
541
542
  const result = await renderCase(
542
543
  {
543
544
  name: 'roster-stability',
@@ -551,7 +552,7 @@ describe('Standard transmission Dawn ROI', () => {
551
552
  },
552
553
  ROSTER_SMOKE_FRAMES,
553
554
  );
554
- expect(result.framesObserved).toBeGreaterThanOrEqual(300);
555
+ expect(result.framesObserved).toBeGreaterThanOrEqual(60);
555
556
  expect(result.observation).toBe(true);
556
557
  expect(result.errors).toEqual([]);
557
558
  process.stdout.write(`[smoke] frames observed=${result.framesObserved}\n`);