@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,1137 @@
1
+ // pbr-pipeline.ts -- PBR / unlit pipeline-layout factories (M4 round-4 D-5).
2
+ //
3
+ // Anchors:
4
+ // - plan-strategy D-5 (round-4 REVISED): the PBR pipeline keeps a 4-slot
5
+ // pipeline layout `[view, material, mesh-array, instances]`. The
6
+ // material BGL grows from the derived user region by appending the 7
7
+ // Skylight resources via `mergeSkylightIntoMaterialBgl`. The
8
+ // unlit pipeline keeps its 7-entry material BGL (no Skylight binding
9
+ // 7..13 contamination) so unlit demos don't carry IBL state.
10
+ // - charter P4: same pipeline layout shape drives Skylight present +
11
+ // absent paths -- AI users do not branch on Skylight existence.
12
+ // - feat-20260520-skylight-ibl-cubemap M4 / t59 (round-4): the
13
+ // pipeline-layout construction migrates out of `createRenderer.ts`
14
+ // into this dedicated module so M4 round-4 tests can mock the device
15
+ // and inspect the captured descriptors without standing up the full
16
+ // createRenderer + asset registry + manifest stack.
17
+ //
18
+ // The factory functions return both the captured handles AND the
19
+ // `bindGroupLayouts` array passed to `device.createPipelineLayout`. Callers
20
+ // (the createRenderer step that wires the standard + standard-HDR
21
+ // `RenderPipeline` instances) consume the result by name; tests inspect
22
+ // `device.createBindGroupLayout.mock.calls` to verify shape (t57).
23
+
24
+ import type {
25
+ BindGroup,
26
+ BindGroupEntry,
27
+ BindGroupLayout,
28
+ BindGroupLayoutDescriptor,
29
+ Buffer,
30
+ PipelineLayout,
31
+ RhiDevice,
32
+ Sampler,
33
+ TextureView,
34
+ } from '@forgeax/engine-rhi';
35
+ import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA, type ShaderCatalog } from '@forgeax/engine-shader';
36
+ import { derive, type ParamSchemaEntry } from '@forgeax/engine-types';
37
+ import { GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX } from './gpu-stage';
38
+ import type { PipelineSpec } from './pipeline-spec-types';
39
+
40
+ // Stub PipelineSpec used by the BGL-only call sites. The dispatcher only reads
41
+ // `spec.shader` when a registry is supplied for reflection; for caps-driven
42
+ // kinds (pbr-view / pbr-mesh-array / pbr-instances / pbr-skin-mesh-array) and
43
+ // for the no-registry material path the spec content is unused. A single
44
+ // frozen stub keeps the call sites readable and is allocation-free.
45
+ //
46
+ // D-13 round-2 dispatcher landing — see plan-decisions D-13.
47
+ const BGL_ONLY_SPEC_STUB: PipelineSpec = Object.freeze({
48
+ shader: { id: '', passKind: 'forward', variantSet: undefined },
49
+ attachments: { colorFormats: [], depthFormat: undefined, sampleCount: 1 },
50
+ geometry: { topology: 'triangle-list', vertexLayout: {} },
51
+ renderState: undefined,
52
+ }) as PipelineSpec;
53
+
54
+ // ─── Device owner ───────────────────────────────────────────────────────────
55
+
56
+ /** The PBR layout builder consumes only the two creation methods it owns. */
57
+ export type PbrPipelineDevice = Pick<RhiDevice, 'createBindGroupLayout' | 'createPipelineLayout'>;
58
+
59
+ // ─── Result shape ───────────────────────────────────────────────────────────
60
+
61
+ export interface PbrPipelineLayoutBundle {
62
+ /** Pipeline layout passed to `createRenderPipeline({ layout })`. */
63
+ readonly pipelineLayout: PipelineLayout;
64
+ /** view BindGroupLayout (slot 0). */
65
+ readonly viewBgl: BindGroupLayout;
66
+ /**
67
+ * PBR material BindGroupLayout (slot 1) -- derived user-region entries plus
68
+ * Skylight and lightmap injection.
69
+ */
70
+ readonly materialBgl: BindGroupLayout;
71
+ /** Per-entity mesh BindGroupLayout (slot 2). */
72
+ readonly meshArrayBgl: BindGroupLayout;
73
+ /** Per-instance storage BindGroupLayout (slot 3). */
74
+ readonly instancesBgl: BindGroupLayout;
75
+ /**
76
+ * Same 4 layouts in slot order. Useful for assertion sites that check the
77
+ * pipeline-layout `bindGroupLayouts` array shape (t57 (a) + (d)).
78
+ */
79
+ readonly bindGroupLayouts: readonly [
80
+ BindGroupLayout,
81
+ BindGroupLayout,
82
+ BindGroupLayout,
83
+ BindGroupLayout,
84
+ ];
85
+ }
86
+
87
+ // ─── Base entries (round-4 SSOT) ────────────────────────────────────────────
88
+
89
+ /**
90
+ * The built-in standard-PBR material paramSchema's texture/user-region shape,
91
+ * used as the fallback when the material BGL is built without a registry
92
+ * (the caps-driven `buildPbrPipelineLayouts` seam). Declares the 3 standard
93
+ * user-region textures + a numeric UBO run; `derive()` collapses the numerics
94
+ * into binding 0 and emits sampler/texture pairs at 1..6 — byte-equivalent to
95
+ * the legacy fixed base-7. The shared PBR parameter contract comes from the
96
+ * shader package; this module only derives the GPU layout.
97
+ */
98
+ /**
99
+ * Build the PBR material BGL **user-region** from a paramSchema via the
100
+ * `derive()` SSOT (D-1). The user-region is binding 0 (the run-merged material
101
+ * UBO) followed by one sampler/texture pair per declared texture. Engine
102
+ * injection (IBL + lightmap) is appended AFTER this region by the caller via
103
+ * `appendInjection`, with start binding = `userRegion.length` — so a 4-texture
104
+ * custom schema (e.g. parallax + heightTexture) shifts the injection region by
105
+ * one sampler/texture pair automatically.
106
+ *
107
+ * The built-in `default-standard-pbr` paramSchema declares exactly 4 textures,
108
+ * so this derives to binding 0 UBO + 4 pairs = 9 entries. Injection is appended
109
+ * after that derived region.
110
+ *
111
+ * One material-UBO convention is layered on top of the pure `derive()` output:
112
+ * binding 0 is patched to `{ type: 'uniform', hasDynamicOffset: true }` with
113
+ * `VERTEX | FRAGMENT` visibility. The material UBO is bound with a per-submesh
114
+ * dynamic offset (`render-system-record.ts setBindGroup(1, bg, [offset])`) and
115
+ * the vertex stage reads material params, so this is required for GPU
116
+ * validation. `derive()` stays FRAGMENT-only / no-dynamic-offset for its other
117
+ * consumers (it is the generic SSOT, not the material-UBO authority).
118
+ *
119
+ * @param paramSchema - the material shader's paramSchema (defaults to the
120
+ * built-in standard-PBR shape when omitted, for the caps-driven seam).
121
+ */
122
+ export function buildPbrMaterialUserRegionEntries(
123
+ paramSchema: readonly ParamSchemaEntry[] = DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
124
+ ): GPUBindGroupLayoutEntry[] {
125
+ const derived = derive(paramSchema);
126
+ // Project the engine-owned entry shape into the DOM WebGPU descriptor. Omit
127
+ // absent optional members so exactOptionalPropertyTypes remains true at the
128
+ // boundary instead of leaking an `undefined` property into the descriptor.
129
+ const entries = derived.bglEntries.map(
130
+ (entry): GPUBindGroupLayoutEntry => ({
131
+ binding: entry.binding,
132
+ visibility: entry.visibility,
133
+ ...(entry.buffer === undefined ? {} : { buffer: entry.buffer }),
134
+ ...(entry.sampler === undefined ? {} : { sampler: entry.sampler }),
135
+ ...(entry.texture === undefined ? {} : { texture: entry.texture }),
136
+ ...(entry.storageTexture === undefined ? {} : { storageTexture: entry.storageTexture }),
137
+ }),
138
+ );
139
+ // Patch binding 0 (the material UBO) to the dynamic-offset, vertex-visible
140
+ // material-UBO contract. derive() emits binding 0 as the first numeric run's
141
+ // merged UBO; an empty schema has no binding-0 UBO and needs no patch.
142
+ const ubo = entries[0];
143
+ if (ubo !== undefined && ubo.binding === 0 && ubo.buffer !== undefined) {
144
+ entries[0] = {
145
+ binding: 0,
146
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
147
+ buffer: { type: 'uniform', hasDynamicOffset: true },
148
+ };
149
+ }
150
+ return entries;
151
+ }
152
+
153
+ // ─── appendInjection — generic engine-injection BGL appender (M3 / w15) ──────
154
+ //
155
+ // Decision anchors (plan-strategy §2):
156
+ // - D-6 appendInjection(bgl, kind) replaces the previous hardcoded
157
+ // emissive/AO start-binding literal (=14). The starting binding
158
+ // number is computed from `bgl.length`, byte-equivalent to
159
+ // `derive(schema).userRegionBindingEnd` when `bgl` is the BGL list
160
+ // derive returned for the user paramSchema.
161
+ // - R-1 the 14-slot user-region assumption breaks once D-3 merges UBO;
162
+ // appendInjection lets the material BGL grow / shrink without
163
+ // churning every injection site.
164
+ //
165
+ // Closed union of injection kinds (plan-strategy §2 D-6):
166
+ // - 'shadow' reserved for future material-level shadow injection
167
+ // (sampler_comparison + texture_depth_2d, 2 entries).
168
+ // The active shadow bindings live in the view BGL today
169
+ // (group(0) bindings 3..7); this kind is the seam for
170
+ // each per-material shadow override surface a future feat
171
+ // wires onto group(1).
172
+ // - 'ibl' the 7 IBL / Skylight entries (irradiance / prefilter
173
+ // cube + brdfLut 2d + 3 samplers + intensity uniform).
174
+ // Used by `buildPbrPipelineLayouts` after the user-region
175
+ // user paramSchema entries are emitted.
176
+ // - 'lightmap' the 4 emissive + occlusion entries (sampler + texture
177
+ // pair x 2). The historical name is "emissive/AO"; we
178
+ // keep that meaning under the generic 'lightmap' label
179
+ // (per-surface secondary-lighting injection) so future
180
+ // lightmap support lands without renaming the kind.
181
+ export type InjectionKind = keyof typeof INJECTION_KIND_LENGTHS;
182
+
183
+ const IBL_INJECTION_LENGTH = 7;
184
+ const LIGHTMAP_INJECTION_LENGTH = 4;
185
+ const SHADOW_INJECTION_LENGTH = 2;
186
+
187
+ /**
188
+ * Append the engine-injection BGL entries for the given `kind` after the
189
+ * user-region BGL entries, with binding numbers starting at `bgl.length`.
190
+ *
191
+ * The function reads `bgl.length` (NOT a hardcoded constant) so each
192
+ * user-region size — derived from `derive(schema).userRegionBindingEnd` or
193
+ * computed manually — flows through to the injection start binding without
194
+ * a coupled edit.
195
+ *
196
+ * Returns ONLY the injected entries; the caller spreads them after `bgl`:
197
+ *
198
+ * ```ts
199
+ * const merged = [...userBgl, ...appendInjection(userBgl, 'ibl')];
200
+ * device.createBindGroupLayout({ entries: merged });
201
+ * ```
202
+ */
203
+ export function appendInjection(
204
+ bgl: readonly GPUBindGroupLayoutEntry[],
205
+ kind: InjectionKind,
206
+ ): GPUBindGroupLayoutEntry[] {
207
+ const start = bgl.length;
208
+ switch (kind) {
209
+ case 'ibl':
210
+ return [
211
+ // binding start+0: irradianceMap (texture_cube)
212
+ {
213
+ binding: start,
214
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
215
+ texture: { sampleType: 'float', viewDimension: 'cube' },
216
+ },
217
+ // binding start+1: irradianceSampler
218
+ {
219
+ binding: start + 1,
220
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
221
+ sampler: { type: 'filtering' },
222
+ },
223
+ // binding start+2: prefilterMap (texture_cube)
224
+ {
225
+ binding: start + 2,
226
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
227
+ texture: { sampleType: 'float', viewDimension: 'cube' },
228
+ },
229
+ // binding start+3: prefilterSampler
230
+ {
231
+ binding: start + 3,
232
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
233
+ sampler: { type: 'filtering' },
234
+ },
235
+ // binding start+4: brdfLut (texture_2d)
236
+ {
237
+ binding: start + 4,
238
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
239
+ texture: { sampleType: 'float', viewDimension: '2d' },
240
+ },
241
+ // binding start+5: brdfLutSampler
242
+ {
243
+ binding: start + 5,
244
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
245
+ sampler: { type: 'filtering' },
246
+ },
247
+ // binding start+6: uniform { intensity: f32 }
248
+ {
249
+ binding: start + 6,
250
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
251
+ buffer: { type: 'uniform' },
252
+ },
253
+ ];
254
+ case 'lightmap':
255
+ return [
256
+ // emissive sampler + texture pair
257
+ {
258
+ binding: start,
259
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
260
+ sampler: { type: 'filtering' },
261
+ },
262
+ {
263
+ binding: start + 1,
264
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
265
+ texture: { sampleType: 'float', viewDimension: '2d' },
266
+ },
267
+ // occlusion sampler + texture pair
268
+ {
269
+ binding: start + 2,
270
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
271
+ sampler: { type: 'filtering' },
272
+ },
273
+ {
274
+ binding: start + 3,
275
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
276
+ texture: { sampleType: 'float', viewDimension: '2d' },
277
+ },
278
+ ];
279
+ case 'shadow':
280
+ return [
281
+ {
282
+ binding: start,
283
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
284
+ sampler: { type: 'comparison' },
285
+ },
286
+ {
287
+ binding: start + 1,
288
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
289
+ texture: { sampleType: 'depth', viewDimension: '2d' },
290
+ },
291
+ ];
292
+ }
293
+ }
294
+
295
+ // Closed-set length sentinels — the map is the membership owner.
296
+ export const INJECTION_KIND_LENGTHS = {
297
+ shadow: SHADOW_INJECTION_LENGTH,
298
+ ibl: IBL_INJECTION_LENGTH,
299
+ lightmap: LIGHTMAP_INJECTION_LENGTH,
300
+ };
301
+
302
+ /**
303
+ * Caps shape consumed by the BGL factory functions for storage-buffer vs
304
+ * uniform-buffer branching. Mirrors the two fields the engine reads from
305
+ * `RhiCaps` (plan D-4 + D-5).
306
+ */
307
+ export interface PbrCaps {
308
+ readonly storageBuffer: boolean;
309
+ }
310
+
311
+ /**
312
+ * The view BGL entry list. binding 0 = view UBO (vertex + fragment);
313
+ * binding 1 = pointLights (storage or uniform, per caps);
314
+ * binding 2 = spotLights (storage or uniform, per caps);
315
+ * binding 3 = directional shadowMap atlas (texture_depth_2d, vertex+fragment).
316
+ * feat-20260613-csm-cascaded-shadow-maps: this is the CSM atlas — N
317
+ * cascades tiled into one 2D depth texture, sampled via per-cascade UV
318
+ * mapping in `lighting-directional.wgsl`. Single binding survives N=1..4
319
+ * (no array-layer form; cascades live in viewport offsets per the
320
+ * check-csm-unique-shadow-path grep gate).
321
+ * binding 4 = shadow comparison sampler (shared by directional + point);
322
+ * binding 5 = point shadow cube_array depth atlas (texture_depth_cube_array;
323
+ * fragment-only). feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1.
324
+ * binding 6 = point shadow params UBO (`array<vec4<f32>, 4>`, 64 B;
325
+ * fragment-only). One lane per shadow-casting point light slot
326
+ * (shadowAtlasLayer in [0, 4)) carrying `(near, far, 1/(far-near), 0)`.
327
+ * binding 7 = shadowCasterCascade UBO (16 B; vertex + fragment). Per-pass
328
+ * cascade-index uniform consumed exclusively by `shadow_caster.wgsl` to
329
+ * pick `view.lightViewProj_X` for the cascade currently being rasterized
330
+ * (feat-20260613-csm-cascaded-shadow-maps M5 / w28). Forward PBR shaders
331
+ * declare the binding via `common.wgsl` but do not reference it; WebGPU
332
+ * still requires a populated entry on every view BG so the host writes a
333
+ * stable singleton buffer.
334
+ * binding 8 = spot shadow atlas (texture_depth_2d; fragment-only).
335
+ * feat-20260625-spot-light-shadow-mapping M3 / w14 (D-5). A single 2D depth
336
+ * texture holding up to 4 spot shadows in a 2x2 tile grid. ALWAYS-ON (no caps
337
+ * gate — `texture_depth_2d` is compat-safe everywhere), matching the
338
+ * unconditional `spotShadowMap` WGSL declaration in common.wgsl. Reuses the
339
+ * comparison sampler at binding 4 (no binding 9). Every view BG must populate
340
+ * binding 8 (real spotShadowDepth view when spot shadows run, else a 1x1
341
+ * fallback depth view cleared to fully-lit).
342
+ *
343
+ * Mirrors feat-20260519-light-casters M3 D-S1 layout +
344
+ * feat-20260520-directional-light-shadow-mapping M2 / w14 (D-1) shadow
345
+ * map binding +
346
+ * feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1 BGL hookup
347
+ * (always-on bindings 5/6 paired with the unconditional `POINT_SHADOW_AVAILABLE`
348
+ * define registered in vite-plugin-shader) +
349
+ * feat-20260613-csm-cascaded-shadow-maps M5 / w28 (binding 7 cascade UBO).
350
+ * binding 10 (Points/Lines viewport UBO; always bound for the shared view
351
+ * layout and consumed only by the dedicated points-lines shader).
352
+ * Isolated here so M4 round-4 tests can recreate the layout.
353
+ *
354
+ * feat-20260526-pbr-uniform-fallback-no-storage-buffer M3 / w9:
355
+ * caps.storageBuffer===false switches bindings 1+2 from
356
+ * 'read-only-storage' to 'uniform'.
357
+ */
358
+ export function buildPbrViewBglEntries(caps: PbrCaps): GPUBindGroupLayoutEntry[] {
359
+ const lightBufType: GPUBufferBindingType = caps.storageBuffer ? 'read-only-storage' : 'uniform';
360
+ return [
361
+ {
362
+ binding: 0,
363
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
364
+ buffer: { type: 'uniform' },
365
+ },
366
+ {
367
+ binding: 1,
368
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
369
+ buffer: { type: lightBufType },
370
+ },
371
+ {
372
+ binding: 2,
373
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
374
+ buffer: { type: lightBufType },
375
+ },
376
+ {
377
+ binding: 3,
378
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
379
+ texture: { sampleType: 'depth', viewDimension: '2d' },
380
+ },
381
+ {
382
+ binding: 4,
383
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
384
+ sampler: { type: 'comparison' },
385
+ },
386
+ // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: point shadow
387
+ // cube_array depth atlas. Bound to either the real ShadowAtlas
388
+ // cube_array view (when point shadows are active) or a 1x1x6 fallback
389
+ // cube_array view cleared to 1.0 (fully lit). Visibility is FRAGMENT
390
+ // only -- the directional binding 3 is VERTEX|FRAGMENT for shadow
391
+ // probe-debug sampling, but the cube atlas has no host-side probe path.
392
+ {
393
+ binding: 5,
394
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
395
+ texture: { sampleType: 'depth', viewDimension: 'cube-array' },
396
+ },
397
+ // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: point shadow
398
+ // params UBO. Carries `array<vec4<f32>, 4>` = 64 B with one lane per
399
+ // shadow-casting point light slot (shadowAtlasLayer in [0, 4)). Each
400
+ // lane stores `(near, far, 1/(far-near), 0)` so the fragment-shader
401
+ // depth-ref reconstruction (lighting-punctual.wgsl evalPointShadowed)
402
+ // can avoid sampling LightSlot for the URP path. HDRP rides the same
403
+ // constants on `LightSlot.kind_and_pad.zw` so binding 6 is unused on
404
+ // HDRP shaders even though the BGL declares it (charter P4 single SSOT
405
+ // BGL across pipelines; the HDRP variant simply doesn't reference the
406
+ // binding in WGSL, which is allowed).
407
+ {
408
+ binding: 6,
409
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
410
+ buffer: { type: 'uniform' },
411
+ },
412
+ // feat-20260613-csm-cascaded-shadow-maps M5 / w28: shadowCasterCascade
413
+ // UBO (16 B). Carries the 0-based cascade index of the shadow pass
414
+ // currently being rasterized so `shadow_caster.wgsl` can index into
415
+ // `view.lightViewProj_X` per cascade. Shifted from binding 5 to
416
+ // binding 7 on 2026-06-13 to make room for point-shadow bindings 5/6
417
+ // (they predate this feat in main; CSM's slot was the optimal-yield
418
+ // give since point-shadow needs FRAGMENT-only and the cascade UBO
419
+ // needs vertex-stage too — keeping cascade higher avoids interleaving
420
+ // visibility flags within the contiguous shadow-binding cluster).
421
+ {
422
+ binding: 7,
423
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
424
+ buffer: { type: 'uniform' },
425
+ },
426
+ // feat-20260625-spot-light-shadow-mapping M3 / w14 (D-5): spot shadow
427
+ // atlas. A single `texture_depth_2d` holding up to 4 spot shadows in a 2x2
428
+ // tile grid (urp-pipeline.ts spotShadowDepth). FRAGMENT-only — the spot
429
+ // shadow factor is reconstructed at fragment time via perspective-divide in
430
+ // `evalSpotShadowed` (lighting-punctual.wgsl).
431
+ //
432
+ // ALWAYS-ON (no caps gate, unlike the point cube_array atlas at binding 5
433
+ // which rides POINT_SHADOW_AVAILABLE): spot uses `texture_depth_2d` which is
434
+ // compat-safe in every WebGPU profile, so the binding is unconditionally
435
+ // declared. The matching WGSL declaration is `spotShadowMap` at @group(0)
436
+ // binding 8 in common.wgsl (also unconditional) — the two must stay in
437
+ // lock-step or WebGPU validation rejects the bind group at smoke time
438
+ // (memory: BGL shape mismatch is a browser-path-only bug). No binding 9
439
+ // sampler: spot reuses the comparison sampler at binding 4.
440
+ // feat-20260625-spot-light-shadow-mapping M3 / w14 (D-5): spot shadow 2D
441
+ // atlas, the LAST view-BG binding. The per-spot fragment-read perspective
442
+ // lightViewProj matrices that w24 originally declared at a standalone
443
+ // binding 9 uniform buffer were folded into the View UBO (binding 0,
444
+ // `view.spotLightViewProj`) in w25 (scope-amend webkit-fallback): the
445
+ // standalone binding pushed the WebGL2 fallback fragment uniform-buffer
446
+ // count to 12, over GLES 3.0's `max_uniform_buffers_per_shader_stage = 11`,
447
+ // crashing pipeline-layout creation on the compat path (this feat's target).
448
+ {
449
+ binding: 8,
450
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
451
+ texture: { sampleType: 'depth', viewDimension: '2d' },
452
+ },
453
+ {
454
+ binding: 10,
455
+ visibility: GPU_SHADER_STAGE_VERTEX,
456
+ buffer: { type: 'uniform', hasDynamicOffset: true },
457
+ },
458
+ ];
459
+ }
460
+
461
+ // ─── PBR pipeline layout factory ────────────────────────────────────────────
462
+
463
+ /**
464
+ * Build the PBR pipeline layout under D-5 round-4: 4 slots `[view,
465
+ * material, mesh-array, instances]`; the material BGL is derived from the
466
+ * standard material schema and engine injection chain.
467
+ *
468
+ * `caps.storageBuffer===false` switches every storage-buffer BGL entry
469
+ * (view bindings 1+2, mesh-array, instances) to `uniform`.
470
+ *
471
+ * Throws on each `createBindGroupLayout` / `createPipelineLayout` Result
472
+ * failure -- the engine bootstrap path (createRenderer) wraps the call in
473
+ * `runShimSyncStep` to fold the throw into the structured error pipe.
474
+ */
475
+ export function buildPbrPipelineLayouts(
476
+ device: PbrPipelineDevice,
477
+ caps: PbrCaps,
478
+ ): PbrPipelineLayoutBundle {
479
+ // D-13 round-2: 4 BGLs route through buildBindGroupLayoutDescriptor.
480
+ // The dispatcher reads kind + caps; spec content is unused without a
481
+ // registry (no shader-axis reflection at this seam — the 4 BGLs are
482
+ // caps-driven literals + the deterministic Skylight + lightmap merge
483
+ // sequence that has no dependency on shader.id).
484
+ const viewBglRes = device.createBindGroupLayout(
485
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'pbr-view', caps }),
486
+ );
487
+ if (!viewBglRes.ok) throw viewBglRes.error;
488
+
489
+ // Material BGL: derived user region + Skylight + lightmap injection.
490
+ // feat-20260613 fix-issue-5: drop the buildPbrMaterialEmissiveAoEntries
491
+ // shim. The lightmap injection start binding is computed from the post-
492
+ // skylight BGL length (= 14) directly inside appendInjection.
493
+ const materialBglRes = device.createBindGroupLayout(
494
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'pbr-material-merged' }),
495
+ );
496
+ if (!materialBglRes.ok) throw materialBglRes.error;
497
+
498
+ // mesh-array BGL.
499
+ const meshArrayBglRes = device.createBindGroupLayout(
500
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'pbr-mesh-array', caps }),
501
+ );
502
+ if (!meshArrayBglRes.ok) throw meshArrayBglRes.error;
503
+
504
+ // instances BGL.
505
+ const instancesBglRes = device.createBindGroupLayout(
506
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'pbr-instances', caps }),
507
+ );
508
+ if (!instancesBglRes.ok) throw instancesBglRes.error;
509
+
510
+ // Pipeline layout (4 slots).
511
+ const layouts: readonly [BindGroupLayout, BindGroupLayout, BindGroupLayout, BindGroupLayout] = [
512
+ viewBglRes.value,
513
+ materialBglRes.value,
514
+ meshArrayBglRes.value,
515
+ instancesBglRes.value,
516
+ ];
517
+ const pipelineLayoutRes = device.createPipelineLayout({
518
+ label: 'pbr-pl',
519
+ bindGroupLayouts: layouts,
520
+ });
521
+ if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
522
+
523
+ return {
524
+ pipelineLayout: pipelineLayoutRes.value,
525
+ viewBgl: viewBglRes.value,
526
+ materialBgl: materialBglRes.value,
527
+ meshArrayBgl: meshArrayBglRes.value,
528
+ instancesBgl: instancesBglRes.value,
529
+ bindGroupLayouts: layouts,
530
+ };
531
+ }
532
+
533
+ // ─── PBR skin material-shader identifier (SSOT) ────────────────────────────
534
+
535
+ /**
536
+ * SSOT for the skin material shader's registered identifier. The shader
537
+ * package registers under this string (see register-default-standard-pbr-skin.ts
538
+ * `RESERVED_ID`); runtime dispatch sites import this constant rather than
539
+ * carrying a literal so a future rename is a one-line change. AC-09 grep
540
+ * gate: the body of `selectPipelineLayoutForVariant` MUST NOT contain a
541
+ * literal `'forgeax::pbr-skin'` -- callers map this constant to
542
+ * `LayoutKind = 'pbr-skin'` upstream.
543
+ */
544
+ export const SKIN_MATERIAL_SHADER_ID = 'forgeax::pbr-skin' as const;
545
+
546
+ /** Returns true for the engine-shipped standard-PBR material shader family. */
547
+ export function isStandardPbrMaterialShader(shaderId: string | undefined): boolean {
548
+ return (
549
+ shaderId === 'forgeax::default-standard-pbr' ||
550
+ shaderId === SKIN_MATERIAL_SHADER_ID ||
551
+ shaderId === 'forgeax::default-standard-pbr-skin'
552
+ );
553
+ }
554
+
555
+ // ─── PBR skin pipeline layout factory (bug-20260611) ───────────────────────
556
+ //
557
+ // The skin material shader (`forgeax::pbr-skin`, registered by
558
+ // `register-default-standard-pbr-skin.ts`) needs the same 4-slot layout shape
559
+ // as standard PBR EXCEPT for slot 2: its mesh-array BGL declares **2**
560
+ // dynamic-offset entries (binding 0 = meshes, binding 1 = palette) versus
561
+ // standard PBR's single binding 0. Without a dedicated pipeline layout the
562
+ // skin shader's `@group(2) @binding(1) palette : array<mat4x4<f32>>` reference
563
+ // trips a `Binding doesn't exist in [BindGroupLayoutInternal "pbr-mesh-array-bgl"]`
564
+ // validation error in `device.createRenderPipeline`, surfaced as
565
+ // `RhiError limit-exceeded` and an invalid command buffer (Playwright TDD trace
566
+ // captured 2026-06-11 in apps/hello/skin).
567
+ //
568
+ // The factory **reuses** view / material / instances BGL handles produced by
569
+ // `buildPbrPipelineLayouts` (charter P4: a single SSOT BGL for each slot the
570
+ // shapes actually share) and only creates a new mesh-array BGL + new pipeline
571
+ // layout. This keeps the per-binding-shape SSOT in one place and avoids an
572
+ // alternate skin-only material BGL (the skin shader's group(0) and group(1)
573
+ // are byte-for-byte the standard-PBR contract).
574
+
575
+ /**
576
+ * Build the PBR skin pipeline layout (4 slots `[view, material,
577
+ * mesh-array(2-entry), instances]`). View / material / instances BGLs are
578
+ * shared with the standard-PBR layout (passed in via `pbr` bundle); the only
579
+ * new BGL is the 2-entry mesh-array slot for `meshes` + `palette`.
580
+ *
581
+ * Throws on each `createBindGroupLayout` / `createPipelineLayout` Result
582
+ * failure -- the engine bootstrap path wraps the call in `runShimSyncStep`
583
+ * to fold the throw into the structured error pipe.
584
+ */
585
+ export function buildPbrSkinLayouts(
586
+ device: PbrPipelineDevice,
587
+ caps: PbrCaps,
588
+ pbr: PbrPipelineLayoutBundle,
589
+ ): PbrPipelineLayoutBundle {
590
+ // 2-entry mesh-array BGL: binding 0 meshes + binding 1 palette. Both
591
+ // dynamic-offset (palette window per-entity, like meshes window).
592
+ const skinMeshArrayBglRes = device.createBindGroupLayout(
593
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, {
594
+ kind: 'pbr-skin-mesh-array',
595
+ caps,
596
+ }),
597
+ );
598
+ if (!skinMeshArrayBglRes.ok) throw skinMeshArrayBglRes.error;
599
+
600
+ const layouts: readonly [BindGroupLayout, BindGroupLayout, BindGroupLayout, BindGroupLayout] = [
601
+ pbr.viewBgl,
602
+ pbr.materialBgl,
603
+ skinMeshArrayBglRes.value,
604
+ pbr.instancesBgl,
605
+ ];
606
+ const pipelineLayoutRes = device.createPipelineLayout({
607
+ label: 'pbr-skin-pl',
608
+ bindGroupLayouts: layouts,
609
+ });
610
+ if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
611
+
612
+ return {
613
+ pipelineLayout: pipelineLayoutRes.value,
614
+ viewBgl: pbr.viewBgl,
615
+ materialBgl: pbr.materialBgl,
616
+ meshArrayBgl: skinMeshArrayBglRes.value,
617
+ instancesBgl: pbr.instancesBgl,
618
+ bindGroupLayouts: layouts,
619
+ };
620
+ }
621
+
622
+ // ─── Unlit material BGL factory ─────────────────────────────────────────────
623
+
624
+ /**
625
+ * Build a stand-alone 7-entry unlit material BGL. Round-4 D-5 keeps unlit
626
+ * material BG isolated from Skylight binding 7..13 -- unlit demos do not
627
+ * pay for IBL state. The unlit pipeline still binds material at slot 1,
628
+ * just with a 7-entry layout.
629
+ *
630
+ * Note: at the moment the runtime still routes both unlit + standard
631
+ * through a single 14-entry pipeline layout; the unlit material BG
632
+ * carries fallback identity resources at binding 7..13. This factory is
633
+ * exported as a future-proof seam for the moment when unlit demos own
634
+ * their own pipeline layout (t57 (e) test pins the contract today so the
635
+ * eventual split has a green target).
636
+ */
637
+ export function buildUnlitMaterialBgl(device: PbrPipelineDevice): BindGroupLayout {
638
+ const res = device.createBindGroupLayout(
639
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'unlit-material' }),
640
+ );
641
+ if (!res.ok) throw res.error;
642
+ return res.value;
643
+ }
644
+
645
+ // ─── Material BG assembly helpers (unlit) ───────────────────────────────────
646
+
647
+ /**
648
+ * Inputs for `buildUnlitMaterialBindGroupEntries`. The fields mirror the
649
+ * record-stage's local variables; isolating the assembler here lets t58
650
+ * (e) test exercise the contract without recreating the entire record
651
+ * stage.
652
+ */
653
+ export interface UnlitMaterialBindGroupEntryInputs {
654
+ readonly materialUniform: Buffer;
655
+ readonly materialOffset: number;
656
+ readonly materialSize: number;
657
+ readonly defaultSampler: Sampler;
658
+ readonly baseColorView: TextureView;
659
+ readonly defaultWhiteView: TextureView;
660
+ }
661
+
662
+ /**
663
+ * Build the 7 BindGroupEntry values for the unlit material BG (binding
664
+ * 0..6). Output flows into `device.createBindGroup({ layout:
665
+ * unlitMaterialBgl, entries })`.
666
+ */
667
+ export function buildUnlitMaterialBindGroupEntries(
668
+ inputs: UnlitMaterialBindGroupEntryInputs,
669
+ ): BindGroupEntry[] {
670
+ return [
671
+ {
672
+ binding: 0,
673
+ resource: {
674
+ kind: 'buffer' as const,
675
+ value: {
676
+ buffer: inputs.materialUniform,
677
+ offset: inputs.materialOffset,
678
+ size: inputs.materialSize,
679
+ },
680
+ },
681
+ },
682
+ { binding: 1, resource: { kind: 'sampler' as const, value: inputs.defaultSampler } },
683
+ { binding: 2, resource: { kind: 'textureView' as const, value: inputs.baseColorView } },
684
+ { binding: 3, resource: { kind: 'sampler' as const, value: inputs.defaultSampler } },
685
+ { binding: 4, resource: { kind: 'textureView' as const, value: inputs.defaultWhiteView } },
686
+ { binding: 5, resource: { kind: 'sampler' as const, value: inputs.defaultSampler } },
687
+ { binding: 6, resource: { kind: 'textureView' as const, value: inputs.defaultWhiteView } },
688
+ ];
689
+ }
690
+
691
+ // Surface re-export so consumers can build a complete BindGroup pipeline
692
+ // without reaching into multiple modules.
693
+ export type { BindGroup };
694
+
695
+ // ─── feat-20260625 M3 / w10 — sprite-pass variantSet selector ────────────────
696
+ //
697
+ // Plan-strategy D-1 + D-4: when an entity carries `SpriteInstances` the
698
+ // sprite-pass record stage must pick the `PER_INSTANCE_REGION=true` sprite
699
+ // shader variant compiled in M2 (w7) so the WGSL `InstanceData` struct
700
+ // includes the per-instance `region: vec4<f32>` field and reads region from
701
+ // the interleaved 80B-per-instance buffer (not from the material UBO).
702
+ //
703
+ // Non-`SpriteInstances` sprite entities (e.g. the sprite-atlas demo) keep
704
+ // the default variant where `PER_INSTANCE_REGION` is undefined and the
705
+ // shader's `#else` branch reads region from material UBO — preserving
706
+ // existing behaviour (plan-strategy D-4 "pbr / unlit / sprite-atlas
707
+ // behaviour unchanged" / requirements Edge Cases).
708
+ //
709
+ // Variant set string format mirrors the existing `URP_PBR_VARIANT_SET` /
710
+ // HDRP variant set string idiom in `pipeline-spec.ts` (`+`-separated kv
711
+ // pairs); the record stage threads this string through the per-shader
712
+ // pipeline-cache key + lazy-build `getMaterialShaderPipeline` lookup.
713
+
714
+ /**
715
+ * variantSet string fired into the sprite-pass pipeline cache when the
716
+ * entity carries `SpriteInstances` (plan-strategy D-1 interleaved single
717
+ * buffer + D-4 axis on `sprite.wgsl`).
718
+ *
719
+ * bug-20260708 M2 (c): aligned with the canonical all-true variant key
720
+ * `''` — sprite's manifest emits `{PIR:true, SBA:true}` under the empty-
721
+ * string key (all variant axes true → canonical). The runtime's
722
+ * `getMaterialShaderPipeline` variant-substitution branch
723
+ * (`createRenderer.ts:1730`) resolves this via
724
+ * `findVariantByKey(msEntry, '')` returning the 5653B PIR=true variant.
725
+ * Combined with the `cacheKeyOf` sentinel `~` (bug-20260708 M2 (b)) this
726
+ * value produces a cache key distinct from the `variantSet=undefined`
727
+ * character/default path (which now resolves to the PIR=false 5575B boot-
728
+ * registered variant). Sprite pipeline layout routing is anchored via
729
+ * `LayoutKind='sprite-urp'` so `variantSet=''` here does NOT trigger the
730
+ * HDRP-layout branch of `selectPipelineLayoutForVariant` (research R-12
731
+ * flow; plan-strategy §4 R-1' guard).
732
+ */
733
+ export const SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET = '';
734
+
735
+ // BglKind dispatch (M3 / D-13) — closed union of BGL shapes the runtime ships
736
+ // ══════════════════════════════════════════════════════════════════════════════
737
+
738
+ /**
739
+ * Closed union of bind-group-layout shapes the runtime constructs.
740
+ *
741
+ * Each kind names one physically distinct BGL the runtime has historically
742
+ * built by hand. {@link buildBindGroupLayoutDescriptor} dispatches on this
743
+ * union so every `device.createBindGroupLayout(...)` call site shares one
744
+ * SSOT for entries / labels (plan-strategy §3.2; D-13 round-2 decision).
745
+ *
746
+ * Three groups by derivation source:
747
+ * 1. Shader-derived (paramSchema reflection + injection chain):
748
+ * - `'pbr-material-merged'` — derived user region + Skylight 7 + lightmap 4
749
+ * - `'unlit-material'` — 7 entries: base PBR material only (no inject)
750
+ * - `'hdrp-7-slot'` — 7 entries (binding 0 + 3..8): HDRP cluster + SSAO group(2) BGL
751
+ * 2. Caps-driven literal shapes (no shader):
752
+ * - `'pbr-view'` — 10 entries: view UBO + lights + 6 shadow bindings
753
+ * (directional 3/4, point 5/6, cascade 7, spot atlas 8, spot
754
+ * lightViewProj matrices 9 — feat-20260625)
755
+ * - `'pbr-mesh-array'` — 1 entry: per-entity mesh SSBO (dynamic-offset)
756
+ * - `'pbr-instances'` — 1 entry: per-instance SSBO (no dynamic-offset)
757
+ * - `'pbr-skin-mesh-array'` — 2 entries: meshes + skin palette
758
+ * 3. Attachment-driven (fullscreen post-process):
759
+ * - `'fullscreen-post'` — 2 entries: input texture + sampler. The texture
760
+ * `sampleType` is derived from `spec.attachments` (plan §R3 fix):
761
+ * `'depth32float'` → `'depth'`; `'r32float'` → `'unfilterable-float'`;
762
+ * else → `'float'`.
763
+ * - `'fullscreen-post-with-params'` — 3 entries: the same texture@0 +
764
+ * sampler@1 as `'fullscreen-post'`, plus a `buffer@2` uniform for the
765
+ * per-frame params UBO (feat-20260621 D-2: `entry.params !== undefined`
766
+ * passes route here; the layout stays group(1), q3=B). `'fullscreen-post'`
767
+ * stays byte-identical so param-less consumers degrade with no change.
768
+ * - `'fullscreen-post-with-scene-depth-msaa'` — the depth-read layout with
769
+ * `texture.multisampled=true`, selected for a 4-sample scene depth target.
770
+ */
771
+ export type BglKind =
772
+ | 'pbr-view'
773
+ | 'pbr-material-merged'
774
+ | 'pbr-mesh-array'
775
+ | 'pbr-instances'
776
+ | 'pbr-skin-mesh-array'
777
+ | 'unlit-material'
778
+ | 'hdrp-7-slot'
779
+ | 'fullscreen-post'
780
+ | 'fullscreen-post-with-params'
781
+ | 'fullscreen-post-with-scene-depth'
782
+ | 'fullscreen-post-with-scene-depth-msaa';
783
+
784
+ /**
785
+ * Output shape of {@link buildBindGroupLayoutDescriptor}: matches the RHI
786
+ * `BindGroupLayoutDescriptor` (label + entries with `ExplicitUndefined`) so
787
+ * the result can be passed directly to `device.createBindGroupLayout(...)`.
788
+ *
789
+ * `entries` is a mutable `Array` to match `GPUBindGroupLayoutDescriptor`
790
+ * (WebGPU types declare it mutable). Callers MUST treat the array as
791
+ * read-only — the dispatcher freezes neither the array nor its entries
792
+ * for hot-path performance.
793
+ */
794
+ export interface BindGroupLayoutDescriptorOutput {
795
+ readonly label: string | undefined;
796
+ readonly entries: GPUBindGroupLayoutEntry[];
797
+ }
798
+
799
+ /** Build the canonical HDRP group(2) bind-group layout. */
800
+ export function createHdrpBindGroupLayoutDescriptor(
801
+ storageBuffer: boolean = true,
802
+ ): BindGroupLayoutDescriptor {
803
+ const meshBufType: GPUBufferBindingType = storageBuffer ? 'read-only-storage' : 'uniform';
804
+ const clusterBufType: GPUBufferBindingType = storageBuffer ? 'read-only-storage' : 'uniform';
805
+ return {
806
+ label: 'hdrp-unified-bgl-group2',
807
+ entries: [
808
+ {
809
+ binding: 0,
810
+ visibility: GPU_SHADER_STAGE_VERTEX,
811
+ buffer: { type: meshBufType, hasDynamicOffset: true },
812
+ },
813
+ // Bindings 1 and 2 stay absent for the URP physical isolation gap.
814
+ {
815
+ binding: 3,
816
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
817
+ buffer: { type: clusterBufType, hasDynamicOffset: false },
818
+ },
819
+ {
820
+ binding: 4,
821
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
822
+ buffer: { type: clusterBufType, hasDynamicOffset: false },
823
+ },
824
+ {
825
+ binding: 5,
826
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
827
+ buffer: { type: clusterBufType, hasDynamicOffset: false },
828
+ },
829
+ {
830
+ binding: 6,
831
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
832
+ buffer: { type: 'uniform', hasDynamicOffset: false },
833
+ },
834
+ {
835
+ binding: 7,
836
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
837
+ texture: { sampleType: 'float', viewDimension: '2d', multisampled: false },
838
+ },
839
+ {
840
+ binding: 8,
841
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
842
+ sampler: { type: 'filtering' },
843
+ },
844
+ ],
845
+ };
846
+ }
847
+
848
+ /**
849
+ * Build a `GPUBindGroupLayoutDescriptor` from a PipelineSpec, dispatching on
850
+ * `options.kind` to one of 9 closed BGL shapes (D-13 round-2).
851
+ *
852
+ * Shader-derived kinds (`'pbr-material-merged'` / `'unlit-material'` /
853
+ * `'hdrp-7-slot'`) require `options.registry` to look up the shader entry
854
+ * and reflect its `paramSchema` via {@link deriveBglShapeFromShader}; they
855
+ * compose the per-entry injection chain (Skylight + lightmap for material;
856
+ * HDRP variantSet for cluster-forward).
857
+ *
858
+ * Caps-driven kinds (`'pbr-view'` / `'pbr-mesh-array'` / `'pbr-instances'` /
859
+ * `'pbr-skin-mesh-array'`) require `options.caps` for the storage-buffer
860
+ * vs uniform-buffer fallback (RhiCaps.storageBuffer; PBR feat-20260526 M3 /
861
+ * w9). They are wholly determined by the caps shape.
862
+ *
863
+ * Attachment-driven kind (`'fullscreen-post'`) reads
864
+ * `spec.attachments.depthFormat` and `spec.attachments.colorFormats[0]` to
865
+ * pick the texture binding's `sampleType` (R3 fix: `'depth32float'` → `'depth'`,
866
+ * `'r32float'` → `'unfilterable-float'`, else → `'float'`).
867
+ *
868
+ * @param spec - the pipeline spec (axis source for reflection / caps fallback)
869
+ * @param options.kind - which BGL shape to build (closed {@link BglKind} union)
870
+ * @param options.registry - ShaderCatalog for shader-derived kinds
871
+ * @param options.caps - caps shape for caps-driven kinds (storageBuffer)
872
+ * @returns a WebGPU bind-group-layout descriptor (entries + label)
873
+ * @see plan-strategy §3.2 · plan-decisions D-13 · requirements AC-02
874
+ */
875
+ /**
876
+ * Resolve the material paramSchema for a per-shader user-region BGL derivation.
877
+ *
878
+ * Priority (D-1): explicit `options.materialParamSchema` > registry lookup of
879
+ * `spec.shader.id` > `undefined` (the user-region builder then falls back to
880
+ * the built-in standard-PBR 4-texture schema, whose user region is 9 entries).
881
+ */
882
+ function resolveMaterialParamSchema(
883
+ spec: PipelineSpec,
884
+ options: { registry?: ShaderCatalog; materialParamSchema?: readonly ParamSchemaEntry[] },
885
+ ): readonly ParamSchemaEntry[] | undefined {
886
+ if (options.materialParamSchema !== undefined) return options.materialParamSchema;
887
+ if (options.registry !== undefined) {
888
+ const lookup = options.registry.findMaterialArtifact(spec.shader.id);
889
+ if (lookup.ok) return lookup.value.paramSchema;
890
+ }
891
+ return undefined;
892
+ }
893
+
894
+ export function buildBindGroupLayoutDescriptor(
895
+ spec: PipelineSpec,
896
+ options: {
897
+ kind: BglKind;
898
+ registry?: ShaderCatalog;
899
+ caps?: PbrCaps;
900
+ /**
901
+ * Material paramSchema for the per-shader user-region derivation
902
+ * (`'pbr-material-merged'` / `'unlit-material'`). When supplied it is the
903
+ * authoritative source for the user-region BGL shape (D-1); when omitted,
904
+ * `buildPbrMaterialUserRegionEntries` falls back to the built-in
905
+ * standard-PBR 4-texture schema (user region is 9 entries), so
906
+ * the caps-driven `buildPbrPipelineLayouts` seam keeps working unchanged.
907
+ * A registry + resolvable shader id takes precedence over this field.
908
+ */
909
+ materialParamSchema?: readonly ParamSchemaEntry[];
910
+ },
911
+ ): BindGroupLayoutDescriptorOutput {
912
+ switch (options.kind) {
913
+ case 'pbr-view': {
914
+ const caps = options.caps ?? { storageBuffer: true };
915
+ return {
916
+ label: 'pbr-view-bgl',
917
+ entries: buildPbrViewBglEntries(caps),
918
+ };
919
+ }
920
+ case 'pbr-mesh-array': {
921
+ const caps = options.caps ?? { storageBuffer: true };
922
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
923
+ ? 'read-only-storage'
924
+ : 'uniform';
925
+ // sprite-lit's fragment stage does not read the mesh SSBO -- worldPos
926
+ // is carried through the VsOut interpolant. Visibility is kept widened
927
+ // to VERTEX|FRAGMENT because the BGL JSON is compared byte-identically
928
+ // across the sprite / sprite-lit / PBR pipelines that share this
929
+ // descriptor; narrowing here would change every sibling pipeline's
930
+ // BGL fingerprint. WebGPU rejects createRenderPipeline when a fragment
931
+ // stage accesses a binding whose BGL visibility excludes FRAGMENT --
932
+ // widening is permissive (validation-only, no perf cost).
933
+ return {
934
+ label: 'pbr-mesh-array-bgl',
935
+ entries: [
936
+ {
937
+ binding: 0,
938
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
939
+ buffer: { type: meshBufType, hasDynamicOffset: true },
940
+ },
941
+ ],
942
+ };
943
+ }
944
+ case 'pbr-instances': {
945
+ const caps = options.caps ?? { storageBuffer: true };
946
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
947
+ ? 'read-only-storage'
948
+ : 'uniform';
949
+ return {
950
+ label: 'pbr-instances-bgl',
951
+ entries: [
952
+ {
953
+ binding: 0,
954
+ visibility: GPU_SHADER_STAGE_VERTEX,
955
+ buffer: { type: meshBufType, hasDynamicOffset: false },
956
+ },
957
+ ],
958
+ };
959
+ }
960
+ case 'pbr-skin-mesh-array': {
961
+ const caps = options.caps ?? { storageBuffer: true };
962
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
963
+ ? 'read-only-storage'
964
+ : 'uniform';
965
+ return {
966
+ label: 'pbr-skin-mesh-array-bgl',
967
+ entries: [
968
+ {
969
+ binding: 0,
970
+ visibility: GPU_SHADER_STAGE_VERTEX,
971
+ buffer: { type: meshBufType, hasDynamicOffset: true },
972
+ },
973
+ {
974
+ binding: 1,
975
+ visibility: GPU_SHADER_STAGE_VERTEX,
976
+ buffer: { type: meshBufType, hasDynamicOffset: true },
977
+ },
978
+ ],
979
+ };
980
+ }
981
+ case 'pbr-material-merged': {
982
+ // Material BGL: per-shader user-region (derive(paramSchema).bglEntries)
983
+ // + IBL injection (7) + lightmap injection (4). The user-region size is
984
+ // the only variable; injection start = userRegion.length so a 4-texture
985
+ // custom schema shifts IBL/lightmap by one sampler/texture pair (D-1).
986
+ // For the built-in 4-texture standard-PBR schema this is 9 + 7 + 4 = 20.
987
+ //
988
+ // Schema source priority (D-1): explicit materialParamSchema option >
989
+ // registry lookup of spec.shader.id > built-in standard-PBR fallback.
990
+ const resolvedSchema = resolveMaterialParamSchema(spec, options);
991
+ const userRegion = buildPbrMaterialUserRegionEntries(resolvedSchema);
992
+ const afterIbl = [...userRegion, ...appendInjection(userRegion, 'ibl')];
993
+ const merged = [...afterIbl, ...appendInjection(afterIbl, 'lightmap')];
994
+ return {
995
+ label: 'pbr-material-skylight-bgl',
996
+ entries: merged,
997
+ };
998
+ }
999
+ case 'unlit-material': {
1000
+ // Unlit material BGL: per-shader user-region only. No IBL/lightmap
1001
+ // injection (D-5 round-4: unlit demos do not pay for IBL state).
1002
+ const resolvedSchema = resolveMaterialParamSchema(spec, options);
1003
+ return {
1004
+ label: 'unlit-material-bgl',
1005
+ entries: buildPbrMaterialUserRegionEntries(resolvedSchema),
1006
+ };
1007
+ }
1008
+ case 'hdrp-7-slot': {
1009
+ // HDRP unified BGL for group(2): 9 entries (binding 0 + 3..8). The
1010
+ // shape depends on caps.storageBuffer for the cluster-buffer fallback.
1011
+ const caps = options.caps ?? { storageBuffer: true };
1012
+ const desc = createHdrpBindGroupLayoutDescriptor(caps.storageBuffer);
1013
+ return {
1014
+ label: desc.label ?? 'hdrp-unified-bgl-group2',
1015
+ entries: [...(desc.entries ?? [])],
1016
+ };
1017
+ }
1018
+ case 'fullscreen-post': {
1019
+ // Fullscreen post-process BGL: 2 entries (input texture + sampler).
1020
+ // R3 fix: derive sampleType from spec.attachments. Depth attachments
1021
+ // (depth32float) need `sampleType: 'depth'`; r32float needs
1022
+ // `'unfilterable-float'`; everything else (rgba8unorm-srgb, rgba16float,
1023
+ // bgra8unorm, …) is filterable `'float'`.
1024
+ return {
1025
+ label: 'fullscreen-post-bgl',
1026
+ entries: buildFullscreenPostInputEntries(spec),
1027
+ };
1028
+ }
1029
+ case 'fullscreen-post-with-params': {
1030
+ // feat-20260621 D-2: the same input texture@0 + sampler@1 as
1031
+ // 'fullscreen-post', plus binding 2 = per-frame params UBO (uniform).
1032
+ // The first two entries reuse buildFullscreenPostInputEntries so the
1033
+ // sampleType derivation stays a single SSOT; 'fullscreen-post' is
1034
+ // untouched (param-less zero-regression, R-A7).
1035
+ return {
1036
+ label: 'fullscreen-post-with-params-bgl',
1037
+ entries: [
1038
+ ...buildFullscreenPostInputEntries(spec),
1039
+ {
1040
+ binding: 2,
1041
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1042
+ buffer: { type: 'uniform' },
1043
+ },
1044
+ ],
1045
+ };
1046
+ }
1047
+ case 'fullscreen-post-with-scene-depth': {
1048
+ // plan-strategy D-3: 5-entry BGL for post-process passes that read the
1049
+ // camera scene depth. color@0 + sampler@1 reuse buildFullscreenPostInputEntries
1050
+ // (float+filtering for color). depthTex@3 uses `sampleType: 'depth'` and
1051
+ // `dimension: '2d'`; depthSampler@4 uses `type: 'non-filtering'` (nearest
1052
+ // + clamp-to-edge, D-2 — NOT comparison). params@2 is always present
1053
+ // (uniform) to avoid a 2x2 kind explosion per D-3.
1054
+ return {
1055
+ label: 'fullscreen-post-with-scene-depth-bgl',
1056
+ entries: [
1057
+ ...buildFullscreenPostInputEntries(spec),
1058
+ {
1059
+ binding: 2,
1060
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1061
+ buffer: { type: 'uniform' },
1062
+ },
1063
+ {
1064
+ binding: 3,
1065
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1066
+ texture: { sampleType: 'depth', viewDimension: '2d' },
1067
+ },
1068
+ {
1069
+ binding: 4,
1070
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1071
+ sampler: { type: 'non-filtering' },
1072
+ },
1073
+ ],
1074
+ };
1075
+ }
1076
+ case 'fullscreen-post-with-scene-depth-msaa': {
1077
+ return {
1078
+ label: 'fullscreen-post-with-scene-depth-msaa-bgl',
1079
+ entries: [
1080
+ ...buildFullscreenPostInputEntries(spec),
1081
+ {
1082
+ binding: 2,
1083
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1084
+ buffer: { type: 'uniform' },
1085
+ },
1086
+ {
1087
+ binding: 3,
1088
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1089
+ texture: { sampleType: 'depth', viewDimension: '2d', multisampled: true },
1090
+ },
1091
+ {
1092
+ binding: 4,
1093
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1094
+ sampler: { type: 'non-filtering' },
1095
+ },
1096
+ ],
1097
+ };
1098
+ }
1099
+ }
1100
+ }
1101
+
1102
+ /**
1103
+ * The shared texture@0 + sampler@1 entries for fullscreen post-process BGLs.
1104
+ * sampleType is derived from `spec.attachments` (R3 fix): depth attachments →
1105
+ * `'depth'` + `'comparison'` sampler; `'r32float'` → `'unfilterable-float'`;
1106
+ * else → `'float'` + `'filtering'`. Both `'fullscreen-post'` and
1107
+ * `'fullscreen-post-with-params'` reuse this so the derivation is one SSOT.
1108
+ */
1109
+ function buildFullscreenPostInputEntries(spec: PipelineSpec): GPUBindGroupLayoutEntry[] {
1110
+ const inputFormat: GPUTextureFormat | undefined =
1111
+ spec.attachments.depthFormat ?? spec.attachments.colorFormats[0];
1112
+ const sampleType: GPUTextureSampleType =
1113
+ inputFormat === 'depth32float' ||
1114
+ inputFormat === 'depth24plus' ||
1115
+ inputFormat === 'depth24plus-stencil8' ||
1116
+ inputFormat === 'depth16unorm'
1117
+ ? 'depth'
1118
+ : inputFormat === 'r32float'
1119
+ ? 'unfilterable-float'
1120
+ : 'float';
1121
+ return [
1122
+ {
1123
+ binding: 0,
1124
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1125
+ texture: { sampleType, viewDimension: '2d' },
1126
+ },
1127
+ {
1128
+ binding: 1,
1129
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1130
+ sampler: {
1131
+ type: sampleType === 'depth' ? 'comparison' : 'filtering',
1132
+ },
1133
+ },
1134
+ ];
1135
+ }
1136
+
1137
+ // ══════════════════════════════════════════════════════════════════════════════