@forgeax/engine-render 0.0.0-dev.8d955ade1c79

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 (891) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +647 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/authoring-path.unit.test.d.ts +2 -0
  5. package/dist/__tests__/authoring-path.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts +2 -0
  7. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts.map +1 -0
  8. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  9. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/cluster-binner.test.d.ts +2 -0
  11. package/dist/__tests__/cluster-binner.test.d.ts.map +1 -0
  12. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts +2 -0
  13. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts +2 -0
  15. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts +2 -0
  17. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts.map +1 -0
  18. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts +2 -0
  19. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts +2 -0
  21. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts.map +1 -0
  22. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts +2 -0
  23. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/factory-contract.integration.test.d.ts +2 -0
  25. package/dist/__tests__/factory-contract.integration.test.d.ts.map +1 -0
  26. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts +2 -0
  27. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/frame-observation.contract.test.d.ts +2 -0
  29. package/dist/__tests__/frame-observation.contract.test.d.ts.map +1 -0
  30. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts +2 -0
  31. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts +2 -0
  33. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts +6 -0
  35. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -0
  36. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts +2 -0
  37. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts.map +1 -0
  38. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts +2 -0
  39. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts.map +1 -0
  40. package/dist/__tests__/gpu-driven-production.integration.test.d.ts +2 -0
  41. package/dist/__tests__/gpu-driven-production.integration.test.d.ts.map +1 -0
  42. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts +2 -0
  43. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts.map +1 -0
  44. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +18 -0
  45. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -0
  46. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts +2 -0
  47. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts.map +1 -0
  48. package/dist/__tests__/gpu-driven-view-reference.d.ts +15 -0
  49. package/dist/__tests__/gpu-driven-view-reference.d.ts.map +1 -0
  50. package/dist/__tests__/gpu-driven-view.browser.test.d.ts +2 -0
  51. package/dist/__tests__/gpu-driven-view.browser.test.d.ts.map +1 -0
  52. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts +2 -0
  53. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts.map +1 -0
  54. package/dist/__tests__/gpu-driven-view.unit.test.d.ts +2 -0
  55. package/dist/__tests__/gpu-driven-view.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts +2 -0
  57. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts +7 -0
  59. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -0
  60. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts +2 -0
  61. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts.map +1 -0
  62. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts +2 -0
  63. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts.map +1 -0
  64. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts +2 -0
  65. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/gpu-scene.dawn.test.d.ts +2 -0
  67. package/dist/__tests__/gpu-scene.dawn.test.d.ts.map +1 -0
  68. package/dist/__tests__/gpu-scene.unit.test.d.ts +2 -0
  69. package/dist/__tests__/gpu-scene.unit.test.d.ts.map +1 -0
  70. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts +2 -0
  71. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts.map +1 -0
  72. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts +2 -0
  73. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts.map +1 -0
  74. package/dist/__tests__/injection-kind-owner.test-d.d.ts +2 -0
  75. package/dist/__tests__/injection-kind-owner.test-d.d.ts.map +1 -0
  76. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts +2 -0
  77. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts.map +1 -0
  78. package/dist/__tests__/light-buffer-layout.unit.test.d.ts +2 -0
  79. package/dist/__tests__/light-buffer-layout.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/material-contract-inventory.unit.test.d.ts +2 -0
  81. package/dist/__tests__/material-contract-inventory.unit.test.d.ts.map +1 -0
  82. package/dist/__tests__/material-cooked-projection.unit.test.d.ts +2 -0
  83. package/dist/__tests__/material-cooked-projection.unit.test.d.ts.map +1 -0
  84. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts +2 -0
  85. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts.map +1 -0
  86. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts +2 -0
  87. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/material-stride-surface.unit.test.d.ts +2 -0
  89. package/dist/__tests__/material-stride-surface.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts +2 -0
  91. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts.map +1 -0
  92. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts +2 -0
  93. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts.map +1 -0
  94. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts +2 -0
  95. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts.map +1 -0
  96. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts +2 -0
  97. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts.map +1 -0
  98. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts +2 -0
  99. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts.map +1 -0
  100. package/dist/__tests__/morph-feature-plan.unit.test.d.ts +2 -0
  101. package/dist/__tests__/morph-feature-plan.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts +2 -0
  103. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts.map +1 -0
  104. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts +2 -0
  105. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts +2 -0
  107. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts +2 -0
  109. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts.map +1 -0
  110. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts +2 -0
  111. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts.map +1 -0
  112. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts +2 -0
  113. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts.map +1 -0
  114. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts +2 -0
  115. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts +2 -0
  117. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts.map +1 -0
  118. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts +2 -0
  119. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts.map +1 -0
  120. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts +2 -0
  121. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts.map +1 -0
  122. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts +2 -0
  123. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts +2 -0
  125. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts.map +1 -0
  126. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  127. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  128. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  129. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  130. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  131. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  132. package/dist/__tests__/profiler-phase-token.test.d.ts +2 -0
  133. package/dist/__tests__/profiler-phase-token.test.d.ts.map +1 -0
  134. package/dist/__tests__/public-surface.test-d.d.ts +2 -0
  135. package/dist/__tests__/public-surface.test-d.d.ts.map +1 -0
  136. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts +2 -0
  137. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts.map +1 -0
  138. package/dist/__tests__/render-error-code-owner.test-d.d.ts +2 -0
  139. package/dist/__tests__/render-error-code-owner.test-d.d.ts.map +1 -0
  140. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts +2 -0
  141. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts.map +1 -0
  142. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +2 -0
  143. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  144. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  145. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  146. package/dist/__tests__/render-feature-context.test-d.d.ts +2 -0
  147. package/dist/__tests__/render-feature-context.test-d.d.ts.map +1 -0
  148. package/dist/__tests__/render-feature-contract.test-d.d.ts +2 -0
  149. package/dist/__tests__/render-feature-contract.test-d.d.ts.map +1 -0
  150. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts +2 -0
  151. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts.map +1 -0
  152. package/dist/__tests__/render-feature-docs.unit.test.d.ts +2 -0
  153. package/dist/__tests__/render-feature-docs.unit.test.d.ts.map +1 -0
  154. package/dist/__tests__/render-feature-errors.unit.test.d.ts +2 -0
  155. package/dist/__tests__/render-feature-errors.unit.test.d.ts.map +1 -0
  156. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts +2 -0
  157. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts.map +1 -0
  158. package/dist/__tests__/render-feature-plan.test-d.d.ts +2 -0
  159. package/dist/__tests__/render-feature-plan.test-d.d.ts.map +1 -0
  160. package/dist/__tests__/render-feature-plan.unit.test.d.ts +2 -0
  161. package/dist/__tests__/render-feature-plan.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts +2 -0
  163. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts +2 -0
  165. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts.map +1 -0
  166. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  167. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts +2 -0
  169. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts.map +1 -0
  170. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts +2 -0
  171. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts.map +1 -0
  172. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts +2 -0
  173. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts.map +1 -0
  174. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts +2 -0
  175. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts.map +1 -0
  176. package/dist/__tests__/render-feature-public-surface.test-d.d.ts +2 -0
  177. package/dist/__tests__/render-feature-public-surface.test-d.d.ts.map +1 -0
  178. package/dist/__tests__/render-feature-retry.unit.test.d.ts +2 -0
  179. package/dist/__tests__/render-feature-retry.unit.test.d.ts.map +1 -0
  180. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts +2 -0
  181. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts.map +1 -0
  182. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts +2 -0
  183. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts.map +1 -0
  184. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts +2 -0
  185. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts.map +1 -0
  186. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts +2 -0
  187. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts.map +1 -0
  188. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts +2 -0
  189. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts.map +1 -0
  190. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts +2 -0
  191. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts.map +1 -0
  192. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts +7 -0
  193. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts.map +1 -0
  194. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts +2 -0
  195. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts.map +1 -0
  196. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts +2 -0
  197. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts.map +1 -0
  198. package/dist/__tests__/render-graph-hzb-gpu.d.ts +7 -0
  199. package/dist/__tests__/render-graph-hzb-gpu.d.ts.map +1 -0
  200. package/dist/__tests__/render-graph-hzb.browser.test.d.ts +2 -0
  201. package/dist/__tests__/render-graph-hzb.browser.test.d.ts.map +1 -0
  202. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts +2 -0
  203. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts.map +1 -0
  204. package/dist/__tests__/render-graph-primitives.unit.test.d.ts +2 -0
  205. package/dist/__tests__/render-graph-primitives.unit.test.d.ts.map +1 -0
  206. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts +12 -0
  207. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts.map +1 -0
  208. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts +2 -0
  209. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts.map +1 -0
  210. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts +2 -0
  211. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts.map +1 -0
  212. package/dist/__tests__/render-scene-projection.unit.test.d.ts +2 -0
  213. package/dist/__tests__/render-scene-projection.unit.test.d.ts.map +1 -0
  214. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts +2 -0
  215. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts.map +1 -0
  216. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  217. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  218. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts +2 -0
  219. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts.map +1 -0
  220. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts +2 -0
  221. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts.map +1 -0
  222. package/dist/__tests__/shader-stage-surface.unit.test.d.ts +2 -0
  223. package/dist/__tests__/shader-stage-surface.unit.test.d.ts.map +1 -0
  224. package/dist/__tests__/ssao-config.unit.test.d.ts +2 -0
  225. package/dist/__tests__/ssao-config.unit.test.d.ts.map +1 -0
  226. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts +2 -0
  227. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts.map +1 -0
  228. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts +2 -0
  229. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts.map +1 -0
  230. package/dist/__tests__/standard-descriptors.test-d.d.ts +2 -0
  231. package/dist/__tests__/standard-descriptors.test-d.d.ts.map +1 -0
  232. package/dist/__tests__/standard-pipeline.dawn.test.d.ts +2 -0
  233. package/dist/__tests__/standard-pipeline.dawn.test.d.ts.map +1 -0
  234. package/dist/__tests__/standard-pipeline.integration.test.d.ts +2 -0
  235. package/dist/__tests__/standard-pipeline.integration.test.d.ts.map +1 -0
  236. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts +2 -0
  237. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts.map +1 -0
  238. package/dist/__tests__/surface-configuration.unit.test.d.ts +2 -0
  239. package/dist/__tests__/surface-configuration.unit.test.d.ts.map +1 -0
  240. package/dist/__tests__/texture-usage-surface.unit.test.d.ts +2 -0
  241. package/dist/__tests__/texture-usage-surface.unit.test.d.ts.map +1 -0
  242. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts +2 -0
  243. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts.map +1 -0
  244. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts +2 -0
  245. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts.map +1 -0
  246. package/dist/__tests__/urp-pipeline.unit.test.d.ts +2 -0
  247. package/dist/__tests__/urp-pipeline.unit.test.d.ts.map +1 -0
  248. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts +2 -0
  249. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts.map +1 -0
  250. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts +2 -0
  251. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts.map +1 -0
  252. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts +2 -0
  253. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts.map +1 -0
  254. package/dist/__tests__/visibility-extract.integration.test.d.ts +2 -0
  255. package/dist/__tests__/visibility-extract.integration.test.d.ts.map +1 -0
  256. package/dist/__tests__/visibility-extract.perf.test.d.ts +2 -0
  257. package/dist/__tests__/visibility-extract.perf.test.d.ts.map +1 -0
  258. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts +2 -0
  259. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts.map +1 -0
  260. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts +2 -0
  261. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/visibility-instances.integration.test.d.ts +2 -0
  263. package/dist/__tests__/visibility-instances.integration.test.d.ts.map +1 -0
  264. package/dist/__tests__/visibility-multi-world.integration.test.d.ts +2 -0
  265. package/dist/__tests__/visibility-multi-world.integration.test.d.ts.map +1 -0
  266. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts +2 -0
  267. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts.map +1 -0
  268. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts +2 -0
  269. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts.map +1 -0
  270. package/dist/__tests__/visibility-public-surface.test-d.d.ts +2 -0
  271. package/dist/__tests__/visibility-public-surface.test-d.d.ts.map +1 -0
  272. package/dist/__tests__/visibility-resolver.unit.test.d.ts +2 -0
  273. package/dist/__tests__/visibility-resolver.unit.test.d.ts.map +1 -0
  274. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts +2 -0
  275. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts.map +1 -0
  276. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts +2 -0
  277. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts.map +1 -0
  278. package/dist/__tests__/vocabulary.unit.test.d.ts +2 -0
  279. package/dist/__tests__/vocabulary.unit.test.d.ts.map +1 -0
  280. package/dist/assembly/backend-contract.d.ts +37 -0
  281. package/dist/assembly/backend-contract.d.ts.map +1 -0
  282. package/dist/assembly/factory.d.ts +207 -0
  283. package/dist/assembly/factory.d.ts.map +1 -0
  284. package/dist/assembly/host-contract.d.ts +84 -0
  285. package/dist/assembly/host-contract.d.ts.map +1 -0
  286. package/dist/assembly/material/assembly.d.ts +21 -0
  287. package/dist/assembly/material/assembly.d.ts.map +1 -0
  288. package/dist/assembly/material/pipeline-projection.d.ts +30 -0
  289. package/dist/assembly/material/pipeline-projection.d.ts.map +1 -0
  290. package/dist/assets/asset-decoders.d.ts +5 -0
  291. package/dist/assets/asset-decoders.d.ts.map +1 -0
  292. package/dist/assets/render-asset-port.d.ts +17 -0
  293. package/dist/assets/render-asset-port.d.ts.map +1 -0
  294. package/dist/assets/resolve-render-asset.d.ts +6 -0
  295. package/dist/assets/resolve-render-asset.d.ts.map +1 -0
  296. package/dist/authoring.d.ts +12 -0
  297. package/dist/authoring.d.ts.map +1 -0
  298. package/dist/authoring.mjs +27 -0
  299. package/dist/authoring.mjs.map +1 -0
  300. package/dist/chunk-CQXZC5XI.mjs +182 -0
  301. package/dist/chunk-CQXZC5XI.mjs.map +1 -0
  302. package/dist/chunk-HCOGPHKS.mjs +93 -0
  303. package/dist/chunk-HCOGPHKS.mjs.map +1 -0
  304. package/dist/chunk-YEJIUW7D.mjs +1152 -0
  305. package/dist/chunk-YEJIUW7D.mjs.map +1 -0
  306. package/dist/cluster-binner.d.ts +152 -0
  307. package/dist/cluster-binner.d.ts.map +1 -0
  308. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts +2 -0
  309. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts.map +1 -0
  310. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts +2 -0
  311. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts.map +1 -0
  312. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  313. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  314. package/dist/components/__tests__/schema-parity.unit.test.d.ts +2 -0
  315. package/dist/components/__tests__/schema-parity.unit.test.d.ts.map +1 -0
  316. package/dist/components/__tests__/visibility-schema.unit.test.d.ts +2 -0
  317. package/dist/components/__tests__/visibility-schema.unit.test.d.ts.map +1 -0
  318. package/dist/components/camera.d.ts +311 -0
  319. package/dist/components/camera.d.ts.map +1 -0
  320. package/dist/components/directional-light.d.ts +76 -0
  321. package/dist/components/directional-light.d.ts.map +1 -0
  322. package/dist/components/glyph-text.d.ts +26 -0
  323. package/dist/components/glyph-text.d.ts.map +1 -0
  324. package/dist/components/index.d.ts +24 -0
  325. package/dist/components/index.d.ts.map +1 -0
  326. package/dist/components/instances.d.ts +41 -0
  327. package/dist/components/instances.d.ts.map +1 -0
  328. package/dist/components/layer.d.ts +34 -0
  329. package/dist/components/layer.d.ts.map +1 -0
  330. package/dist/components/light-helpers.d.ts +53 -0
  331. package/dist/components/light-helpers.d.ts.map +1 -0
  332. package/dist/components/lines.d.ts +5 -0
  333. package/dist/components/lines.d.ts.map +1 -0
  334. package/dist/components/mesh-filter.d.ts +24 -0
  335. package/dist/components/mesh-filter.d.ts.map +1 -0
  336. package/dist/components/mesh-renderer.d.ts +33 -0
  337. package/dist/components/mesh-renderer.d.ts.map +1 -0
  338. package/dist/components/point-light-shadow.d.ts +27 -0
  339. package/dist/components/point-light-shadow.d.ts.map +1 -0
  340. package/dist/components/point-light.d.ts +35 -0
  341. package/dist/components/point-light.d.ts.map +1 -0
  342. package/dist/components/points.d.ts +15 -0
  343. package/dist/components/points.d.ts.map +1 -0
  344. package/dist/components/post-process-params.d.ts +5 -0
  345. package/dist/components/post-process-params.d.ts.map +1 -0
  346. package/dist/components/scene-instance.d.ts +140 -0
  347. package/dist/components/scene-instance.d.ts.map +1 -0
  348. package/dist/components/skybox-background.d.ts +56 -0
  349. package/dist/components/skybox-background.d.ts.map +1 -0
  350. package/dist/components/skylight.d.ts +55 -0
  351. package/dist/components/skylight.d.ts.map +1 -0
  352. package/dist/components/sort-key.d.ts +44 -0
  353. package/dist/components/sort-key.d.ts.map +1 -0
  354. package/dist/components/spot-light.d.ts +81 -0
  355. package/dist/components/spot-light.d.ts.map +1 -0
  356. package/dist/components/sprite-animation.d.ts +74 -0
  357. package/dist/components/sprite-animation.d.ts.map +1 -0
  358. package/dist/components/sprite-instances.d.ts +51 -0
  359. package/dist/components/sprite-instances.d.ts.map +1 -0
  360. package/dist/components/sprite-playback-mode.d.ts +42 -0
  361. package/dist/components/sprite-playback-mode.d.ts.map +1 -0
  362. package/dist/components/sprite-region-override.d.ts +46 -0
  363. package/dist/components/sprite-region-override.d.ts.map +1 -0
  364. package/dist/components/tile-layer.d.ts +106 -0
  365. package/dist/components/tile-layer.d.ts.map +1 -0
  366. package/dist/components/tilemap.d.ts +25 -0
  367. package/dist/components/tilemap.d.ts.map +1 -0
  368. package/dist/components/visibility.d.ts +22 -0
  369. package/dist/components/visibility.d.ts.map +1 -0
  370. package/dist/construct-renderer.d.ts +19 -0
  371. package/dist/construct-renderer.d.ts.map +1 -0
  372. package/dist/construct-renderer.mjs +27462 -0
  373. package/dist/construct-renderer.mjs.map +1 -0
  374. package/dist/debug-draw-glue.d.ts +5 -0
  375. package/dist/debug-draw-glue.d.ts.map +1 -0
  376. package/dist/device/device-scope.d.ts +83 -0
  377. package/dist/device/device-scope.d.ts.map +1 -0
  378. package/dist/device/gpu-residency.d.ts +337 -0
  379. package/dist/device/gpu-residency.d.ts.map +1 -0
  380. package/dist/device/resource-types.d.ts +8 -0
  381. package/dist/device/resource-types.d.ts.map +1 -0
  382. package/dist/engine-metrics.d.ts +23 -0
  383. package/dist/engine-metrics.d.ts.map +1 -0
  384. package/dist/errors/ecs-validation.d.ts +3 -0
  385. package/dist/errors/ecs-validation.d.ts.map +1 -0
  386. package/dist/errors/index.d.ts +4 -0
  387. package/dist/errors/index.d.ts.map +1 -0
  388. package/dist/errors/recover.d.ts +105 -0
  389. package/dist/errors/recover.d.ts.map +1 -0
  390. package/dist/errors/render.d.ts +705 -0
  391. package/dist/errors/render.d.ts.map +1 -0
  392. package/dist/extract/visibility.d.ts +26 -0
  393. package/dist/extract/visibility.d.ts.map +1 -0
  394. package/dist/features/fullscreen.d.ts +19 -0
  395. package/dist/features/fullscreen.d.ts.map +1 -0
  396. package/dist/features/host.d.ts +106 -0
  397. package/dist/features/host.d.ts.map +1 -0
  398. package/dist/features/morph/morph-feature.d.ts +79 -0
  399. package/dist/features/morph/morph-feature.d.ts.map +1 -0
  400. package/dist/features/plan.d.ts +182 -0
  401. package/dist/features/plan.d.ts.map +1 -0
  402. package/dist/features/prepared-gpu-work.d.ts +117 -0
  403. package/dist/features/prepared-gpu-work.d.ts.map +1 -0
  404. package/dist/features/prepared-graphics-store.d.ts +66 -0
  405. package/dist/features/prepared-graphics-store.d.ts.map +1 -0
  406. package/dist/features/prepared-graphics.d.ts +215 -0
  407. package/dist/features/prepared-graphics.d.ts.map +1 -0
  408. package/dist/features/render-graph-compute.d.ts +13 -0
  409. package/dist/features/render-graph-compute.d.ts.map +1 -0
  410. package/dist/features/render-graph-contribution.d.ts +12 -0
  411. package/dist/features/render-graph-contribution.d.ts.map +1 -0
  412. package/dist/features/render-graph-raster.d.ts +38 -0
  413. package/dist/features/render-graph-raster.d.ts.map +1 -0
  414. package/dist/features/render-graph-resources.d.ts +11 -0
  415. package/dist/features/render-graph-resources.d.ts.map +1 -0
  416. package/dist/features/targets.d.ts +32 -0
  417. package/dist/features/targets.d.ts.map +1 -0
  418. package/dist/features/types.d.ts +68 -0
  419. package/dist/features/types.d.ts.map +1 -0
  420. package/dist/features/vocabulary.d.ts +14 -0
  421. package/dist/features/vocabulary.d.ts.map +1 -0
  422. package/dist/fullscreen-post-process-pass.d.ts +157 -0
  423. package/dist/fullscreen-post-process-pass.d.ts.map +1 -0
  424. package/dist/glyph-text-layout-system.d.ts +19 -0
  425. package/dist/glyph-text-layout-system.d.ts.map +1 -0
  426. package/dist/gpu-driven/batch-topology.d.ts +55 -0
  427. package/dist/gpu-driven/batch-topology.d.ts.map +1 -0
  428. package/dist/gpu-driven/production-raster.d.ts +51 -0
  429. package/dist/gpu-driven/production-raster.d.ts.map +1 -0
  430. package/dist/gpu-driven/view-gpu.d.ts +85 -0
  431. package/dist/gpu-driven/view-gpu.d.ts.map +1 -0
  432. package/dist/gpu-resource.d.ts +73 -0
  433. package/dist/gpu-resource.d.ts.map +1 -0
  434. package/dist/gpu-scene-schema.d.ts +78 -0
  435. package/dist/gpu-scene-schema.d.ts.map +1 -0
  436. package/dist/gpu-scene.d.ts +55 -0
  437. package/dist/gpu-scene.d.ts.map +1 -0
  438. package/dist/gpu-stage.d.ts +4 -0
  439. package/dist/gpu-stage.d.ts.map +1 -0
  440. package/dist/gpu-texture-usage.d.ts +6 -0
  441. package/dist/gpu-texture-usage.d.ts.map +1 -0
  442. package/dist/gpu-usage.d.ts +9 -0
  443. package/dist/gpu-usage.d.ts.map +1 -0
  444. package/dist/hdrp-buffers.d.ts +163 -0
  445. package/dist/hdrp-buffers.d.ts.map +1 -0
  446. package/dist/ibl/IblPipelineCache.d.ts +168 -0
  447. package/dist/ibl/IblPipelineCache.d.ts.map +1 -0
  448. package/dist/ibl/skylight-bind-group.d.ts +130 -0
  449. package/dist/ibl/skylight-bind-group.d.ts.map +1 -0
  450. package/dist/index.d.ts +31 -0
  451. package/dist/index.d.ts.map +1 -0
  452. package/dist/index.mjs +169 -0
  453. package/dist/index.mjs.map +1 -0
  454. package/dist/inspection-types.d.ts +72 -0
  455. package/dist/inspection-types.d.ts.map +1 -0
  456. package/dist/instance-buffer-cache.d.ts +56 -0
  457. package/dist/instance-buffer-cache.d.ts.map +1 -0
  458. package/dist/internal.d.ts +2 -0
  459. package/dist/internal.d.ts.map +1 -0
  460. package/dist/internal.mjs +3 -0
  461. package/dist/internal.mjs.map +1 -0
  462. package/dist/lifecycle.d.ts +62 -0
  463. package/dist/lifecycle.d.ts.map +1 -0
  464. package/dist/light-buffer-layout.d.ts +164 -0
  465. package/dist/light-buffer-layout.d.ts.map +1 -0
  466. package/dist/materials.d.ts +47 -0
  467. package/dist/materials.d.ts.map +1 -0
  468. package/dist/mesh-material-bindings.d.ts +43 -0
  469. package/dist/mesh-material-bindings.d.ts.map +1 -0
  470. package/dist/pbr-pipeline.d.ts +301 -0
  471. package/dist/pbr-pipeline.d.ts.map +1 -0
  472. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  473. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  474. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  475. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  476. package/dist/pipeline/standard-profile.d.ts +40 -0
  477. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  478. package/dist/pipeline-builder.d.ts +122 -0
  479. package/dist/pipeline-builder.d.ts.map +1 -0
  480. package/dist/pipeline-spec-types.d.ts +24 -0
  481. package/dist/pipeline-spec-types.d.ts.map +1 -0
  482. package/dist/pipeline-spec.d.ts +367 -0
  483. package/dist/pipeline-spec.d.ts.map +1 -0
  484. package/dist/plugin.d.ts +4 -0
  485. package/dist/plugin.d.ts.map +1 -0
  486. package/dist/points-lines/__tests__/bounds.unit.test.d.ts +2 -0
  487. package/dist/points-lines/__tests__/bounds.unit.test.d.ts.map +1 -0
  488. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts +2 -0
  489. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts.map +1 -0
  490. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts +2 -0
  491. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts.map +1 -0
  492. package/dist/points-lines/__tests__/inspection.unit.test.d.ts +2 -0
  493. package/dist/points-lines/__tests__/inspection.unit.test.d.ts.map +1 -0
  494. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts +2 -0
  495. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts.map +1 -0
  496. package/dist/points-lines/__tests__/points-lines.bench.d.ts +2 -0
  497. package/dist/points-lines/__tests__/points-lines.bench.d.ts.map +1 -0
  498. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts +2 -0
  499. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts.map +1 -0
  500. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts +2 -0
  501. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts.map +1 -0
  502. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts +2 -0
  503. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts.map +1 -0
  504. package/dist/points-lines/admission.d.ts +36 -0
  505. package/dist/points-lines/admission.d.ts.map +1 -0
  506. package/dist/points-lines/bounds.d.ts +8 -0
  507. package/dist/points-lines/bounds.d.ts.map +1 -0
  508. package/dist/points-lines/expansion-cache.d.ts +28 -0
  509. package/dist/points-lines/expansion-cache.d.ts.map +1 -0
  510. package/dist/points-lines/inspection.d.ts +53 -0
  511. package/dist/points-lines/inspection.d.ts.map +1 -0
  512. package/dist/points-lines/prepare.d.ts +67 -0
  513. package/dist/points-lines/prepare.d.ts.map +1 -0
  514. package/dist/points-lines/record.d.ts +60 -0
  515. package/dist/points-lines/record.d.ts.map +1 -0
  516. package/dist/points-lines/snapshot.d.ts +49 -0
  517. package/dist/points-lines/snapshot.d.ts.map +1 -0
  518. package/dist/post-process-errors.d.ts +182 -0
  519. package/dist/post-process-errors.d.ts.map +1 -0
  520. package/dist/prepare/prepared-graphics-resolver.d.ts +59 -0
  521. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -0
  522. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts +2 -0
  523. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts.map +1 -0
  524. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts +2 -0
  525. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts.map +1 -0
  526. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  527. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  528. package/dist/record/__tests__/video-texture-view.unit.test.d.ts +2 -0
  529. package/dist/record/__tests__/video-texture-view.unit.test.d.ts.map +1 -0
  530. package/dist/record/frame-lighting.d.ts +121 -0
  531. package/dist/record/frame-lighting.d.ts.map +1 -0
  532. package/dist/record/frame-snapshot.d.ts +429 -0
  533. package/dist/record/frame-snapshot.d.ts.map +1 -0
  534. package/dist/record/frame-targets.d.ts +20 -0
  535. package/dist/record/frame-targets.d.ts.map +1 -0
  536. package/dist/record/frame.d.ts +71 -0
  537. package/dist/record/frame.d.ts.map +1 -0
  538. package/dist/record/helpers.d.ts +102 -0
  539. package/dist/record/helpers.d.ts.map +1 -0
  540. package/dist/record/main-pass-geometry.d.ts +28 -0
  541. package/dist/record/main-pass-geometry.d.ts.map +1 -0
  542. package/dist/record/main-pass-material.d.ts +204 -0
  543. package/dist/record/main-pass-material.d.ts.map +1 -0
  544. package/dist/record/main-pass-sprite-draws.d.ts +43 -0
  545. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -0
  546. package/dist/record/main-pass.d.ts +20 -0
  547. package/dist/record/main-pass.d.ts.map +1 -0
  548. package/dist/record/mesh-ssbo.d.ts +446 -0
  549. package/dist/record/mesh-ssbo.d.ts.map +1 -0
  550. package/dist/record/render-context.d.ts +252 -0
  551. package/dist/record/render-context.d.ts.map +1 -0
  552. package/dist/record/shadow-pass.d.ts +52 -0
  553. package/dist/record/shadow-pass.d.ts.map +1 -0
  554. package/dist/record/skybox-post-pass.d.ts +33 -0
  555. package/dist/record/skybox-post-pass.d.ts.map +1 -0
  556. package/dist/record/typed-frame-graph.d.ts +35 -0
  557. package/dist/record/typed-frame-graph.d.ts.map +1 -0
  558. package/dist/record/view-ubo.d.ts +45 -0
  559. package/dist/record/view-ubo.d.ts.map +1 -0
  560. package/dist/render-contract.d.ts +424 -0
  561. package/dist/render-contract.d.ts.map +1 -0
  562. package/dist/render-data.d.ts +143 -0
  563. package/dist/render-data.d.ts.map +1 -0
  564. package/dist/render-graph-primitives.d.ts +76 -0
  565. package/dist/render-graph-primitives.d.ts.map +1 -0
  566. package/dist/render-pipeline.d.ts +110 -0
  567. package/dist/render-pipeline.d.ts.map +1 -0
  568. package/dist/render-system-extract.d.ts +868 -0
  569. package/dist/render-system-extract.d.ts.map +1 -0
  570. package/dist/render-system.d.ts +125 -0
  571. package/dist/render-system.d.ts.map +1 -0
  572. package/dist/scene/render-scene-types.d.ts +61 -0
  573. package/dist/scene/render-scene-types.d.ts.map +1 -0
  574. package/dist/scene/render-scene.d.ts +112 -0
  575. package/dist/scene/render-scene.d.ts.map +1 -0
  576. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +30 -0
  577. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -0
  578. package/dist/shadow-atlas.d.ts +117 -0
  579. package/dist/shadow-atlas.d.ts.map +1 -0
  580. package/dist/ssao-buffers.d.ts +50 -0
  581. package/dist/ssao-buffers.d.ts.map +1 -0
  582. package/dist/ssao-config.d.ts +28 -0
  583. package/dist/ssao-config.d.ts.map +1 -0
  584. package/dist/systems/active-camera.d.ts +53 -0
  585. package/dist/systems/active-camera.d.ts.map +1 -0
  586. package/dist/systems/pass-selector.d.ts +24 -0
  587. package/dist/systems/pass-selector.d.ts.map +1 -0
  588. package/dist/systems/skin-palette-allocator.d.ts +49 -0
  589. package/dist/systems/skin-palette-allocator.d.ts.map +1 -0
  590. package/dist/systems/skin-palette-types.d.ts +14 -0
  591. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  592. package/dist/systems/transparent-sort-config.d.ts +112 -0
  593. package/dist/systems/transparent-sort-config.d.ts.map +1 -0
  594. package/dist/tilemap-chunk-extract-system.d.ts +143 -0
  595. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -0
  596. package/dist/typed-render-graph-primitives.d.ts +57 -0
  597. package/dist/typed-render-graph-primitives.d.ts.map +1 -0
  598. package/dist/typed-shadow-passes.d.ts +11 -0
  599. package/dist/typed-shadow-passes.d.ts.map +1 -0
  600. package/package.json +94 -0
  601. package/src/__tests__/authoring-path.unit.test.ts +23 -0
  602. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +21 -0
  603. package/src/__tests__/callback-inference.test-d.ts +8 -0
  604. package/src/__tests__/cluster-binner.test.ts +272 -0
  605. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +20 -0
  606. package/src/__tests__/construct-renderer-identity.unit.test.ts +23 -0
  607. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  608. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  609. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +23 -0
  610. package/src/__tests__/direct-light-snapshot.unit.test.ts +61 -0
  611. package/src/__tests__/factory-contract.integration.test.ts +280 -0
  612. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +15 -0
  613. package/src/__tests__/frame-observation.contract.test.ts +112 -0
  614. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  615. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +167 -0
  616. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +350 -0
  617. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +12 -0
  618. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +16 -0
  619. package/src/__tests__/gpu-driven-production.integration.test.ts +436 -0
  620. package/src/__tests__/gpu-driven-scaling.unit.test.ts +87 -0
  621. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +271 -0
  622. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +290 -0
  623. package/src/__tests__/gpu-driven-view-reference.ts +111 -0
  624. package/src/__tests__/gpu-driven-view.browser.test.ts +30 -0
  625. package/src/__tests__/gpu-driven-view.dawn.test.ts +28 -0
  626. package/src/__tests__/gpu-driven-view.unit.test.ts +199 -0
  627. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +59 -0
  628. package/src/__tests__/gpu-scene-render-graph-gpu.ts +308 -0
  629. package/src/__tests__/gpu-scene-render-graph.browser.test.ts +19 -0
  630. package/src/__tests__/gpu-scene-render-graph.dawn.test.ts +19 -0
  631. package/src/__tests__/gpu-scene-schema.unit.test.ts +16 -0
  632. package/src/__tests__/gpu-scene.dawn.test.ts +205 -0
  633. package/src/__tests__/gpu-scene.unit.test.ts +147 -0
  634. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  635. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +92 -0
  636. package/src/__tests__/injection-kind-owner.test-d.ts +14 -0
  637. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +728 -0
  638. package/src/__tests__/light-buffer-layout.unit.test.ts +40 -0
  639. package/src/__tests__/material-contract-inventory.unit.test.ts +24 -0
  640. package/src/__tests__/material-cooked-projection.unit.test.ts +150 -0
  641. package/src/__tests__/material-snapshot-mutation.integration.test.ts +53 -0
  642. package/src/__tests__/material-static-dynamic-route.unit.test.ts +94 -0
  643. package/src/__tests__/material-stride-surface.unit.test.ts +32 -0
  644. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +106 -0
  645. package/src/__tests__/mesh-material-bindings.unit.test.ts +89 -0
  646. package/src/__tests__/mesh-stride-surface.unit.test.ts +16 -0
  647. package/src/__tests__/morph-culling-reentry.dawn.test.ts +157 -0
  648. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +80 -0
  649. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  650. package/src/__tests__/morph-visual-evidence.integration.test.ts +80 -0
  651. package/src/__tests__/nineslice-handle-surface.unit.test.ts +19 -0
  652. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +201 -0
  653. package/src/__tests__/prepared-buffer-kind-owner.test-d.ts +29 -0
  654. package/src/__tests__/prepared-graphics-capability.unit.test.ts +65 -0
  655. package/src/__tests__/prepared-graphics-generation.unit.test.ts +161 -0
  656. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +138 -0
  657. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +29 -0
  658. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +285 -0
  659. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +105 -0
  660. package/src/__tests__/prepared-graphics-store.unit.test.ts +154 -0
  661. package/src/__tests__/prepared-graphics-validation.unit.test.ts +176 -0
  662. package/src/__tests__/profiler-default-off.test.ts +22 -0
  663. package/src/__tests__/profiler-phase-catalog.test.ts +66 -0
  664. package/src/__tests__/profiler-phase-integration.test.ts +62 -0
  665. package/src/__tests__/profiler-phase-token.test.ts +79 -0
  666. package/src/__tests__/public-surface.test-d.ts +94 -0
  667. package/src/__tests__/recover-error-policy-owner.unit.test.ts +107 -0
  668. package/src/__tests__/render-error-code-owner.test-d.ts +116 -0
  669. package/src/__tests__/render-error-detail-ssot.test-d.ts +139 -0
  670. package/src/__tests__/render-error-exhaustive.test-d.ts +110 -0
  671. package/src/__tests__/render-feature-assembly.test-d.ts +43 -0
  672. package/src/__tests__/render-feature-context.test-d.ts +57 -0
  673. package/src/__tests__/render-feature-contract.test-d.ts +49 -0
  674. package/src/__tests__/render-feature-diagnostics.unit.test.ts +149 -0
  675. package/src/__tests__/render-feature-docs.unit.test.ts +89 -0
  676. package/src/__tests__/render-feature-errors.unit.test.ts +47 -0
  677. package/src/__tests__/render-feature-gpu-work.integration.test.ts +316 -0
  678. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  679. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  680. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +90 -0
  681. package/src/__tests__/render-feature-prepared-errors.test-d.ts +79 -0
  682. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +80 -0
  683. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +72 -0
  684. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +36 -0
  685. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +74 -0
  686. package/src/__tests__/render-feature-prepared-graphics.unit.test.ts +121 -0
  687. package/src/__tests__/render-feature-public-surface.test-d.ts +57 -0
  688. package/src/__tests__/render-feature-retry.unit.test.ts +87 -0
  689. package/src/__tests__/render-feature-scheduling.unit.test.ts +110 -0
  690. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +137 -0
  691. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +146 -0
  692. package/src/__tests__/render-feature-visibility-context.test-d.ts +33 -0
  693. package/src/__tests__/render-feature-visibility-context.unit.test.ts +37 -0
  694. package/src/__tests__/render-feature-zero-work.unit.test.ts +76 -0
  695. package/src/__tests__/render-graph-compute-raster-gpu.ts +342 -0
  696. package/src/__tests__/render-graph-compute-raster.browser.test.ts +16 -0
  697. package/src/__tests__/render-graph-compute-raster.dawn.test.ts +22 -0
  698. package/src/__tests__/render-graph-hzb-gpu.ts +239 -0
  699. package/src/__tests__/render-graph-hzb.browser.test.ts +16 -0
  700. package/src/__tests__/render-graph-hzb.dawn.test.ts +23 -0
  701. package/src/__tests__/render-graph-primitives.unit.test.ts +22 -0
  702. package/src/__tests__/render-graph-storage-indirect-gpu.ts +162 -0
  703. package/src/__tests__/render-graph-storage-indirect.browser.test.ts +21 -0
  704. package/src/__tests__/render-graph-storage-indirect.dawn.test.ts +28 -0
  705. package/src/__tests__/render-scene-projection.unit.test.ts +168 -0
  706. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +121 -0
  707. package/src/__tests__/renderer-lifecycle.integration.test.ts +58 -0
  708. package/src/__tests__/rhi-backend-package-boundary.unit.test.ts +11 -0
  709. package/src/__tests__/scriptable-pack-consumer.test-d.ts +14 -0
  710. package/src/__tests__/shader-stage-surface.unit.test.ts +43 -0
  711. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  712. package/src/__tests__/ssao-kernel-surface.unit.test.ts +14 -0
  713. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  714. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  715. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  716. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  717. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  718. package/src/__tests__/surface-configuration.unit.test.ts +91 -0
  719. package/src/__tests__/texture-usage-surface.unit.test.ts +58 -0
  720. package/src/__tests__/typed-pipeline-topology.unit.test.ts +223 -0
  721. package/src/__tests__/urp-pipeline-targets.unit.test.ts +42 -0
  722. package/src/__tests__/urp-pipeline.unit.test.ts +14 -0
  723. package/src/__tests__/vertex-color-pipeline.unit.test.ts +132 -0
  724. package/src/__tests__/vertex-layout-consumer.unit.test.ts +25 -0
  725. package/src/__tests__/visibility-diagnostics.integration.test.ts +62 -0
  726. package/src/__tests__/visibility-extract.integration.test.ts +98 -0
  727. package/src/__tests__/visibility-extract.perf.test.ts +130 -0
  728. package/src/__tests__/visibility-feature-dedup.integration.test.ts +55 -0
  729. package/src/__tests__/visibility-hidden-report.unit.test.ts +36 -0
  730. package/src/__tests__/visibility-instances.integration.test.ts +46 -0
  731. package/src/__tests__/visibility-multi-world.integration.test.ts +86 -0
  732. package/src/__tests__/visibility-producer-matrix.integration.test.ts +168 -0
  733. package/src/__tests__/visibility-producer-matrix.unit.test.ts +96 -0
  734. package/src/__tests__/visibility-public-surface.test-d.ts +27 -0
  735. package/src/__tests__/visibility-resolver.unit.test.ts +85 -0
  736. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  737. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +60 -0
  738. package/src/__tests__/vocabulary.unit.test.ts +21 -0
  739. package/src/assembly/backend-contract.ts +57 -0
  740. package/src/assembly/factory.ts +8130 -0
  741. package/src/assembly/host-contract.ts +101 -0
  742. package/src/assembly/material/assembly.ts +48 -0
  743. package/src/assembly/material/pipeline-projection.ts +63 -0
  744. package/src/assets/asset-decoders.ts +158 -0
  745. package/src/assets/render-asset-port.ts +44 -0
  746. package/src/assets/resolve-render-asset.ts +13 -0
  747. package/src/authoring.ts +17 -0
  748. package/src/cluster-binner.ts +700 -0
  749. package/src/components/__tests__/points-lines-admission.unit.test.ts +219 -0
  750. package/src/components/__tests__/points-lines-schema.unit.test.ts +56 -0
  751. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  752. package/src/components/__tests__/schema-parity.unit.test.ts +25 -0
  753. package/src/components/__tests__/visibility-schema.unit.test.ts +35 -0
  754. package/src/components/camera.ts +512 -0
  755. package/src/components/directional-light.ts +120 -0
  756. package/src/components/glyph-text.ts +64 -0
  757. package/src/components/index.ts +54 -0
  758. package/src/components/instances.ts +206 -0
  759. package/src/components/layer.ts +69 -0
  760. package/src/components/light-helpers.ts +188 -0
  761. package/src/components/lines.ts +18 -0
  762. package/src/components/mesh-filter.ts +60 -0
  763. package/src/components/mesh-renderer.ts +61 -0
  764. package/src/components/point-light-shadow.ts +43 -0
  765. package/src/components/point-light.ts +65 -0
  766. package/src/components/points.ts +40 -0
  767. package/src/components/post-process-params.ts +35 -0
  768. package/src/components/scene-instance.ts +193 -0
  769. package/src/components/skybox-background.ts +103 -0
  770. package/src/components/skylight.ts +97 -0
  771. package/src/components/sort-key.ts +75 -0
  772. package/src/components/spot-light.ts +124 -0
  773. package/src/components/sprite-animation.ts +168 -0
  774. package/src/components/sprite-instances.ts +179 -0
  775. package/src/components/sprite-playback-mode.ts +79 -0
  776. package/src/components/sprite-region-override.ts +105 -0
  777. package/src/components/tile-layer.ts +167 -0
  778. package/src/components/tilemap.ts +48 -0
  779. package/src/components/visibility.ts +53 -0
  780. package/src/construct-renderer.ts +67 -0
  781. package/src/debug-draw-glue.ts +48 -0
  782. package/src/device/device-scope.ts +306 -0
  783. package/src/device/gpu-residency.ts +1822 -0
  784. package/src/device/resource-types.ts +20 -0
  785. package/src/engine-metrics.ts +82 -0
  786. package/src/errors/ecs-validation.ts +16 -0
  787. package/src/errors/index.ts +3 -0
  788. package/src/errors/recover.ts +161 -0
  789. package/src/errors/render.ts +1284 -0
  790. package/src/extract/visibility.ts +120 -0
  791. package/src/features/fullscreen.ts +46 -0
  792. package/src/features/host.ts +1363 -0
  793. package/src/features/morph/morph-feature.ts +377 -0
  794. package/src/features/plan.ts +447 -0
  795. package/src/features/prepared-gpu-work.ts +959 -0
  796. package/src/features/prepared-graphics-store.ts +449 -0
  797. package/src/features/prepared-graphics.ts +420 -0
  798. package/src/features/render-graph-compute.ts +69 -0
  799. package/src/features/render-graph-contribution.ts +75 -0
  800. package/src/features/render-graph-raster.ts +332 -0
  801. package/src/features/render-graph-resources.ts +38 -0
  802. package/src/features/targets.ts +70 -0
  803. package/src/features/types.ts +103 -0
  804. package/src/features/vocabulary.ts +24 -0
  805. package/src/fullscreen-post-process-pass.ts +363 -0
  806. package/src/glyph-text-layout-system.ts +421 -0
  807. package/src/gpu-driven/batch-topology.ts +245 -0
  808. package/src/gpu-driven/production-raster.ts +695 -0
  809. package/src/gpu-driven/view-gpu.ts +703 -0
  810. package/src/gpu-resource.ts +159 -0
  811. package/src/gpu-scene-schema.ts +136 -0
  812. package/src/gpu-scene.ts +722 -0
  813. package/src/gpu-stage.ts +9 -0
  814. package/src/gpu-texture-usage.ts +12 -0
  815. package/src/gpu-usage.ts +14 -0
  816. package/src/hdrp-buffers.ts +480 -0
  817. package/src/ibl/IblPipelineCache.ts +1006 -0
  818. package/src/ibl/skylight-bind-group.ts +513 -0
  819. package/src/index.ts +129 -0
  820. package/src/inspection-types.ts +80 -0
  821. package/src/instance-buffer-cache.ts +95 -0
  822. package/src/internal.ts +9 -0
  823. package/src/lifecycle.ts +168 -0
  824. package/src/light-buffer-layout.ts +346 -0
  825. package/src/materials.ts +214 -0
  826. package/src/mesh-material-bindings.ts +103 -0
  827. package/src/pbr-pipeline.ts +1137 -0
  828. package/src/pipeline/standard-forward-lane.ts +229 -0
  829. package/src/pipeline/standard-pipeline.ts +555 -0
  830. package/src/pipeline/standard-profile.ts +65 -0
  831. package/src/pipeline-builder.ts +382 -0
  832. package/src/pipeline-spec-types.ts +28 -0
  833. package/src/pipeline-spec.ts +1231 -0
  834. package/src/plugin.ts +69 -0
  835. package/src/points-lines/__tests__/bounds.unit.test.ts +21 -0
  836. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +157 -0
  837. package/src/points-lines/__tests__/inspection-lanes.integration.test.ts +146 -0
  838. package/src/points-lines/__tests__/inspection.unit.test.ts +173 -0
  839. package/src/points-lines/__tests__/lane-structural.integration.test.ts +122 -0
  840. package/src/points-lines/__tests__/points-lines.bench.ts +400 -0
  841. package/src/points-lines/__tests__/raster-lane.integration.test.ts +44 -0
  842. package/src/points-lines/__tests__/snapshot.unit.test.ts +101 -0
  843. package/src/points-lines/__tests__/view-ubo.unit.test.ts +73 -0
  844. package/src/points-lines/admission.ts +238 -0
  845. package/src/points-lines/bounds.ts +23 -0
  846. package/src/points-lines/expansion-cache.ts +215 -0
  847. package/src/points-lines/inspection.ts +97 -0
  848. package/src/points-lines/prepare.ts +177 -0
  849. package/src/points-lines/record.ts +125 -0
  850. package/src/points-lines/snapshot.ts +130 -0
  851. package/src/post-process-errors.ts +302 -0
  852. package/src/prepare/prepared-graphics-resolver.ts +456 -0
  853. package/src/record/__tests__/material-bg-cache.unit.test.ts +41 -0
  854. package/src/record/__tests__/material-slot-plan.unit.test.ts +44 -0
  855. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  856. package/src/record/__tests__/video-texture-view.unit.test.ts +90 -0
  857. package/src/record/frame-lighting.ts +1074 -0
  858. package/src/record/frame-snapshot.ts +500 -0
  859. package/src/record/frame-targets.ts +137 -0
  860. package/src/record/frame.ts +1598 -0
  861. package/src/record/helpers.ts +284 -0
  862. package/src/record/main-pass-geometry.ts +1065 -0
  863. package/src/record/main-pass-material.ts +1043 -0
  864. package/src/record/main-pass-sprite-draws.ts +1137 -0
  865. package/src/record/main-pass.ts +610 -0
  866. package/src/record/mesh-ssbo.ts +885 -0
  867. package/src/record/render-context.ts +384 -0
  868. package/src/record/shadow-pass.ts +698 -0
  869. package/src/record/skybox-post-pass.ts +593 -0
  870. package/src/record/typed-frame-graph.ts +461 -0
  871. package/src/record/view-ubo.ts +222 -0
  872. package/src/render-contract.ts +582 -0
  873. package/src/render-data.ts +385 -0
  874. package/src/render-graph-primitives.ts +811 -0
  875. package/src/render-pipeline.ts +259 -0
  876. package/src/render-system-extract.ts +4585 -0
  877. package/src/render-system.ts +1933 -0
  878. package/src/scene/render-scene-types.ts +67 -0
  879. package/src/scene/render-scene.ts +1087 -0
  880. package/src/scene-instances/post-spawn-resolve-joints.ts +165 -0
  881. package/src/shadow-atlas.ts +244 -0
  882. package/src/ssao-buffers.ts +334 -0
  883. package/src/ssao-config.ts +61 -0
  884. package/src/systems/active-camera.ts +116 -0
  885. package/src/systems/pass-selector.ts +49 -0
  886. package/src/systems/skin-palette-allocator.ts +251 -0
  887. package/src/systems/skin-palette-types.ts +14 -0
  888. package/src/systems/transparent-sort-config.ts +233 -0
  889. package/src/tilemap-chunk-extract-system.ts +1290 -0
  890. package/src/typed-render-graph-primitives.ts +541 -0
  891. package/src/typed-shadow-passes.ts +165 -0
@@ -0,0 +1,1074 @@
1
+ // @forgeax/engine-runtime - RenderSystem record stage: per-frame lighting.
2
+ // feat-20260704 M5/w31: further-split from frame.ts (AC-05 <=1500 lines/file).
3
+ // Pure leaf helpers invoked once each from recordFrame; behavior verbatim.
4
+
5
+ import { mat4, type Vec3, vec3 } from '@forgeax/engine-math';
6
+ import {
7
+ type BindGroup,
8
+ type BindGroupLayout,
9
+ RhiError,
10
+ type TextureView,
11
+ } from '@forgeax/engine-rhi';
12
+ import { toShared } from '@forgeax/engine-types';
13
+ import { bin, type ClusterBinProfilePhase, type ClusterBinProfileRunner } from '../cluster-binner';
14
+ import {
15
+ HdrpIndexListOverflowError,
16
+ HdrpLightBudgetExceededError,
17
+ PointShadowAtlasBoundsViolationError,
18
+ PointShadowAtlasUninitializedError,
19
+ } from '../errors/render';
20
+ import {
21
+ createHdrpClusterMembershipBindGroup,
22
+ createHdrpUnifiedBindGroup,
23
+ getOrCreateHdrpBuffers,
24
+ HDRP_UNIFORM_LIGHT_CAPACITY,
25
+ packClusterUniform,
26
+ } from '../hdrp-buffers';
27
+ import {
28
+ LIGHT_ARRAY_HEADER_BYTES,
29
+ LIGHT_ARRAY_MAX_SLOTS,
30
+ POINT_LIGHT_STD430_BYTES,
31
+ packLightArrayHeader,
32
+ packLightSlot,
33
+ packPointLight,
34
+ packSpotLight,
35
+ SPOT_LIGHT_STD430_BYTES,
36
+ } from '../light-buffer-layout';
37
+ import { DEFAULT_CLUSTER_GRID, LIGHT_INDEX_LIST_CAPACITY } from '../pipeline/standard-profile';
38
+ import type { CameraSnapshot, RenderHdrpClusterPhase } from '../render-contract';
39
+ import type {
40
+ DirectionalLightSnapshot,
41
+ ExtractedLights,
42
+ RenderableSnapshot,
43
+ SkyboxSnapshot,
44
+ SkylightSnapshot,
45
+ } from '../render-system-extract';
46
+ import { ShadowAtlas } from '../shadow-atlas';
47
+ import { getOrCreateSsaoBuffers } from '../ssao-buffers';
48
+ import { getSsaoParameters } from '../ssao-config';
49
+ import type { BindGroupCounts, RenderFrameState } from './frame-snapshot';
50
+ import {
51
+ computeProjectionMatrix,
52
+ computeViewMatrix,
53
+ isLitMaterialSnapshot,
54
+ warnMultiLightDirectional,
55
+ warnMultiLightPoint,
56
+ warnMultiLightSpot,
57
+ } from './helpers';
58
+ import { getOrCreateFromChain, MESH_SSBO_BYTES, MESH_UBO_FULL_ARRAY_BYTES } from './mesh-ssbo';
59
+ import type { PipelineState, RecordProfileRunner, RenderSystemInternals } from './render-context';
60
+ import { POINTS_LINES_VIEW_BYTES, VIEW_UNIFORM_BYTES } from './view-ubo';
61
+
62
+ function runHdrpClusterProfilePhase<T>(
63
+ runner: RecordProfileRunner | undefined,
64
+ phase: RenderHdrpClusterPhase,
65
+ action: () => T,
66
+ ): T {
67
+ return runner === undefined ? action() : runner(phase, action);
68
+ }
69
+
70
+ /**
71
+ * feat-20260704 M3/w18: per-frame bind-group cache resolution, extracted
72
+ * verbatim from `recordFrame`. Walks the handle-identity WeakMap caches
73
+ * (feat-20260531 M2 + feat-20260622 M3) to resolve or lazily create the view
74
+ * (@group 0), mesh (@group 2), and — when HDRP is active — HDRP-unified cluster
75
+ * bind groups. Returns all three (null when `hasValidated` is false, the Case E
76
+ * clear-pass-only path). No new mutable state: `bindGroupCounts` accounting +
77
+ * cache maps are threaded through explicitly.
78
+ *
79
+ * @internal
80
+ */
81
+ export function buildPerFrameBindGroups(
82
+ internals: RenderSystemInternals,
83
+ frameState: RenderFrameState,
84
+ pipelineState: PipelineState,
85
+ hasValidated: boolean,
86
+ bindGroupCounts: BindGroupCounts,
87
+ graphTargets?: {
88
+ readonly directionalShadow?: TextureView | undefined;
89
+ readonly spotShadow?: TextureView | undefined;
90
+ },
91
+ includeView = true,
92
+ ): {
93
+ viewBindGroup: BindGroup | null;
94
+ meshBindGroup: BindGroup | null;
95
+ hdrpClusterBindGroup: BindGroup | null;
96
+ hdrpClusterMembershipBindGroup: BindGroup | null;
97
+ } {
98
+ // View main (#1) chain = b0(viewUniformBuffer), b1(pointLightsBuffer),
99
+ // b2(spotLightsBuffer), b3(graph shadowDepth view or
100
+ // shadowFallbackTextureView), b4(shadowSampler), b5(atlas view), b6
101
+ // (shadowParams); variant 'view-main'.
102
+ // Mesh (#2) chain = inner b0 buffer (meshStorageBuffer.buffer); variant 'mesh'.
103
+ let viewBindGroup: BindGroup | null = null;
104
+ let meshBindGroup: BindGroup | null = null;
105
+ // feat-20260609-hdrp-cluster-fragment-ggx M4 / w19: HDRP unified group(2)
106
+ // BindGroup. Non-null when `frameState.isHdrpActive` AND HDRP buffer
107
+ // allocation succeeded; consumed by recordMainPass at `setBindGroup(2, ...)`.
108
+ let hdrpClusterBindGroup: BindGroup | null = null;
109
+ const hdrpClusterMembershipBindGroup: BindGroup | null = frameState.isHdrpActive
110
+ ? frameState.hdrpClusterMembershipBindGroup
111
+ : null;
112
+ if (hasValidated) {
113
+ // Shadow atlas view comes from the typed graph target.
114
+ // Graph owns the texture lifecycle; record-stage reads the resolved
115
+ // view each frame (D-2 SSOT). When the graph has not allocated the
116
+ // target (castShadow:false or shadowMapSize=0),
117
+ // `getColorTargetView` returns undefined and we fall through to the
118
+ // 1x1 fallback view that keeps the BGL satisfied.
119
+ if (includeView) {
120
+ const shadowSampler = pipelineState.perPassResources.shadowSampler;
121
+ if (shadowSampler === null) {
122
+ return {
123
+ viewBindGroup: null,
124
+ meshBindGroup: null,
125
+ hdrpClusterBindGroup: null,
126
+ hdrpClusterMembershipBindGroup,
127
+ };
128
+ }
129
+ const graphShadowView = graphTargets?.directionalShadow;
130
+ const b3View =
131
+ graphShadowView !== undefined ? graphShadowView : pipelineState.shadowFallbackTextureView;
132
+ // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: bind the real
133
+ // ShadowAtlas cube_array view when point shadows are active in this
134
+ // frame; otherwise the 1x1x6 fallback (cleared to 1.0 = fully lit).
135
+ const pointShadowAtlas = frameState.pointShadowAtlas;
136
+ const atlasViewMaybe = pointShadowAtlas?.isAllocated()
137
+ ? pointShadowAtlas.getAtlasView()
138
+ : null;
139
+ const b5View =
140
+ atlasViewMaybe !== null ? atlasViewMaybe : pipelineState.shadowAtlasFallbackTextureView;
141
+ // feat-20260625-spot-light-shadow-mapping M2 / w21 (D-1 fragment side +
142
+ // D-5): bind the real `spotShadowDepth` 2D atlas view (graph-owned) when
143
+ // spot shadows run this frame; otherwise the 1x1 depth fallback cleared to
144
+ // 1.0 (fully lit) — same `texture_depth_2d` shape as binding 3, so it
145
+ // satisfies the BGL without a dedicated spot fallback allocation. binding
146
+ // 9 always binds the real spotLightViewProj UBO (zeroed lanes are safe via
147
+ // the shadowAtlasTile >= 0 shader gate).
148
+ const graphSpotShadowView = graphTargets?.spotShadow;
149
+ const b8View =
150
+ graphSpotShadowView !== undefined
151
+ ? graphSpotShadowView
152
+ : pipelineState.shadowFallbackTextureView;
153
+ viewBindGroup = getOrCreateFromChain(
154
+ frameState.viewBindGroupCache,
155
+ [
156
+ pipelineState.viewUniformBuffer,
157
+ pipelineState.pointLightsBuffer,
158
+ pipelineState.spotLightsBuffer,
159
+ b3View,
160
+ shadowSampler,
161
+ b5View,
162
+ pipelineState.shadowParamsBuffer,
163
+ b8View,
164
+ pipelineState.pointsLinesViewBuffer ?? pipelineState.viewUniformBuffer,
165
+ ],
166
+ 'view-main',
167
+ () => {
168
+ const viewBindGroupResult = internals.device.createBindGroup({
169
+ label: 'pbr-view-bg',
170
+ layout: pipelineState.viewBindGroupLayout,
171
+ entries: [
172
+ {
173
+ binding: 0,
174
+ resource: {
175
+ kind: 'buffer',
176
+ value: { buffer: pipelineState.viewUniformBuffer, size: VIEW_UNIFORM_BYTES },
177
+ },
178
+ },
179
+ {
180
+ binding: 1,
181
+ resource: {
182
+ kind: 'buffer',
183
+ value: { buffer: pipelineState.pointLightsBuffer },
184
+ },
185
+ },
186
+ {
187
+ binding: 2,
188
+ resource: {
189
+ kind: 'buffer',
190
+ value: { buffer: pipelineState.spotLightsBuffer },
191
+ },
192
+ },
193
+ {
194
+ binding: 3,
195
+ resource: {
196
+ kind: 'textureView',
197
+ value: b3View,
198
+ },
199
+ },
200
+ {
201
+ binding: 4,
202
+ resource: {
203
+ kind: 'sampler',
204
+ value: shadowSampler,
205
+ },
206
+ },
207
+ // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1:
208
+ // cube_array shadow atlas view (real ShadowAtlas when point
209
+ // shadows are active; else 1x1x6 fallback).
210
+ {
211
+ binding: 5,
212
+ resource: {
213
+ kind: 'textureView',
214
+ value: b5View,
215
+ },
216
+ },
217
+ // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1:
218
+ // shadowParams UBO (`array<vec4<f32>, 4>` = 64 B). Lane N
219
+ // stores `(near, far, 1/(far-near), 0)` for the point light
220
+ // with shadowAtlasLayer === N. Updated per frame from
221
+ // `pointShadowSnapshots` below.
222
+ {
223
+ binding: 6,
224
+ resource: {
225
+ kind: 'buffer',
226
+ value: { buffer: pipelineState.shadowParamsBuffer },
227
+ },
228
+ },
229
+ // feat-20260613-csm-cascaded-shadow-maps M5 / w28 (rebased to
230
+ // binding 7 on 2026-06-13 to make room for point-shadow 5/6):
231
+ // forward shaders declare binding 7 in common.wgsl (shared
232
+ // view BGL) but never reference it; only shadow_caster.wgsl
233
+ // reads it. Host writes a stable singleton buffer so every
234
+ // forward bind group entry stays populated.
235
+ {
236
+ binding: 7,
237
+ resource: {
238
+ kind: 'buffer',
239
+ value: { buffer: pipelineState.shadowCasterCascadeBuffer },
240
+ },
241
+ },
242
+ // feat-20260625-spot-light-shadow-mapping M3 / w21 (D-5):
243
+ // spot shadow 2D atlas (real spotShadowDepth view when spot
244
+ // shadows run this frame, else the 1x1 depth fallback). Always-on.
245
+ {
246
+ binding: 8,
247
+ resource: {
248
+ kind: 'textureView',
249
+ value: b8View,
250
+ },
251
+ },
252
+ {
253
+ binding: 10,
254
+ resource: {
255
+ kind: 'buffer',
256
+ value: {
257
+ buffer: pipelineState.pointsLinesViewBuffer ?? pipelineState.viewUniformBuffer,
258
+ size: POINTS_LINES_VIEW_BYTES,
259
+ },
260
+ },
261
+ },
262
+ // feat-20260625-spot-light-shadow-mapping w25: the per-spot
263
+ // fragment-read lightViewProj matrices fold into the View UBO
264
+ // (binding 0, `view.spotLightViewProj`) — no standalone binding 9
265
+ // (WebGL2 fragment uniform-buffer budget). binding 10 is the
266
+ // dedicated vertex-only Points/Lines viewport UBO.
267
+ ],
268
+ });
269
+ if (!viewBindGroupResult.ok) throw viewBindGroupResult.error;
270
+ return viewBindGroupResult.value;
271
+ },
272
+ bindGroupCounts,
273
+ );
274
+ }
275
+
276
+ // M3 / w10 (D-3 hard constraint): use the inner `.buffer` as the
277
+ // WeakMap chain key so the cache tracks the underlying GPU buffer
278
+ // identity. The wrapper object's identity is stable across grow
279
+ // events; using the wrapper would defeat AC-07 cache invalidation.
280
+ meshBindGroup = getOrCreateFromChain(
281
+ frameState.meshBindGroupCache,
282
+ [pipelineState.meshStorageBuffer.buffer],
283
+ 'mesh',
284
+ () => {
285
+ // bug-20260610: WebGL2 fallback path needs the binding to cover the
286
+ // whole `array<Mesh, 128>` uniform buffer (14336 B) instead of a
287
+ // single dynamic-offset slot (112 B). `caps.storageBuffer === false`
288
+ // is the same proxy createRenderer uses to pick the uniform variant.
289
+ const meshBindSize = internals.device.caps.storageBuffer
290
+ ? MESH_SSBO_BYTES
291
+ : MESH_UBO_FULL_ARRAY_BYTES;
292
+ const meshBindGroupResult = internals.device.createBindGroup({
293
+ label: 'pbr-mesh-bg',
294
+ layout: pipelineState.meshBindGroupLayout,
295
+ entries: [
296
+ {
297
+ binding: 0,
298
+ resource: {
299
+ kind: 'buffer',
300
+ value: {
301
+ buffer: pipelineState.meshStorageBuffer.buffer,
302
+ offset: 0,
303
+ size: meshBindSize,
304
+ },
305
+ },
306
+ },
307
+ ],
308
+ });
309
+ if (!meshBindGroupResult.ok) throw meshBindGroupResult.error;
310
+ return meshBindGroupResult.value;
311
+ },
312
+ bindGroupCounts,
313
+ );
314
+
315
+ // feat-20260609-hdrp-cluster-fragment-ggx M4 / w19: when HDRP is active,
316
+ // build the unified group(2) BindGroup that carries the mesh SSBO at
317
+ // binding 0 + the 4 cluster buffers at bindings 3..6. The bindGroup
318
+ // shares the mesh SSBO with URP's `meshBindGroup` (same `meshStorageBuffer.buffer`
319
+ // + same per-entity stride), so the dynamic offset issued at
320
+ // `setBindGroup(2, ...)` covers binding 0 of either layout. Cached
321
+ // alongside `meshBindGroupCache` keyed on the mesh SSBO + cluster
322
+ // buffer identities; cache invalidates on a buffer-grow event the same
323
+ // way the mesh path does (handle id rotation).
324
+ if (frameState.isHdrpActive) {
325
+ const hdrpBuffers = getOrCreateHdrpBuffers(
326
+ internals,
327
+ frameState.installedPipelineConfig?.clusterGrid,
328
+ );
329
+ if (hdrpBuffers !== null) {
330
+ // D-3: buffer dimension uses the inner `.buffer` (same constraint
331
+ // as the mesh path) so a grow event rotates the chain key.
332
+ hdrpClusterBindGroup = getOrCreateFromChain(
333
+ frameState.meshBindGroupCache,
334
+ [
335
+ pipelineState.meshStorageBuffer.buffer,
336
+ hdrpBuffers.lightDataBuffer,
337
+ hdrpBuffers.clusterGridBuffer,
338
+ hdrpBuffers.lightIndexListBuffer,
339
+ hdrpBuffers.clusterUniformBuffer,
340
+ ],
341
+ 'hdrp-unified',
342
+ () => {
343
+ const bg = createHdrpUnifiedBindGroup(
344
+ internals,
345
+ hdrpBuffers,
346
+ pipelineState.meshStorageBuffer.buffer,
347
+ );
348
+ if (bg === null) {
349
+ throw new RhiError({
350
+ code: 'webgpu-runtime-error',
351
+ expected: 'HDRP unified BindGroup creation succeeds when HDRP is active',
352
+ hint: 'inspect prior errorRegistry events for createBindGroup failure detail',
353
+ });
354
+ }
355
+ return bg;
356
+ },
357
+ bindGroupCounts,
358
+ );
359
+ }
360
+ }
361
+ }
362
+ return { viewBindGroup, meshBindGroup, hdrpClusterBindGroup, hdrpClusterMembershipBindGroup };
363
+ }
364
+
365
+ /**
366
+ * feat-20260704 M3/w18: per-frame lighting preparation, extracted verbatim from
367
+ * `recordFrame`. (1) URP-only multi-light warn-once (directional / point / spot
368
+ * over `LIGHT_ARRAY_MAX_SLOTS`; HDRP gated off — 256 SSBO lights). (2) pin the
369
+ * point + spot shadow snapshot lists onto frameState for the URP shadow caster
370
+ * pass closures + lazy-allocate the point-shadow cube_array atlas on first
371
+ * non-empty frame (AC-09 zero-shadow zero-alloc). (3) destructure ExtractedLights
372
+ * into the directional-fallback `light` (zero-intensity Case C default), point /
373
+ * spot arrays, and totalLightCount.
374
+ *
375
+ * @internal
376
+ */
377
+ export function prepareFrameLighting(
378
+ internals: RenderSystemInternals,
379
+ frameState: RenderFrameState,
380
+ lights: ExtractedLights,
381
+ ): {
382
+ light: DirectionalLightSnapshot;
383
+ pointLights: ExtractedLights['point'];
384
+ spotLights: ExtractedLights['spot'];
385
+ totalLightCount: number;
386
+ } {
387
+ if (lights.directionalCount > 1) {
388
+ warnMultiLightDirectional(frameState, lights.directionalCount);
389
+ }
390
+ // feat-20260621-merge-directionallightshadow-into-directionallight M3 / m3-t2:
391
+ // the AC-04/AC-22 "shadow disabled by missing component" once-warn is gone.
392
+ // After merging DirectionalLightShadow into DirectionalLight there is no
393
+ // orphan-shadow / missing-companion configuration to warn about -- castShadow
394
+ // defaults true on the single component, so the warn condition can never
395
+ // arise. The error class + RuntimeErrorCode member have been removed in M4 (m4-t2).
396
+
397
+ // feat-20260608-cluster-lighting M6 / w23 (F-4 fix): URP-only multi-light
398
+ // warn. HDRP supports 256 punctual lights via SSBO; the 4-slot first-slice
399
+ // cap is irrelevant under HDRP, so gate on `!isHdrpActive` to silence noise.
400
+ // Sibling tweak-20260608-rhi-hdr-renderable-caps-and-warn-once (#320)
401
+ // extracted the warn into warnMultiLight{Point,Spot} helpers (warn-once
402
+ // dedup); we keep the helpers and add the HDRP gate on top.
403
+ if (!frameState.isHdrpActive) {
404
+ if (lights.point.length > LIGHT_ARRAY_MAX_SLOTS) {
405
+ warnMultiLightPoint(frameState, lights.point.length);
406
+ }
407
+ if (lights.spot.length > LIGHT_ARRAY_MAX_SLOTS) {
408
+ warnMultiLightSpot(frameState, lights.spot.length);
409
+ }
410
+ }
411
+
412
+ // feat-20260612-point-light-shadows-urp-hdrp M3 / T-M3-2 (plan-strategy §D-1):
413
+ // project lights.pointShadow onto frameState so the URP point shadow caster
414
+ // pass can read the snapshot list during graph execute. Lazy-allocate the
415
+ // cube_array atlas on first non-empty frame; zero-shadow scenes never
416
+ // touch the GPU here (AC-09). The snapshot list is stable for the
417
+ // duration of recordFrame; its count is part of the typed topology key.
418
+ frameState.pointShadowSnapshots = lights.pointShadow;
419
+ // feat-20260625-spot-light-shadow-mapping M2 / w9 (D-2): pin the spot
420
+ // snapshots for the spotShadowDepth caster pass closure. The spot atlas is
421
+ // a graph-owned typed target, not a runtime ShadowAtlas, so graph compilation
422
+ // owns the depth texture lifetime.
423
+ frameState.spotShadowSnapshots = lights.spot;
424
+ if (lights.pointShadow.length > 0) {
425
+ if (frameState.pointShadowAtlas === null) {
426
+ const firstSnap = lights.pointShadow[0];
427
+ const faceSize = firstSnap?.mapSize ?? 512;
428
+ frameState.pointShadowAtlas = new ShadowAtlas(internals.device, {
429
+ faceSize,
430
+ layers: 4,
431
+ });
432
+ }
433
+ try {
434
+ frameState.pointShadowAtlas.ensure();
435
+ } catch (e) {
436
+ if (
437
+ e instanceof PointShadowAtlasUninitializedError ||
438
+ e instanceof PointShadowAtlasBoundsViolationError
439
+ ) {
440
+ internals.errorRegistry.fire(e);
441
+ } else {
442
+ throw e;
443
+ }
444
+ }
445
+ }
446
+
447
+ // ExtractedLights three-arm consumption (R-10 preparation; M2 / w16):
448
+ //
449
+ // - lights.directional : feeds the View UBO at slot [16..23]
450
+ // (lightDir + lightColor; existing path).
451
+ // - lights.point[] : packed into pointLightsBuffer (std430).
452
+ // - lights.spot[] : packed into spotLightsBuffer (std430).
453
+ //
454
+ // Each variant carries the discriminant `kind` so the record-time packing
455
+ // call sites can run exhaustive switch (charter P2 + AC-03).
456
+ const directionalLight: DirectionalLightSnapshot | undefined = lights.directional;
457
+ const pointLights = lights.point;
458
+ const spotLights = lights.spot;
459
+
460
+ // Case C: 0 DirectionalLight = legitimate scene; the View UBO falls
461
+ // back to a zero-intensity directional payload so the shader's
462
+ // `view.lightDir * view.lightColor` term contributes nothing
463
+ // (physically-correct black under standard, untouched under unlit).
464
+ const light: DirectionalLightSnapshot = directionalLight ?? {
465
+ kind: 'directional' as const,
466
+ direction: vec3.create(0, -1, 0),
467
+ color: vec3.create(0, 0, 0),
468
+ intensity: 0,
469
+ };
470
+
471
+ const totalLightCount =
472
+ (directionalLight !== undefined ? 1 : 0) + pointLights.length + spotLights.length;
473
+
474
+ return { light, pointLights, spotLights, totalLightCount };
475
+ }
476
+
477
+ /**
478
+ * feat-20260704 M3/w18: per-frame full rewrite of the PointLight + SpotLight
479
+ * std430 storage buffers, extracted verbatim from `recordFrame`.
480
+ *
481
+ * feat-20260519-light-casters-point-spot-pbr M3 / w20 (D-S1 + D-S2 + D-S6):
482
+ * header (16 B count u32 + 12 B pad) at offset 0 + first-slice cap N=4 slots
483
+ * packed sequentially. The N>4 fail-fast upstream ensures the counts are <= 4
484
+ * when the listener registry consumed the structured error; the slice keeps
485
+ * the buffer write bounded even if downstream listeners ignore the RhiError
486
+ * (charter P9 graceful degradation: surplus entities dropped, frame records).
487
+ *
488
+ * @internal
489
+ */
490
+ export function writePointSpotLightBuffers(
491
+ internals: RenderSystemInternals,
492
+ pipelineState: PipelineState,
493
+ lights: ExtractedLights,
494
+ ): void {
495
+ const pointSlots =
496
+ lights.point.length <= LIGHT_ARRAY_MAX_SLOTS
497
+ ? lights.point
498
+ : lights.point.slice(0, LIGHT_ARRAY_MAX_SLOTS);
499
+ const pointHeader = packLightArrayHeader(pointSlots.length);
500
+ const pointHeaderUpload = internals.device.queue.writeBuffer(
501
+ pipelineState.pointLightsBuffer,
502
+ 0,
503
+ new Uint8Array(pointHeader),
504
+ );
505
+ if (!pointHeaderUpload.ok) throw pointHeaderUpload.error;
506
+ for (let i = 0; i < pointSlots.length; i++) {
507
+ const slot = pointSlots[i];
508
+ if (slot === undefined) continue;
509
+ const packed = packPointLight(slot);
510
+ const offset = LIGHT_ARRAY_HEADER_BYTES + i * POINT_LIGHT_STD430_BYTES;
511
+ const writeRes = internals.device.queue.writeBuffer(
512
+ pipelineState.pointLightsBuffer,
513
+ offset,
514
+ packed,
515
+ );
516
+ if (!writeRes.ok) throw writeRes.error;
517
+ }
518
+ const spotSlots =
519
+ lights.spot.length <= LIGHT_ARRAY_MAX_SLOTS
520
+ ? lights.spot
521
+ : lights.spot.slice(0, LIGHT_ARRAY_MAX_SLOTS);
522
+ const spotHeader = packLightArrayHeader(spotSlots.length);
523
+ const spotHeaderUpload = internals.device.queue.writeBuffer(
524
+ pipelineState.spotLightsBuffer,
525
+ 0,
526
+ new Uint8Array(spotHeader),
527
+ );
528
+ if (!spotHeaderUpload.ok) throw spotHeaderUpload.error;
529
+ for (let i = 0; i < spotSlots.length; i++) {
530
+ const slot = spotSlots[i];
531
+ if (slot === undefined) continue;
532
+ const packed = packSpotLight(slot);
533
+ const offset = LIGHT_ARRAY_HEADER_BYTES + i * SPOT_LIGHT_STD430_BYTES;
534
+ const writeRes = internals.device.queue.writeBuffer(
535
+ pipelineState.spotLightsBuffer,
536
+ offset,
537
+ packed,
538
+ );
539
+ if (!writeRes.ok) throw writeRes.error;
540
+ }
541
+ }
542
+
543
+ /**
544
+ * feat-20260704 M3/w18: write the point-shadow params UBO (bound at viewBg
545
+ * binding 6), extracted verbatim from `recordFrame`.
546
+ *
547
+ * feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: 4 lanes x vec4<f32>;
548
+ * lane[shadowAtlasLayer] = (near, far, 1/(far-near), 0). Lanes for non-shadow
549
+ * slots stay zero (the WGSL sample path is gated by PointLight.shadowAtlasLayer
550
+ * >= 0). Always writes the full 64 B so stale non-zero lanes from a previous
551
+ * frame's allocation cannot poison the current frame.
552
+ *
553
+ * @internal
554
+ */
555
+ export function writeShadowParamsBuffer(
556
+ internals: RenderSystemInternals,
557
+ frameState: RenderFrameState,
558
+ pipelineState: PipelineState,
559
+ ): void {
560
+ const SHADOW_PARAMS_LANE_COUNT = 4;
561
+ const SHADOW_PARAMS_FLOATS_PER_LANE = 4;
562
+ const shadowParamsArr = new Float32Array(
563
+ SHADOW_PARAMS_LANE_COUNT * SHADOW_PARAMS_FLOATS_PER_LANE,
564
+ );
565
+ for (let i = 0; i < frameState.pointShadowSnapshots.length; i++) {
566
+ const ps = frameState.pointShadowSnapshots[i];
567
+ if (ps === undefined) continue;
568
+ const layer = ps.shadowAtlasLayer;
569
+ if (layer < 0 || layer >= SHADOW_PARAMS_LANE_COUNT) continue;
570
+ const base = layer * SHADOW_PARAMS_FLOATS_PER_LANE;
571
+ const near = ps.nearPlane;
572
+ const far = ps.farPlane;
573
+ const invSpan = far > near ? 1 / (far - near) : 0;
574
+ shadowParamsArr[base] = near;
575
+ shadowParamsArr[base + 1] = far;
576
+ shadowParamsArr[base + 2] = invSpan;
577
+ shadowParamsArr[base + 3] = 0;
578
+ }
579
+ const shadowParamsWriteRes = internals.device.queue.writeBuffer(
580
+ pipelineState.shadowParamsBuffer,
581
+ 0,
582
+ shadowParamsArr,
583
+ );
584
+ if (!shadowParamsWriteRes.ok) {
585
+ internals.errorRegistry.fire(shadowParamsWriteRes.error);
586
+ }
587
+ }
588
+
589
+ /**
590
+ * feat-20260704 M3/w18: zero-light standard-material once-warn, extracted
591
+ * verbatim from `recordFrame`.
592
+ *
593
+ * feat-20260520-skylight-ibl-cubemap M4 / t27 (AC-10): fires once per
594
+ * RenderSystem lifetime when the 0-light three-condition conjunction holds — no
595
+ * Skylight, 0 direct light (totalLightCount === 0), AND at least one builtin
596
+ * standard/PBR material (which renders black with no light). Custom shaders
597
+ * own their lighting contract and cannot be classified by this generic
598
+ * diagnostic. Suppressed under NODE_ENV=production.
599
+ *
600
+ * @internal
601
+ */
602
+ export function warnZeroLightStandard(
603
+ frameState: RenderFrameState,
604
+ renderables: readonly RenderableSnapshot[],
605
+ skylight: SkylightSnapshot | undefined,
606
+ totalLightCount: number,
607
+ ): void {
608
+ const hasStandardMaterial = renderables.some((r) => isLitMaterialSnapshot(r.material));
609
+ if (
610
+ skylight === undefined &&
611
+ totalLightCount === 0 &&
612
+ hasStandardMaterial &&
613
+ !frameState.warnedZeroLightStandard
614
+ ) {
615
+ frameState.warnedZeroLightStandard = true;
616
+ const env = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;
617
+ if (env?.env?.NODE_ENV !== 'production') {
618
+ console.warn(
619
+ '[forgeax] standard material renders black with 0 lights of every type (no Skylight, and directional + point + spot all empty); spawn at least one light (Skylight, DirectionalLight, PointLight, or SpotLight) or switch material to an unlit shader (Materials.unlit(...)). See AGENTS.md section Breaking changes 2026-05-19.',
620
+ );
621
+ }
622
+ }
623
+ }
624
+
625
+ /**
626
+ * feat-20260704 M3/w18: HDRP per-frame CPU cluster binning + light-data /
627
+ * cluster-grid / light-index-list / cluster-uniform / SSAO uniform buffer
628
+ * uploads. Extracted verbatim from `recordFrame`. Runs only when the HDRP
629
+ * pipeline is active. A zero-punctual frame explicitly clears the persistent
630
+ * cluster buffers so stale membership cannot leak across frames; direct and
631
+ * non-clustered paths remain untouched.
632
+ *
633
+ * feat-20260608-cluster-lighting M5 / w21 + M6 / w23 + r2 fix-up: fail-soft
634
+ * semantics preserved verbatim — index-list-overflow and light-budget-exceeded
635
+ * fire once per frame (via `frameState.hdrpOncePerFrameFired`) and continue
636
+ * rendering.
637
+ *
638
+ * @internal
639
+ */
640
+ export function writeHdrpClusterAndSsaoBuffers(
641
+ internals: RenderSystemInternals,
642
+ frameState: RenderFrameState,
643
+ camera: CameraSnapshot,
644
+ pointLights: ExtractedLights['point'],
645
+ spotLights: ExtractedLights['spot'],
646
+ profilePhase?: RecordProfileRunner,
647
+ useGpuMembership = false,
648
+ membershipBindGroupLayout: BindGroupLayout | null = null,
649
+ ): void {
650
+ const hdrpLightCount = pointLights.length + spotLights.length;
651
+ if (!frameState.isHdrpActive) return;
652
+ if (hdrpLightCount === 0) {
653
+ const grid = frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
654
+ const hdrpBuffers = getOrCreateHdrpBuffers(internals, grid);
655
+ if (hdrpBuffers === null) return;
656
+ const lightCapacity = hdrpBuffers.storageBuffer ? 256 : HDRP_UNIFORM_LIGHT_CAPACITY;
657
+ const clusterSsaoConfig = frameState.installedPipelineConfig?.ssao;
658
+ const clusterSsaoIntensity =
659
+ clusterSsaoConfig !== undefined && clusterSsaoConfig.enabled === true
660
+ ? (clusterSsaoConfig.intensity ?? 1.0)
661
+ : 0;
662
+ const clusterUniformPayload = packClusterUniform(
663
+ grid,
664
+ camera.near,
665
+ camera.far,
666
+ clusterSsaoIntensity,
667
+ 0,
668
+ lightCapacity,
669
+ );
670
+ const clusterUniformUpload = internals.device.queue.writeBuffer(
671
+ hdrpBuffers.clusterUniformBuffer,
672
+ 0,
673
+ new Uint8Array(clusterUniformPayload),
674
+ );
675
+ if (!clusterUniformUpload.ok) internals.errorRegistry.fire(clusterUniformUpload.error);
676
+ const clusterGridClear = internals.device.queue.writeBuffer(
677
+ hdrpBuffers.clusterGridBuffer,
678
+ 0,
679
+ new Uint8Array(hdrpBuffers.clusterGridBytes),
680
+ );
681
+ if (!clusterGridClear.ok) internals.errorRegistry.fire(clusterGridClear.error);
682
+ const lightIndexListClear = internals.device.queue.writeBuffer(
683
+ hdrpBuffers.lightIndexListBuffer,
684
+ 0,
685
+ new Uint8Array(hdrpBuffers.lightIndexListBytes),
686
+ );
687
+ if (!lightIndexListClear.ok) internals.errorRegistry.fire(lightIndexListClear.error);
688
+ return;
689
+ }
690
+ const HDRP_LIGHT_BUDGET = 256;
691
+ let effectivePointLights = pointLights;
692
+ let effectiveSpotLights = spotLights;
693
+ if (hdrpLightCount > HDRP_LIGHT_BUDGET) {
694
+ if (!frameState.hdrpOncePerFrameFired.has('hdrp-light-budget-exceeded')) {
695
+ frameState.hdrpOncePerFrameFired.add('hdrp-light-budget-exceeded');
696
+ internals.errorRegistry.fire(
697
+ new HdrpLightBudgetExceededError(hdrpLightCount, HDRP_LIGHT_BUDGET),
698
+ );
699
+ }
700
+ if (pointLights.length >= HDRP_LIGHT_BUDGET) {
701
+ effectivePointLights = pointLights.slice(0, HDRP_LIGHT_BUDGET);
702
+ effectiveSpotLights = [];
703
+ } else {
704
+ effectivePointLights = pointLights;
705
+ effectiveSpotLights = spotLights.slice(0, HDRP_LIGHT_BUDGET - pointLights.length);
706
+ }
707
+ }
708
+ const effectiveLightCount = effectivePointLights.length + effectiveSpotLights.length;
709
+ const configuredClusterGrid =
710
+ frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
711
+ let gpuMembership = useGpuMembership && membershipBindGroupLayout !== null;
712
+ if (
713
+ gpuMembership &&
714
+ membershipBindGroupLayout !== null &&
715
+ frameState.hdrpClusterMembershipBindGroup === null
716
+ ) {
717
+ const hdrpBuffers = getOrCreateHdrpBuffers(internals, configuredClusterGrid);
718
+ if (hdrpBuffers !== null) {
719
+ frameState.hdrpClusterMembershipBindGroup = createHdrpClusterMembershipBindGroup(
720
+ internals,
721
+ hdrpBuffers,
722
+ membershipBindGroupLayout,
723
+ );
724
+ }
725
+ gpuMembership = frameState.hdrpClusterMembershipBindGroup !== null;
726
+ }
727
+
728
+ const { clusterGrid, gridX, gridY, gridZ, clusterGridBuf, lightIndexListBuf, lightIndexCount } =
729
+ runHdrpClusterProfilePhase(profilePhase, 'record/scene-state/hdrp-cluster/binner', () => {
730
+ const binnerProfile: ClusterBinProfileRunner | undefined =
731
+ profilePhase === undefined
732
+ ? undefined
733
+ : <T>(phase: ClusterBinProfilePhase, action: () => T): T =>
734
+ runHdrpClusterProfilePhase(
735
+ profilePhase,
736
+ `record/scene-state/hdrp-cluster/binner/${phase}` as RenderHdrpClusterPhase,
737
+ action,
738
+ );
739
+ const {
740
+ hdrpLights,
741
+ clusterGrid,
742
+ gridX,
743
+ gridY,
744
+ gridZ,
745
+ clusterGridBuf,
746
+ lightIndexListBuf,
747
+ projMatrix,
748
+ viewMatrix,
749
+ } = runHdrpClusterProfilePhase(
750
+ profilePhase,
751
+ 'record/scene-state/hdrp-cluster/binner/input-preparation',
752
+ () => {
753
+ const hdrpLights: Array<{ position: Vec3; range: number }> = [];
754
+ for (const pl of effectivePointLights) {
755
+ const range =
756
+ Number.isFinite(pl.invRangeSquared) && pl.invRangeSquared > 0
757
+ ? Math.sqrt(1 / pl.invRangeSquared)
758
+ : 1000;
759
+ hdrpLights.push({ position: pl.position, range });
760
+ }
761
+ for (const sl of effectiveSpotLights) {
762
+ const range =
763
+ Number.isFinite(sl.invRangeSquared) && sl.invRangeSquared > 0
764
+ ? Math.sqrt(1 / sl.invRangeSquared)
765
+ : 1000;
766
+ hdrpLights.push({ position: sl.position, range });
767
+ }
768
+
769
+ const clusterGrid =
770
+ frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
771
+ const gridX = clusterGrid.x;
772
+ const gridY = clusterGrid.y;
773
+ const gridZ = clusterGrid.z;
774
+ const clusterCount = gridX * gridY * gridZ;
775
+
776
+ const projMatrix = computeProjectionMatrix(camera);
777
+ const viewMatrix = computeViewMatrix(camera);
778
+
779
+ const clusterGridBuf =
780
+ frameState.hdrpClusterGridScratch === null ||
781
+ frameState.hdrpClusterGridScratch.length < clusterCount * 2
782
+ ? new Uint32Array(clusterCount * 2)
783
+ : frameState.hdrpClusterGridScratch;
784
+ frameState.hdrpClusterGridScratch = clusterGridBuf;
785
+ const lightIndexListBuf =
786
+ frameState.hdrpLightIndexListScratch === null ||
787
+ frameState.hdrpLightIndexListScratch.length < LIGHT_INDEX_LIST_CAPACITY
788
+ ? new Uint32Array(LIGHT_INDEX_LIST_CAPACITY)
789
+ : frameState.hdrpLightIndexListScratch;
790
+ frameState.hdrpLightIndexListScratch = lightIndexListBuf;
791
+
792
+ return {
793
+ hdrpLights,
794
+ clusterGrid,
795
+ gridX,
796
+ gridY,
797
+ gridZ,
798
+ clusterGridBuf,
799
+ lightIndexListBuf,
800
+ projMatrix,
801
+ viewMatrix,
802
+ };
803
+ },
804
+ );
805
+
806
+ const binResult = runHdrpClusterProfilePhase(
807
+ profilePhase,
808
+ 'record/scene-state/hdrp-cluster/binner/bin-core',
809
+ () =>
810
+ bin(
811
+ hdrpLights,
812
+ viewMatrix,
813
+ projMatrix,
814
+ { x: gridX, y: gridY, z: gridZ },
815
+ camera.near,
816
+ camera.far,
817
+ clusterGridBuf,
818
+ lightIndexListBuf,
819
+ LIGHT_INDEX_LIST_CAPACITY,
820
+ frameState.hdrpClusterBinScratch,
821
+ binnerProfile,
822
+ { writeMembership: !gpuMembership },
823
+ ),
824
+ );
825
+
826
+ if (!binResult.ok && !frameState.hdrpOncePerFrameFired.has('hdrp-index-list-overflow')) {
827
+ frameState.hdrpOncePerFrameFired.add('hdrp-index-list-overflow');
828
+ const detail = binResult.error.detail;
829
+ internals.errorRegistry.fire(
830
+ new HdrpIndexListOverflowError(detail.actual, detail.capacity),
831
+ );
832
+ }
833
+
834
+ // Falsify injection point: FORGEAX_HDRP_FALSIFY_CLUSTER_GRID_ZERO
835
+ // zeroes the cluster_grid buffer so every fragment culls every light.
836
+ // Used by hello-hdrp-lighting smoke FALSIFY=cluster-grid-zero to
837
+ // prove the smoke has discriminability (must FAIL vs baseline).
838
+ // Read process via globalThis to keep this file @types/node-free.
839
+ const envFalsify = (globalThis as { process?: { env?: Record<string, string | undefined> } })
840
+ .process?.env;
841
+ if (envFalsify?.FORGEAX_HDRP_FALSIFY_CLUSTER_GRID_ZERO) {
842
+ clusterGridBuf.fill(0);
843
+ }
844
+
845
+ return {
846
+ clusterGrid,
847
+ gridX,
848
+ gridY,
849
+ gridZ,
850
+ clusterGridBuf,
851
+ lightIndexListBuf,
852
+ lightIndexCount: binResult.ok ? binResult.value : 0,
853
+ };
854
+ });
855
+
856
+ const hdrpPayload = runHdrpClusterProfilePhase(
857
+ profilePhase,
858
+ 'record/scene-state/hdrp-cluster/payload-packing',
859
+ () => {
860
+ const hdrpBuffers = getOrCreateHdrpBuffers(internals, clusterGrid);
861
+ if (hdrpBuffers === null) return null;
862
+
863
+ const lightCapacity = hdrpBuffers.storageBuffer ? 256 : HDRP_UNIFORM_LIGHT_CAPACITY;
864
+ const lightDataPayload = new Float32Array(lightCapacity * 16);
865
+ let slotIdx = 0;
866
+ for (const pl of effectivePointLights) {
867
+ if (slotIdx >= lightCapacity) break;
868
+ // feat-20260612-point-light-shadows-urp-hdrp M4 / T-M4-4
869
+ // (plan-strategy §D-8): thread the optional shadow info through
870
+ // packLightSlot. PointLightSnapshot.shadowAtlasLayer is set by
871
+ // extract's join pass when the entity carries PointLightShadow;
872
+ // sentinel -1 means no shadow (unshadowed evalPoint path).
873
+ const layer = pl.shadowAtlasLayer;
874
+ const packed =
875
+ layer !== undefined &&
876
+ layer >= 0 &&
877
+ pl.shadowNear !== undefined &&
878
+ pl.shadowFar !== undefined
879
+ ? packLightSlot(pl, {
880
+ shadowAtlasLayer: layer,
881
+ near: pl.shadowNear,
882
+ far: pl.shadowFar,
883
+ })
884
+ : packLightSlot(pl);
885
+ lightDataPayload.set(packed, slotIdx * 16);
886
+ slotIdx += 1;
887
+ }
888
+ for (const sl of effectiveSpotLights) {
889
+ if (slotIdx >= lightCapacity) break;
890
+ const packed = packLightSlot(sl);
891
+ lightDataPayload.set(packed, slotIdx * 16);
892
+ slotIdx += 1;
893
+ }
894
+
895
+ // scope-amend-webgl2-ubo: SSAO intensity is folded into the
896
+ // cluster_uniform .w lane (formerly pad), removing the dedicated
897
+ // @binding(9) UBO that pushed fragment-stage UBO count past
898
+ // WebGL2's max_uniform_buffers_per_shader_stage=11. Disabled-SSAO
899
+ // path writes 0 so `mix(1.0, ssao*ao, 0.0) = 1.0` in the lighting
900
+ // shader (no PSO recompile across enable/disable).
901
+ const clusterSsaoConfig = frameState.installedPipelineConfig?.ssao;
902
+ const clusterSsaoIntensity =
903
+ clusterSsaoConfig !== undefined && clusterSsaoConfig.enabled === true
904
+ ? (clusterSsaoConfig.intensity ?? 1.0)
905
+ : 0;
906
+ const clusterUniformPayload = packClusterUniform(
907
+ { x: gridX, y: gridY, z: gridZ },
908
+ camera.near,
909
+ camera.far,
910
+ clusterSsaoIntensity,
911
+ Math.min(effectivePointLights.length + effectiveSpotLights.length, lightCapacity),
912
+ lightCapacity,
913
+ );
914
+
915
+ return {
916
+ hdrpBuffers,
917
+ lightDataUploadPayload: lightDataPayload.subarray(0, slotIdx * 16),
918
+ clusterUniformPayload: new Uint8Array(clusterUniformPayload),
919
+ };
920
+ },
921
+ );
922
+
923
+ runHdrpClusterProfilePhase(profilePhase, 'record/scene-state/hdrp-cluster/buffer-upload', () => {
924
+ if (hdrpPayload !== null) {
925
+ const { hdrpBuffers, lightDataUploadPayload, clusterUniformPayload } = hdrpPayload;
926
+ const lightDataUpload = internals.device.queue.writeBuffer(
927
+ hdrpBuffers.lightDataBuffer,
928
+ 0,
929
+ lightDataUploadPayload,
930
+ );
931
+ if (!lightDataUpload.ok) internals.errorRegistry.fire(lightDataUpload.error);
932
+
933
+ if (hdrpBuffers.storageBuffer) {
934
+ if (gpuMembership) {
935
+ const lightBoundsUpload = internals.device.queue.writeBuffer(
936
+ hdrpBuffers.lightBoundsBuffer,
937
+ 0,
938
+ frameState.hdrpClusterBinScratch.lightBounds.subarray(0, effectiveLightCount * 6),
939
+ );
940
+ if (!lightBoundsUpload.ok) internals.errorRegistry.fire(lightBoundsUpload.error);
941
+ }
942
+ const clusterGridUpload = internals.device.queue.writeBuffer(
943
+ hdrpBuffers.clusterGridBuffer,
944
+ 0,
945
+ clusterGridBuf.subarray(0, gridX * gridY * gridZ * 2),
946
+ );
947
+ if (!clusterGridUpload.ok) internals.errorRegistry.fire(clusterGridUpload.error);
948
+
949
+ if (!gpuMembership && lightIndexCount > 0) {
950
+ const lightIndexListUpload = internals.device.queue.writeBuffer(
951
+ hdrpBuffers.lightIndexListBuffer,
952
+ 0,
953
+ lightIndexListBuf.subarray(0, lightIndexCount),
954
+ );
955
+ if (!lightIndexListUpload.ok) internals.errorRegistry.fire(lightIndexListUpload.error);
956
+ }
957
+ }
958
+
959
+ const clusterUniformUpload = internals.device.queue.writeBuffer(
960
+ hdrpBuffers.clusterUniformBuffer,
961
+ 0,
962
+ clusterUniformPayload,
963
+ );
964
+ if (!clusterUniformUpload.ok) internals.errorRegistry.fire(clusterUniformUpload.error);
965
+ }
966
+
967
+ // ── feat-20260612-hdrp-ssao M1 / w6 + M7 / w33 ───────────────
968
+ // Per-frame SSAO uniform write (plan-strategy D-1 + D-C):
969
+ // view + projection + inverseProjection at offsets 0/64/128 +
970
+ // intensityPad (vec4 — x=intensity, y=radius, z=bias) at offset 192;
971
+ // total 256 B (matches host SSAO_UNIFORM_BYTES + WGSL struct).
972
+ // Single writeBuffer covers all four fields so one queue entry
973
+ // updates the entire UBO.
974
+ // Separate from View UBO (592 B invariant); does not affect
975
+ // material PSO bytecode.
976
+ //
977
+ // Writes when HDRP is active; config.ssao?.enabled guard comes in
978
+ // M4 / w19 after the config.ssao type narrowing is added.
979
+ {
980
+ const ssaoBufs = getOrCreateSsaoBuffers(internals);
981
+ if (ssaoBufs !== null) {
982
+ const sProj = computeProjectionMatrix(camera);
983
+ const sView = computeViewMatrix(camera);
984
+ // inverseProjection = inverse(projection): NDC -> view-space.
985
+ const invProjOnly = mat4.create();
986
+ mat4.invert(invProjOnly, sProj);
987
+
988
+ // Float32Array of 64 (256 B): 3 mat4 (48) + intensityPad vec4 (4)
989
+ // + 12 trailing padding floats. We only fill the declared region.
990
+ const ssaoUniformPayload = new Float32Array(64);
991
+ ssaoUniformPayload.set(sView, 0);
992
+ ssaoUniformPayload.set(sProj, 16);
993
+ ssaoUniformPayload.set(invProjOnly, 32);
994
+ // intensityPad carries the same resolved values as the graph SSAO
995
+ // calc pass; this early write keeps the shared UBO valid before the
996
+ // typed fullscreen pass executes.
997
+ const ssaoConfig = frameState.installedPipelineConfig?.ssao;
998
+ const parameters = getSsaoParameters(
999
+ ssaoConfig !== undefined && ssaoConfig.enabled === true ? ssaoConfig : undefined,
1000
+ );
1001
+ ssaoUniformPayload[48] = parameters.intensity;
1002
+ ssaoUniformPayload[49] = parameters.radius;
1003
+ ssaoUniformPayload[50] = parameters.bias;
1004
+
1005
+ const ssaoUniformRes = internals.device.queue.writeBuffer(
1006
+ ssaoBufs.uniformBuffer,
1007
+ 0,
1008
+ ssaoUniformPayload,
1009
+ );
1010
+ if (!ssaoUniformRes.ok) internals.errorRegistry.fire(ssaoUniformRes.error);
1011
+ }
1012
+ }
1013
+ });
1014
+ }
1015
+
1016
+ /**
1017
+ * feat-20260704 M3/w18: resolve `tonemapActive` + `skyboxActive` for this
1018
+ * frame, extracted verbatim from `recordFrame`.
1019
+ *
1020
+ * feat-20260519-tonemap-reinhard-mvp: tonemap is active when the camera carries
1021
+ * `tonemap !== 'none'` (routes geometry into the HDR offscreen target + a
1022
+ * fullscreen tonemap pass). feat-20260531-skybox-env-background M2 / w9: skybox
1023
+ * is active only when a SkyboxBackground entity is present AND tonemap is active
1024
+ * (hdrColor is only allocated on the tonemap path). M3 / w20: once-warn when
1025
+ * tonemap is 'none' but a skybox exists (config issue, not resource-timing —
1026
+ * no structured error). M3 / w18: skybox degrades to clear-colour for a frame
1027
+ * while its cubemap view is not yet resident (lazy equirect projection pending
1028
+ * / failed; the lazy trigger owns the fire-once-on-failed error).
1029
+ *
1030
+ * @internal
1031
+ */
1032
+ export function resolveSkyboxActive(
1033
+ internals: RenderSystemInternals,
1034
+ frameState: RenderFrameState,
1035
+ camera: CameraSnapshot,
1036
+ skybox: SkyboxSnapshot | undefined,
1037
+ ): { tonemapActive: boolean; skyboxActive: boolean } {
1038
+ const tonemapActive = camera.tonemap !== 'none';
1039
+ let skyboxActive = skybox !== undefined && tonemapActive;
1040
+ // feat-20260531-skybox-env-background M3 / w20: once-warn when camera
1041
+ // tonemap is 'none' but a SkyboxBackground entity exists. The skybox
1042
+ // pass requires the HDR render target allocated by the tonemap path;
1043
+ // without it the skybox is skipped for this frame. This is a config
1044
+ // issue, not a resource-timing issue -- don't fire a structured error
1045
+ // (plan-strategy D-2 NOTE, charter P3 non-silent).
1046
+ if (skybox !== undefined && !tonemapActive && !frameState.warnedSkyboxTonemapNone) {
1047
+ frameState.warnedSkyboxTonemapNone = true;
1048
+ console.warn(
1049
+ '[forgeax] SkyboxBackground: skybox requires tonemap active (camera.tonemap !== "none") to write HDR target. The skybox pass will be skipped for this frame.',
1050
+ );
1051
+ }
1052
+ // feat-20260531-skybox-env-background M3 / w18: degradation when cubemap
1053
+ // GPU view is not ready. getCubemapGpuView returns undefined if the
1054
+ // equirect-to-cube upload has not completed yet.
1055
+ if (skybox !== undefined && tonemapActive) {
1056
+ const cubemapView = internals.gpuStore.getCubemapGpuView(
1057
+ toShared<'EquirectAsset'>(skybox.equirectHandle),
1058
+ );
1059
+ if (cubemapView === undefined) {
1060
+ // The skybox reuses the Skylight's equirect handle; the cubemap
1061
+ // projection is driven lazily by the single trigger in `driveLazy
1062
+ // EquirectProjection` above (it owns the fire-and-forget launch AND the
1063
+ // fire-once-on-failed structured error). While the projection is
1064
+ // pending or has failed the cube view is not resident, so the skybox
1065
+ // pass degrades to the clear-colour background for this frame
1066
+ // (charter P3: it activates once the shared projection flips to
1067
+ // 'ready'). No error is fired here -- 'pending' is a normal transition
1068
+ // (firing per frame would flood the channel), and 'failed' is reported
1069
+ // once by the lazy trigger. (feat-20260630 M3 / w18.)
1070
+ skyboxActive = false;
1071
+ }
1072
+ }
1073
+ return { tonemapActive, skyboxActive };
1074
+ }