@forgeax/engine-render 0.1.2

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 (1172) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1019 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/analytic-sky-contract.test.d.ts +2 -0
  5. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +1 -0
  6. package/dist/__tests__/analytic-sky-falsify.test.d.ts +2 -0
  7. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +1 -0
  8. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +2 -0
  9. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +1 -0
  10. package/dist/__tests__/authoring-path.unit.test.d.ts +2 -0
  11. package/dist/__tests__/authoring-path.unit.test.d.ts.map +1 -0
  12. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts +2 -0
  13. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
  15. package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
  16. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  17. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/camera-temporal.test-d.d.ts +2 -0
  19. package/dist/__tests__/camera-temporal.test-d.d.ts.map +1 -0
  20. package/dist/__tests__/camera-temporal.test.d.ts +2 -0
  21. package/dist/__tests__/camera-temporal.test.d.ts.map +1 -0
  22. package/dist/__tests__/cluster-binner.test.d.ts +2 -0
  23. package/dist/__tests__/cluster-binner.test.d.ts.map +1 -0
  24. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts +2 -0
  25. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts +2 -0
  27. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts +2 -0
  29. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts.map +1 -0
  30. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts +2 -0
  31. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +2 -0
  33. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/environment-inspection.test.d.ts +2 -0
  35. package/dist/__tests__/environment-inspection.test.d.ts.map +1 -0
  36. package/dist/__tests__/factory-contract.integration.test.d.ts +2 -0
  37. package/dist/__tests__/factory-contract.integration.test.d.ts.map +1 -0
  38. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts +2 -0
  39. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/fog-ai-user.fixture.d.ts +2 -0
  41. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +1 -0
  42. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +16 -0
  43. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +1 -0
  44. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +2 -0
  45. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +1 -0
  46. package/dist/__tests__/fog-inspection.integration.test.d.ts +2 -0
  47. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +1 -0
  48. package/dist/__tests__/fog-owner-state.integration.test.d.ts +2 -0
  49. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +1 -0
  50. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +2 -0
  51. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +1 -0
  52. package/dist/__tests__/fog-public-surface.integration.test.d.ts +2 -0
  53. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +1 -0
  54. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +2 -0
  55. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +1 -0
  56. package/dist/__tests__/fog-source-absence.integration.test.d.ts +2 -0
  57. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +1 -0
  58. package/dist/__tests__/fog-temporal.integration.test.d.ts +2 -0
  59. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +1 -0
  60. package/dist/__tests__/frame-chain.unit.test.d.ts +2 -0
  61. package/dist/__tests__/frame-chain.unit.test.d.ts.map +1 -0
  62. package/dist/__tests__/frame-observation.contract.test.d.ts +2 -0
  63. package/dist/__tests__/frame-observation.contract.test.d.ts.map +1 -0
  64. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts +2 -0
  65. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts +6 -0
  67. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -0
  68. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts +2 -0
  69. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts.map +1 -0
  70. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts +2 -0
  71. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts.map +1 -0
  72. package/dist/__tests__/gpu-driven-production.integration.test.d.ts +2 -0
  73. package/dist/__tests__/gpu-driven-production.integration.test.d.ts.map +1 -0
  74. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts +2 -0
  75. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +12 -0
  77. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -0
  78. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts +2 -0
  79. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts.map +1 -0
  80. package/dist/__tests__/gpu-driven-view.browser.test.d.ts +2 -0
  81. package/dist/__tests__/gpu-driven-view.browser.test.d.ts.map +1 -0
  82. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts +2 -0
  83. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts.map +1 -0
  84. package/dist/__tests__/gpu-driven-view.unit.test.d.ts +2 -0
  85. package/dist/__tests__/gpu-driven-view.unit.test.d.ts.map +1 -0
  86. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts +2 -0
  87. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +2 -0
  89. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +1 -0
  90. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts +7 -0
  91. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -0
  92. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts +2 -0
  93. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts.map +1 -0
  94. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts +2 -0
  95. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts.map +1 -0
  96. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts +2 -0
  97. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/gpu-scene.dawn.test.d.ts +2 -0
  99. package/dist/__tests__/gpu-scene.dawn.test.d.ts.map +1 -0
  100. package/dist/__tests__/gpu-scene.unit.test.d.ts +2 -0
  101. package/dist/__tests__/gpu-scene.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +2 -0
  103. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +1 -0
  104. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +2 -0
  105. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts +2 -0
  107. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/injection-kind-owner.test-d.d.ts +2 -0
  109. package/dist/__tests__/injection-kind-owner.test-d.d.ts.map +1 -0
  110. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts +2 -0
  111. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts.map +1 -0
  112. package/dist/__tests__/light-buffer-layout.unit.test.d.ts +2 -0
  113. package/dist/__tests__/light-buffer-layout.unit.test.d.ts.map +1 -0
  114. package/dist/__tests__/material-contract-inventory.unit.test.d.ts +2 -0
  115. package/dist/__tests__/material-contract-inventory.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/material-cooked-projection.unit.test.d.ts +2 -0
  117. package/dist/__tests__/material-cooked-projection.unit.test.d.ts.map +1 -0
  118. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +2 -0
  119. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +1 -0
  120. package/dist/__tests__/material-derived-payload.integration.test.d.ts +2 -0
  121. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +1 -0
  122. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts +2 -0
  123. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts.map +1 -0
  124. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts +2 -0
  125. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts.map +1 -0
  126. package/dist/__tests__/material-stride-surface.unit.test.d.ts +2 -0
  127. package/dist/__tests__/material-stride-surface.unit.test.d.ts.map +1 -0
  128. package/dist/__tests__/materials.unit.test.d.ts +2 -0
  129. package/dist/__tests__/materials.unit.test.d.ts.map +1 -0
  130. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts +2 -0
  131. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts.map +1 -0
  132. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts +2 -0
  133. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts +2 -0
  135. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts.map +1 -0
  136. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts +2 -0
  137. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts.map +1 -0
  138. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts +2 -0
  139. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts.map +1 -0
  140. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts +2 -0
  141. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts.map +1 -0
  142. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts +2 -0
  143. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts.map +1 -0
  144. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +2 -0
  145. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +1 -0
  146. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +2 -0
  147. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +1 -0
  148. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +2 -0
  149. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +1 -0
  150. package/dist/__tests__/pipeline-pass-trace.test.d.ts +2 -0
  151. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +1 -0
  152. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +2 -0
  153. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +1 -0
  154. package/dist/__tests__/plugin.test.d.ts +2 -0
  155. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  156. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts +2 -0
  157. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts.map +1 -0
  158. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts +2 -0
  159. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts.map +1 -0
  160. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +2 -0
  161. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts +2 -0
  163. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts +2 -0
  165. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts.map +1 -0
  166. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts +2 -0
  167. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts +2 -0
  169. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts.map +1 -0
  170. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +2 -0
  171. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +1 -0
  172. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts +2 -0
  173. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts.map +1 -0
  174. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts +2 -0
  175. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts.map +1 -0
  176. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts +2 -0
  177. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts.map +1 -0
  178. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts +2 -0
  179. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts.map +1 -0
  180. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  181. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  182. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  183. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  184. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  185. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  186. package/dist/__tests__/profiler-phase-token.test.d.ts +2 -0
  187. package/dist/__tests__/profiler-phase-token.test.d.ts.map +1 -0
  188. package/dist/__tests__/public-pipeline-id.test-d.d.ts +2 -0
  189. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +1 -0
  190. package/dist/__tests__/public-surface.test-d.d.ts +2 -0
  191. package/dist/__tests__/public-surface.test-d.d.ts.map +1 -0
  192. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts +2 -0
  193. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts.map +1 -0
  194. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +2 -0
  195. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +1 -0
  196. package/dist/__tests__/render-error-code-owner.test-d.d.ts +2 -0
  197. package/dist/__tests__/render-error-code-owner.test-d.d.ts.map +1 -0
  198. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts +2 -0
  199. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts.map +1 -0
  200. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +2 -0
  201. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  202. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  203. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  204. package/dist/__tests__/render-feature-construction.unit.test.d.ts +2 -0
  205. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +1 -0
  206. package/dist/__tests__/render-feature-context.test-d.d.ts +2 -0
  207. package/dist/__tests__/render-feature-context.test-d.d.ts.map +1 -0
  208. package/dist/__tests__/render-feature-contract.test-d.d.ts +2 -0
  209. package/dist/__tests__/render-feature-contract.test-d.d.ts.map +1 -0
  210. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts +2 -0
  211. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts.map +1 -0
  212. package/dist/__tests__/render-feature-docs.unit.test.d.ts +2 -0
  213. package/dist/__tests__/render-feature-docs.unit.test.d.ts.map +1 -0
  214. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +2 -0
  215. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +1 -0
  216. package/dist/__tests__/render-feature-errors.unit.test.d.ts +2 -0
  217. package/dist/__tests__/render-feature-errors.unit.test.d.ts.map +1 -0
  218. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +2 -0
  219. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +1 -0
  220. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts +2 -0
  221. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts.map +1 -0
  222. package/dist/__tests__/render-feature-graph.integration.test.d.ts +2 -0
  223. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +1 -0
  224. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +2 -0
  225. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +1 -0
  226. package/dist/__tests__/render-feature-order.unit.test.d.ts +2 -0
  227. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +1 -0
  228. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts +2 -0
  229. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts.map +1 -0
  230. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts +2 -0
  231. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts.map +1 -0
  232. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  233. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  234. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts +2 -0
  235. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts.map +1 -0
  236. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts +2 -0
  237. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts.map +1 -0
  238. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +2 -0
  239. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +1 -0
  240. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts +2 -0
  241. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts.map +1 -0
  242. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts +2 -0
  243. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts.map +1 -0
  244. package/dist/__tests__/render-feature-public-surface.test-d.d.ts +2 -0
  245. package/dist/__tests__/render-feature-public-surface.test-d.d.ts.map +1 -0
  246. package/dist/__tests__/render-feature-retry.unit.test.d.ts +2 -0
  247. package/dist/__tests__/render-feature-retry.unit.test.d.ts.map +1 -0
  248. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts +2 -0
  249. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts.map +1 -0
  250. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts +2 -0
  251. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts.map +1 -0
  252. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts +2 -0
  253. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts.map +1 -0
  254. package/dist/__tests__/render-feature-staging.unit.test.d.ts +2 -0
  255. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +1 -0
  256. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts +2 -0
  257. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts.map +1 -0
  258. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts +2 -0
  259. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts.map +1 -0
  260. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts +2 -0
  261. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts +7 -0
  263. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts.map +1 -0
  264. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts +2 -0
  265. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts.map +1 -0
  266. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts +2 -0
  267. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts.map +1 -0
  268. package/dist/__tests__/render-graph-hzb-gpu.d.ts +7 -0
  269. package/dist/__tests__/render-graph-hzb-gpu.d.ts.map +1 -0
  270. package/dist/__tests__/render-graph-hzb.browser.test.d.ts +2 -0
  271. package/dist/__tests__/render-graph-hzb.browser.test.d.ts.map +1 -0
  272. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts +2 -0
  273. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts.map +1 -0
  274. package/dist/__tests__/render-graph-primitives.unit.test.d.ts +2 -0
  275. package/dist/__tests__/render-graph-primitives.unit.test.d.ts.map +1 -0
  276. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts +12 -0
  277. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts.map +1 -0
  278. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts +2 -0
  279. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts.map +1 -0
  280. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts +2 -0
  281. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts.map +1 -0
  282. package/dist/__tests__/render-scene-projection.unit.test.d.ts +2 -0
  283. package/dist/__tests__/render-scene-projection.unit.test.d.ts.map +1 -0
  284. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts +2 -0
  285. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts.map +1 -0
  286. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  287. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  288. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +2 -0
  289. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +1 -0
  290. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts +2 -0
  291. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts.map +1 -0
  292. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +2 -0
  293. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +1 -0
  294. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts +2 -0
  295. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts.map +1 -0
  296. package/dist/__tests__/shader-stage-surface.unit.test.d.ts +2 -0
  297. package/dist/__tests__/shader-stage-surface.unit.test.d.ts.map +1 -0
  298. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts +2 -0
  299. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts.map +1 -0
  300. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +2 -0
  301. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +1 -0
  302. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +2 -0
  303. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +1 -0
  304. package/dist/__tests__/surface-configuration.unit.test.d.ts +2 -0
  305. package/dist/__tests__/surface-configuration.unit.test.d.ts.map +1 -0
  306. package/dist/__tests__/taa-history-store.unit.test.d.ts +2 -0
  307. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +1 -0
  308. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +2 -0
  309. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +1 -0
  310. package/dist/__tests__/temporal-inspection.unit.test.d.ts +2 -0
  311. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +1 -0
  312. package/dist/__tests__/texture-usage-surface.unit.test.d.ts +2 -0
  313. package/dist/__tests__/texture-usage-surface.unit.test.d.ts.map +1 -0
  314. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts +2 -0
  315. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts.map +1 -0
  316. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts +2 -0
  317. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts.map +1 -0
  318. package/dist/__tests__/urp-pipeline.unit.test.d.ts +2 -0
  319. package/dist/__tests__/urp-pipeline.unit.test.d.ts.map +1 -0
  320. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts +2 -0
  321. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts.map +1 -0
  322. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts +2 -0
  323. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts.map +1 -0
  324. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts +2 -0
  325. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts.map +1 -0
  326. package/dist/__tests__/visibility-extract.integration.test.d.ts +2 -0
  327. package/dist/__tests__/visibility-extract.integration.test.d.ts.map +1 -0
  328. package/dist/__tests__/visibility-extract.perf.test.d.ts +2 -0
  329. package/dist/__tests__/visibility-extract.perf.test.d.ts.map +1 -0
  330. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts +2 -0
  331. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts.map +1 -0
  332. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts +2 -0
  333. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts.map +1 -0
  334. package/dist/__tests__/visibility-instances.integration.test.d.ts +2 -0
  335. package/dist/__tests__/visibility-instances.integration.test.d.ts.map +1 -0
  336. package/dist/__tests__/visibility-multi-world.integration.test.d.ts +2 -0
  337. package/dist/__tests__/visibility-multi-world.integration.test.d.ts.map +1 -0
  338. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts +2 -0
  339. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts.map +1 -0
  340. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts +2 -0
  341. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts.map +1 -0
  342. package/dist/__tests__/visibility-public-surface.test-d.d.ts +2 -0
  343. package/dist/__tests__/visibility-public-surface.test-d.d.ts.map +1 -0
  344. package/dist/__tests__/visibility-resolver.unit.test.d.ts +2 -0
  345. package/dist/__tests__/visibility-resolver.unit.test.d.ts.map +1 -0
  346. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts +2 -0
  347. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts.map +1 -0
  348. package/dist/__tests__/vocabulary.unit.test.d.ts +2 -0
  349. package/dist/__tests__/vocabulary.unit.test.d.ts.map +1 -0
  350. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +2 -0
  351. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +1 -0
  352. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +2 -0
  353. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
  354. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +2 -0
  355. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +1 -0
  356. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +2 -0
  357. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +1 -0
  358. package/dist/assets/asset-decoders.d.ts +5 -0
  359. package/dist/assets/asset-decoders.d.ts.map +1 -0
  360. package/dist/assets/render-asset-port.d.ts +17 -0
  361. package/dist/assets/render-asset-port.d.ts.map +1 -0
  362. package/dist/assets/resolve-render-asset.d.ts +6 -0
  363. package/dist/assets/resolve-render-asset.d.ts.map +1 -0
  364. package/dist/authoring.d.ts +12 -0
  365. package/dist/authoring.d.ts.map +1 -0
  366. package/dist/authoring.mjs +5 -0
  367. package/dist/authoring.mjs.map +1 -0
  368. package/dist/chunk-33UF5SAO.mjs +7397 -0
  369. package/dist/chunk-33UF5SAO.mjs.map +1 -0
  370. package/dist/chunk-A5QCJSNL.mjs +29913 -0
  371. package/dist/chunk-A5QCJSNL.mjs.map +1 -0
  372. package/dist/chunk-JMSB7AR4.mjs +3 -0
  373. package/dist/chunk-JMSB7AR4.mjs.map +1 -0
  374. package/dist/chunk-LXNGO6AO.mjs +569 -0
  375. package/dist/chunk-LXNGO6AO.mjs.map +1 -0
  376. package/dist/chunk-QRXPSX4X.mjs +659 -0
  377. package/dist/chunk-QRXPSX4X.mjs.map +1 -0
  378. package/dist/chunk-YAKEQPWO.mjs +1439 -0
  379. package/dist/chunk-YAKEQPWO.mjs.map +1 -0
  380. package/dist/cluster-binner.d.ts +152 -0
  381. package/dist/cluster-binner.d.ts.map +1 -0
  382. package/dist/components/__tests__/atmosphere-red.test.d.ts +2 -0
  383. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +1 -0
  384. package/dist/components/__tests__/atmosphere.test.d.ts +2 -0
  385. package/dist/components/__tests__/atmosphere.test.d.ts.map +1 -0
  386. package/dist/components/__tests__/fog.test-d.d.ts +2 -0
  387. package/dist/components/__tests__/fog.test-d.d.ts.map +1 -0
  388. package/dist/components/__tests__/fog.test.d.ts +2 -0
  389. package/dist/components/__tests__/fog.test.d.ts.map +1 -0
  390. package/dist/components/__tests__/schema-parity.unit.test.d.ts +2 -0
  391. package/dist/components/__tests__/schema-parity.unit.test.d.ts.map +1 -0
  392. package/dist/components/__tests__/visibility-schema.unit.test.d.ts +2 -0
  393. package/dist/components/__tests__/visibility-schema.unit.test.d.ts.map +1 -0
  394. package/dist/components/atmosphere.d.ts +18 -0
  395. package/dist/components/atmosphere.d.ts.map +1 -0
  396. package/dist/components/camera.d.ts +311 -0
  397. package/dist/components/camera.d.ts.map +1 -0
  398. package/dist/components/directional-light.d.ts +76 -0
  399. package/dist/components/directional-light.d.ts.map +1 -0
  400. package/dist/components/environment.d.ts +116 -0
  401. package/dist/components/environment.d.ts.map +1 -0
  402. package/dist/components/glyph-text.d.ts +26 -0
  403. package/dist/components/glyph-text.d.ts.map +1 -0
  404. package/dist/components/index.d.ts +22 -0
  405. package/dist/components/index.d.ts.map +1 -0
  406. package/dist/components/instances.d.ts +41 -0
  407. package/dist/components/instances.d.ts.map +1 -0
  408. package/dist/components/layer.d.ts +34 -0
  409. package/dist/components/layer.d.ts.map +1 -0
  410. package/dist/components/light-helpers.d.ts +53 -0
  411. package/dist/components/light-helpers.d.ts.map +1 -0
  412. package/dist/components/mesh-filter.d.ts +24 -0
  413. package/dist/components/mesh-filter.d.ts.map +1 -0
  414. package/dist/components/mesh-renderer.d.ts +33 -0
  415. package/dist/components/mesh-renderer.d.ts.map +1 -0
  416. package/dist/components/point-light-shadow.d.ts +27 -0
  417. package/dist/components/point-light-shadow.d.ts.map +1 -0
  418. package/dist/components/point-light.d.ts +35 -0
  419. package/dist/components/point-light.d.ts.map +1 -0
  420. package/dist/components/post-process-params.d.ts +5 -0
  421. package/dist/components/post-process-params.d.ts.map +1 -0
  422. package/dist/components/scene-instance.d.ts +140 -0
  423. package/dist/components/scene-instance.d.ts.map +1 -0
  424. package/dist/components/sort-key.d.ts +44 -0
  425. package/dist/components/sort-key.d.ts.map +1 -0
  426. package/dist/components/spot-light.d.ts +81 -0
  427. package/dist/components/spot-light.d.ts.map +1 -0
  428. package/dist/components/sprite-animation.d.ts +75 -0
  429. package/dist/components/sprite-animation.d.ts.map +1 -0
  430. package/dist/components/sprite-instances.d.ts +51 -0
  431. package/dist/components/sprite-instances.d.ts.map +1 -0
  432. package/dist/components/sprite-playback-mode.d.ts +37 -0
  433. package/dist/components/sprite-playback-mode.d.ts.map +1 -0
  434. package/dist/components/sprite-region-override.d.ts +47 -0
  435. package/dist/components/sprite-region-override.d.ts.map +1 -0
  436. package/dist/components/tile-layer.d.ts +101 -0
  437. package/dist/components/tile-layer.d.ts.map +1 -0
  438. package/dist/components/tilemap.d.ts +25 -0
  439. package/dist/components/tilemap.d.ts.map +1 -0
  440. package/dist/components/visibility.d.ts +22 -0
  441. package/dist/components/visibility.d.ts.map +1 -0
  442. package/dist/construct-renderer.d.ts +2 -0
  443. package/dist/construct-renderer.d.ts.map +1 -0
  444. package/dist/construct-renderer.mjs +6 -0
  445. package/dist/construct-renderer.mjs.map +1 -0
  446. package/dist/debug-draw-glue.d.ts +56 -0
  447. package/dist/debug-draw-glue.d.ts.map +1 -0
  448. package/dist/deferred-lighting.d.ts +13 -0
  449. package/dist/deferred-lighting.d.ts.map +1 -0
  450. package/dist/dynamic-texture-store.d.ts +42 -0
  451. package/dist/dynamic-texture-store.d.ts.map +1 -0
  452. package/dist/engine-metrics.d.ts +23 -0
  453. package/dist/engine-metrics.d.ts.map +1 -0
  454. package/dist/environment/__tests__/failure-injection.test.d.ts +2 -0
  455. package/dist/environment/__tests__/failure-injection.test.d.ts.map +1 -0
  456. package/dist/environment/__tests__/generation-red.test.d.ts +2 -0
  457. package/dist/environment/__tests__/generation-red.test.d.ts.map +1 -0
  458. package/dist/environment/__tests__/generation.test.d.ts +2 -0
  459. package/dist/environment/__tests__/generation.test.d.ts.map +1 -0
  460. package/dist/environment/__tests__/graph-transaction.test.d.ts +2 -0
  461. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +1 -0
  462. package/dist/environment/__tests__/inspection-red.test.d.ts +2 -0
  463. package/dist/environment/__tests__/inspection-red.test.d.ts.map +1 -0
  464. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +2 -0
  465. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +1 -0
  466. package/dist/environment/__tests__/pipeline-topology.test.d.ts +2 -0
  467. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +1 -0
  468. package/dist/environment/__tests__/readiness.test.d.ts +2 -0
  469. package/dist/environment/__tests__/readiness.test.d.ts.map +1 -0
  470. package/dist/environment/__tests__/recovery.test.d.ts +2 -0
  471. package/dist/environment/__tests__/recovery.test.d.ts.map +1 -0
  472. package/dist/environment/__tests__/resize-dispose.test.d.ts +2 -0
  473. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +1 -0
  474. package/dist/environment/__tests__/signature-red.test.d.ts +2 -0
  475. package/dist/environment/__tests__/signature-red.test.d.ts.map +1 -0
  476. package/dist/environment/__tests__/signature.test.d.ts +2 -0
  477. package/dist/environment/__tests__/signature.test.d.ts.map +1 -0
  478. package/dist/environment/descriptors.d.ts +2 -0
  479. package/dist/environment/descriptors.d.ts.map +1 -0
  480. package/dist/environment/extracted-environment.d.ts +53 -0
  481. package/dist/environment/extracted-environment.d.ts.map +1 -0
  482. package/dist/environment/generation.d.ts +62 -0
  483. package/dist/environment/generation.d.ts.map +1 -0
  484. package/dist/environment/gpu-bundle.d.ts +23 -0
  485. package/dist/environment/gpu-bundle.d.ts.map +1 -0
  486. package/dist/environment/graph.d.ts +108 -0
  487. package/dist/environment/graph.d.ts.map +1 -0
  488. package/dist/environment/inspection.d.ts +48 -0
  489. package/dist/environment/inspection.d.ts.map +1 -0
  490. package/dist/environment/lifecycle.d.ts +22 -0
  491. package/dist/environment/lifecycle.d.ts.map +1 -0
  492. package/dist/environment/readiness.d.ts +29 -0
  493. package/dist/environment/readiness.d.ts.map +1 -0
  494. package/dist/environment/signature.d.ts +70 -0
  495. package/dist/environment/signature.d.ts.map +1 -0
  496. package/dist/errors/ecs-validation.d.ts +3 -0
  497. package/dist/errors/ecs-validation.d.ts.map +1 -0
  498. package/dist/errors/index.d.ts +4 -0
  499. package/dist/errors/index.d.ts.map +1 -0
  500. package/dist/errors/recover.d.ts +78 -0
  501. package/dist/errors/recover.d.ts.map +1 -0
  502. package/dist/errors/render.d.ts +633 -0
  503. package/dist/errors/render.d.ts.map +1 -0
  504. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +2 -0
  505. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +1 -0
  506. package/dist/extract/__tests__/environment-source.test.d.ts +2 -0
  507. package/dist/extract/__tests__/environment-source.test.d.ts.map +1 -0
  508. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +2 -0
  509. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +1 -0
  510. package/dist/extract/directional-csm.d.ts +129 -0
  511. package/dist/extract/directional-csm.d.ts.map +1 -0
  512. package/dist/extract/index.d.ts +5 -0
  513. package/dist/extract/index.d.ts.map +1 -0
  514. package/dist/extract/material-interface.d.ts +56 -0
  515. package/dist/extract/material-interface.d.ts.map +1 -0
  516. package/dist/extract/schema-readers.d.ts +20 -0
  517. package/dist/extract/schema-readers.d.ts.map +1 -0
  518. package/dist/extract/visibility.d.ts +26 -0
  519. package/dist/extract/visibility.d.ts.map +1 -0
  520. package/dist/features/graph-contribution.d.ts +64 -0
  521. package/dist/features/graph-contribution.d.ts.map +1 -0
  522. package/dist/features/host.d.ts +100 -0
  523. package/dist/features/host.d.ts.map +1 -0
  524. package/dist/features/index.d.ts +21 -0
  525. package/dist/features/index.d.ts.map +1 -0
  526. package/dist/features/morph/index.d.ts +3 -0
  527. package/dist/features/morph/index.d.ts.map +1 -0
  528. package/dist/features/morph/morph-bounds.d.ts +42 -0
  529. package/dist/features/morph/morph-bounds.d.ts.map +1 -0
  530. package/dist/features/morph/morph-feature.d.ts +45 -0
  531. package/dist/features/morph/morph-feature.d.ts.map +1 -0
  532. package/dist/features/prepared-gpu-work.d.ts +113 -0
  533. package/dist/features/prepared-gpu-work.d.ts.map +1 -0
  534. package/dist/features/prepared-graphics-store.d.ts +65 -0
  535. package/dist/features/prepared-graphics-store.d.ts.map +1 -0
  536. package/dist/features/prepared-graphics.d.ts +225 -0
  537. package/dist/features/prepared-graphics.d.ts.map +1 -0
  538. package/dist/features/render-graph-compute.d.ts +13 -0
  539. package/dist/features/render-graph-compute.d.ts.map +1 -0
  540. package/dist/features/render-graph-contribution.d.ts +15 -0
  541. package/dist/features/render-graph-contribution.d.ts.map +1 -0
  542. package/dist/features/render-graph-raster.d.ts +34 -0
  543. package/dist/features/render-graph-raster.d.ts.map +1 -0
  544. package/dist/features/render-graph-resources.d.ts +11 -0
  545. package/dist/features/render-graph-resources.d.ts.map +1 -0
  546. package/dist/features/scene-temporal.d.ts +45 -0
  547. package/dist/features/scene-temporal.d.ts.map +1 -0
  548. package/dist/features/taa-resolve.d.ts +21 -0
  549. package/dist/features/taa-resolve.d.ts.map +1 -0
  550. package/dist/features/targets.d.ts +32 -0
  551. package/dist/features/targets.d.ts.map +1 -0
  552. package/dist/features/types.d.ts +247 -0
  553. package/dist/features/types.d.ts.map +1 -0
  554. package/dist/frame-chain.d.ts +14 -0
  555. package/dist/frame-chain.d.ts.map +1 -0
  556. package/dist/fullscreen-post-process-pass.d.ts +178 -0
  557. package/dist/fullscreen-post-process-pass.d.ts.map +1 -0
  558. package/dist/glyph-text-layout-system.d.ts +18 -0
  559. package/dist/glyph-text-layout-system.d.ts.map +1 -0
  560. package/dist/gpu-driven/batch-topology.d.ts +124 -0
  561. package/dist/gpu-driven/batch-topology.d.ts.map +1 -0
  562. package/dist/gpu-driven/production-raster.d.ts +150 -0
  563. package/dist/gpu-driven/production-raster.d.ts.map +1 -0
  564. package/dist/gpu-driven/view-gpu.d.ts +141 -0
  565. package/dist/gpu-driven/view-gpu.d.ts.map +1 -0
  566. package/dist/gpu-driven/view-reference.d.ts +15 -0
  567. package/dist/gpu-driven/view-reference.d.ts.map +1 -0
  568. package/dist/gpu-resource-store.d.ts +294 -0
  569. package/dist/gpu-resource-store.d.ts.map +1 -0
  570. package/dist/gpu-resource.d.ts +73 -0
  571. package/dist/gpu-resource.d.ts.map +1 -0
  572. package/dist/gpu-scene-schema.d.ts +171 -0
  573. package/dist/gpu-scene-schema.d.ts.map +1 -0
  574. package/dist/gpu-scene.d.ts +81 -0
  575. package/dist/gpu-scene.d.ts.map +1 -0
  576. package/dist/gpu-stage.d.ts +4 -0
  577. package/dist/gpu-stage.d.ts.map +1 -0
  578. package/dist/gpu-texture-usage.d.ts +6 -0
  579. package/dist/gpu-texture-usage.d.ts.map +1 -0
  580. package/dist/gpu-usage.d.ts +9 -0
  581. package/dist/gpu-usage.d.ts.map +1 -0
  582. package/dist/hdrp-buffers.d.ts +213 -0
  583. package/dist/hdrp-buffers.d.ts.map +1 -0
  584. package/dist/hdrp-cluster-membership.d.ts +2 -0
  585. package/dist/hdrp-cluster-membership.d.ts.map +1 -0
  586. package/dist/hdrp-pipeline.d.ts +36 -0
  587. package/dist/hdrp-pipeline.d.ts.map +1 -0
  588. package/dist/ibl/IblPipelineCache.d.ts +274 -0
  589. package/dist/ibl/IblPipelineCache.d.ts.map +1 -0
  590. package/dist/ibl/cubemap-projection.d.ts +23 -0
  591. package/dist/ibl/cubemap-projection.d.ts.map +1 -0
  592. package/dist/ibl/face-uniforms.d.ts +65 -0
  593. package/dist/ibl/face-uniforms.d.ts.map +1 -0
  594. package/dist/ibl/skylight-bind-group.d.ts +130 -0
  595. package/dist/ibl/skylight-bind-group.d.ts.map +1 -0
  596. package/dist/index.d.ts +57 -0
  597. package/dist/index.d.ts.map +1 -0
  598. package/dist/index.mjs +5 -0
  599. package/dist/index.mjs.map +1 -0
  600. package/dist/instance-buffer-cache.d.ts +59 -0
  601. package/dist/instance-buffer-cache.d.ts.map +1 -0
  602. package/dist/internal.d.ts +74 -0
  603. package/dist/internal.d.ts.map +1 -0
  604. package/dist/internal.mjs +45 -0
  605. package/dist/internal.mjs.map +1 -0
  606. package/dist/lifecycle.d.ts +28 -0
  607. package/dist/lifecycle.d.ts.map +1 -0
  608. package/dist/light-buffer-layout.d.ts +164 -0
  609. package/dist/light-buffer-layout.d.ts.map +1 -0
  610. package/dist/materials.d.ts +50 -0
  611. package/dist/materials.d.ts.map +1 -0
  612. package/dist/mesh-material-bindings.d.ts +44 -0
  613. package/dist/mesh-material-bindings.d.ts.map +1 -0
  614. package/dist/mesh-update-errors.d.ts +71 -0
  615. package/dist/mesh-update-errors.d.ts.map +1 -0
  616. package/dist/mipmap-generator.d.ts +39 -0
  617. package/dist/mipmap-generator.d.ts.map +1 -0
  618. package/dist/param-schema-projection-census.d.ts +18 -0
  619. package/dist/param-schema-projection-census.d.ts.map +1 -0
  620. package/dist/pbr-pipeline.d.ts +253 -0
  621. package/dist/pbr-pipeline.d.ts.map +1 -0
  622. package/dist/persistent-render-scene.d.ts +158 -0
  623. package/dist/persistent-render-scene.d.ts.map +1 -0
  624. package/dist/pipeline/index.d.ts +11 -0
  625. package/dist/pipeline/index.d.ts.map +1 -0
  626. package/dist/pipeline-builder.d.ts +122 -0
  627. package/dist/pipeline-builder.d.ts.map +1 -0
  628. package/dist/pipeline-errors.d.ts +110 -0
  629. package/dist/pipeline-errors.d.ts.map +1 -0
  630. package/dist/pipeline-spec.d.ts +506 -0
  631. package/dist/pipeline-spec.d.ts.map +1 -0
  632. package/dist/plugin.d.ts +17 -0
  633. package/dist/plugin.d.ts.map +1 -0
  634. package/dist/post-process-errors.d.ts +182 -0
  635. package/dist/post-process-errors.d.ts.map +1 -0
  636. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +2 -0
  637. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +1 -0
  638. package/dist/prepare/index.d.ts +4 -0
  639. package/dist/prepare/index.d.ts.map +1 -0
  640. package/dist/prepare/prepared-graphics-resolver.d.ts +62 -0
  641. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -0
  642. package/dist/prepare/schema-readers.d.ts +11 -0
  643. package/dist/prepare/schema-readers.d.ts.map +1 -0
  644. package/dist/record/__tests__/environment-record.test.d.ts +2 -0
  645. package/dist/record/__tests__/environment-record.test.d.ts.map +1 -0
  646. package/dist/record/__tests__/frame-targets.unit.test.d.ts +2 -0
  647. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +1 -0
  648. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts +2 -0
  649. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts.map +1 -0
  650. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts +2 -0
  651. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts.map +1 -0
  652. package/dist/record/__tests__/membership-timing.unit.test.d.ts +2 -0
  653. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +1 -0
  654. package/dist/record/__tests__/render-submission.integration.test.d.ts +2 -0
  655. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +1 -0
  656. package/dist/record/__tests__/render-submission.perf.test.d.ts +2 -0
  657. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +1 -0
  658. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +2 -0
  659. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +1 -0
  660. package/dist/record/__tests__/video-texture-view.unit.test.d.ts +2 -0
  661. package/dist/record/__tests__/video-texture-view.unit.test.d.ts.map +1 -0
  662. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +2 -0
  663. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +1 -0
  664. package/dist/record/frame-lighting.d.ts +187 -0
  665. package/dist/record/frame-lighting.d.ts.map +1 -0
  666. package/dist/record/frame-observation.d.ts +38 -0
  667. package/dist/record/frame-observation.d.ts.map +1 -0
  668. package/dist/record/frame-snapshot.d.ts +429 -0
  669. package/dist/record/frame-snapshot.d.ts.map +1 -0
  670. package/dist/record/frame-targets.d.ts +53 -0
  671. package/dist/record/frame-targets.d.ts.map +1 -0
  672. package/dist/record/frame.d.ts +59 -0
  673. package/dist/record/frame.d.ts.map +1 -0
  674. package/dist/record/helpers.d.ts +101 -0
  675. package/dist/record/helpers.d.ts.map +1 -0
  676. package/dist/record/index.d.ts +15 -0
  677. package/dist/record/index.d.ts.map +1 -0
  678. package/dist/record/main-pass-geometry.d.ts +20 -0
  679. package/dist/record/main-pass-geometry.d.ts.map +1 -0
  680. package/dist/record/main-pass-material.d.ts +173 -0
  681. package/dist/record/main-pass-material.d.ts.map +1 -0
  682. package/dist/record/main-pass-skin.d.ts +46 -0
  683. package/dist/record/main-pass-skin.d.ts.map +1 -0
  684. package/dist/record/main-pass-sprite-draws.d.ts +18 -0
  685. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -0
  686. package/dist/record/main-pass-sprite.d.ts +69 -0
  687. package/dist/record/main-pass-sprite.d.ts.map +1 -0
  688. package/dist/record/main-pass.d.ts +20 -0
  689. package/dist/record/main-pass.d.ts.map +1 -0
  690. package/dist/record/material-payload.d.ts +43 -0
  691. package/dist/record/material-payload.d.ts.map +1 -0
  692. package/dist/record/material-slot-plan.d.ts +26 -0
  693. package/dist/record/material-slot-plan.d.ts.map +1 -0
  694. package/dist/record/membership-timing.d.ts +232 -0
  695. package/dist/record/membership-timing.d.ts.map +1 -0
  696. package/dist/record/mesh-ssbo.d.ts +173 -0
  697. package/dist/record/mesh-ssbo.d.ts.map +1 -0
  698. package/dist/record/shadow-caster-uniform.d.ts +8 -0
  699. package/dist/record/shadow-caster-uniform.d.ts.map +1 -0
  700. package/dist/record/shadow-pass.d.ts +125 -0
  701. package/dist/record/shadow-pass.d.ts.map +1 -0
  702. package/dist/record/shadow-submit-mode.d.ts +66 -0
  703. package/dist/record/shadow-submit-mode.d.ts.map +1 -0
  704. package/dist/record/skybox-post-pass.d.ts +33 -0
  705. package/dist/record/skybox-post-pass.d.ts.map +1 -0
  706. package/dist/record/typed-frame-graph.d.ts +13 -0
  707. package/dist/record/typed-frame-graph.d.ts.map +1 -0
  708. package/dist/record/view-ubo.d.ts +39 -0
  709. package/dist/record/view-ubo.d.ts.map +1 -0
  710. package/dist/render-data.d.ts +143 -0
  711. package/dist/render-data.d.ts.map +1 -0
  712. package/dist/render-dispatch-membership.d.ts +47 -0
  713. package/dist/render-dispatch-membership.d.ts.map +1 -0
  714. package/dist/render-graph-primitives.d.ts +424 -0
  715. package/dist/render-graph-primitives.d.ts.map +1 -0
  716. package/dist/render-pipeline-context.d.ts +289 -0
  717. package/dist/render-pipeline-context.d.ts.map +1 -0
  718. package/dist/render-pipeline-target.d.ts +16 -0
  719. package/dist/render-pipeline-target.d.ts.map +1 -0
  720. package/dist/render-pipeline.d.ts +149 -0
  721. package/dist/render-pipeline.d.ts.map +1 -0
  722. package/dist/render-scene-projection.d.ts +174 -0
  723. package/dist/render-scene-projection.d.ts.map +1 -0
  724. package/dist/render-system-extract.d.ts +1096 -0
  725. package/dist/render-system-extract.d.ts.map +1 -0
  726. package/dist/render-system-fold.d.ts +266 -0
  727. package/dist/render-system-fold.d.ts.map +1 -0
  728. package/dist/render-system.d.ts +814 -0
  729. package/dist/render-system.d.ts.map +1 -0
  730. package/dist/renderer/asset-service.d.ts +10 -0
  731. package/dist/renderer/asset-service.d.ts.map +1 -0
  732. package/dist/renderer/backend-selection.d.ts +26 -0
  733. package/dist/renderer/backend-selection.d.ts.map +1 -0
  734. package/dist/renderer/environment-classify.d.ts +6 -0
  735. package/dist/renderer/environment-classify.d.ts.map +1 -0
  736. package/dist/renderer/environment-error.d.ts +13 -0
  737. package/dist/renderer/environment-error.d.ts.map +1 -0
  738. package/dist/renderer/material/assembly.d.ts +22 -0
  739. package/dist/renderer/material/assembly.d.ts.map +1 -0
  740. package/dist/renderer/material/pipeline-projection.d.ts +91 -0
  741. package/dist/renderer/material/pipeline-projection.d.ts.map +1 -0
  742. package/dist/renderer/renderer-factory.d.ts +283 -0
  743. package/dist/renderer/renderer-factory.d.ts.map +1 -0
  744. package/dist/renderer.d.ts +771 -0
  745. package/dist/renderer.d.ts.map +1 -0
  746. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +33 -0
  747. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -0
  748. package/dist/scene-utils/collect-subtree.d.ts +11 -0
  749. package/dist/scene-utils/collect-subtree.d.ts.map +1 -0
  750. package/dist/shadow-atlas.d.ts +117 -0
  751. package/dist/shadow-atlas.d.ts.map +1 -0
  752. package/dist/ssao-buffers.d.ts +31 -0
  753. package/dist/ssao-buffers.d.ts.map +1 -0
  754. package/dist/ssao-config.d.ts +28 -0
  755. package/dist/ssao-config.d.ts.map +1 -0
  756. package/dist/ssao-data.d.ts +34 -0
  757. package/dist/ssao-data.d.ts.map +1 -0
  758. package/dist/surface-format.d.ts +10 -0
  759. package/dist/surface-format.d.ts.map +1 -0
  760. package/dist/systems/active-camera.d.ts +53 -0
  761. package/dist/systems/active-camera.d.ts.map +1 -0
  762. package/dist/systems/pass-selector.d.ts +24 -0
  763. package/dist/systems/pass-selector.d.ts.map +1 -0
  764. package/dist/systems/skin-palette-allocator.d.ts +51 -0
  765. package/dist/systems/skin-palette-allocator.d.ts.map +1 -0
  766. package/dist/systems/transparent-sort-config.d.ts +91 -0
  767. package/dist/systems/transparent-sort-config.d.ts.map +1 -0
  768. package/dist/taa-history-store.d.ts +88 -0
  769. package/dist/taa-history-store.d.ts.map +1 -0
  770. package/dist/temporal-coverage.d.ts +35 -0
  771. package/dist/temporal-coverage.d.ts.map +1 -0
  772. package/dist/temporal-frame-transaction.d.ts +92 -0
  773. package/dist/temporal-frame-transaction.d.ts.map +1 -0
  774. package/dist/temporal-inspection.d.ts +57 -0
  775. package/dist/temporal-inspection.d.ts.map +1 -0
  776. package/dist/temporal-view.d.ts +43 -0
  777. package/dist/temporal-view.d.ts.map +1 -0
  778. package/dist/tilemap/resolve-tileset-runtime.d.ts +23 -0
  779. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +1 -0
  780. package/dist/tilemap-chunk-extract-system.d.ts +142 -0
  781. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -0
  782. package/dist/typed-render-graph-primitives.d.ts +59 -0
  783. package/dist/typed-render-graph-primitives.d.ts.map +1 -0
  784. package/dist/typed-shadow-passes.d.ts +11 -0
  785. package/dist/typed-shadow-passes.d.ts.map +1 -0
  786. package/dist/urp-pipeline.d.ts +4 -0
  787. package/dist/urp-pipeline.d.ts.map +1 -0
  788. package/package.json +94 -0
  789. package/src/__tests__/analytic-sky-contract.test.ts +27 -0
  790. package/src/__tests__/analytic-sky-falsify-carriers.mjs +43 -0
  791. package/src/__tests__/analytic-sky-falsify.test.ts +94 -0
  792. package/src/__tests__/assets-runtime-handoff.integration.test.ts +36 -0
  793. package/src/__tests__/authoring-path.unit.test.ts +14 -0
  794. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +21 -0
  795. package/src/__tests__/backend-selection.integration.test.ts +11 -0
  796. package/src/__tests__/callback-inference.test-d.ts +5 -0
  797. package/src/__tests__/camera-temporal.test-d.ts +8 -0
  798. package/src/__tests__/camera-temporal.test.ts +188 -0
  799. package/src/__tests__/cluster-binner.test.ts +272 -0
  800. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +17 -0
  801. package/src/__tests__/construct-renderer-identity.unit.test.ts +10 -0
  802. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +34 -0
  803. package/src/__tests__/direct-light-snapshot.unit.test.ts +71 -0
  804. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +18 -0
  805. package/src/__tests__/environment-inspection.test.ts +45 -0
  806. package/src/__tests__/factory-contract.integration.test.ts +331 -0
  807. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +18 -0
  808. package/src/__tests__/fog-ai-user.fixture.ts +350 -0
  809. package/src/__tests__/fog-custom-render-feature.fixture.ts +33 -0
  810. package/src/__tests__/fog-custom-render-feature.integration.test.ts +76 -0
  811. package/src/__tests__/fog-inspection.integration.test.ts +127 -0
  812. package/src/__tests__/fog-owner-state.integration.test.ts +112 -0
  813. package/src/__tests__/fog-pipeline-topology.integration.test.ts +93 -0
  814. package/src/__tests__/fog-public-surface.integration.test.ts +60 -0
  815. package/src/__tests__/fog-ray-contract.integration.test.ts +73 -0
  816. package/src/__tests__/fog-source-absence.integration.test.ts +51 -0
  817. package/src/__tests__/fog-temporal.integration.test.ts +115 -0
  818. package/src/__tests__/frame-chain.unit.test.ts +26 -0
  819. package/src/__tests__/frame-observation.contract.test.ts +103 -0
  820. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +172 -0
  821. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +347 -0
  822. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +12 -0
  823. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +16 -0
  824. package/src/__tests__/gpu-driven-production.integration.test.ts +609 -0
  825. package/src/__tests__/gpu-driven-scaling.unit.test.ts +90 -0
  826. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +192 -0
  827. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +128 -0
  828. package/src/__tests__/gpu-driven-view.browser.test.ts +19 -0
  829. package/src/__tests__/gpu-driven-view.dawn.test.ts +17 -0
  830. package/src/__tests__/gpu-driven-view.unit.test.ts +455 -0
  831. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +59 -0
  832. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +27 -0
  833. package/src/__tests__/gpu-scene-render-graph-gpu.ts +309 -0
  834. package/src/__tests__/gpu-scene-render-graph.browser.test.ts +19 -0
  835. package/src/__tests__/gpu-scene-render-graph.dawn.test.ts +19 -0
  836. package/src/__tests__/gpu-scene-schema.unit.test.ts +16 -0
  837. package/src/__tests__/gpu-scene.dawn.test.ts +209 -0
  838. package/src/__tests__/gpu-scene.unit.test.ts +161 -0
  839. package/src/__tests__/hdrp-pipeline.unit.test.ts +100 -0
  840. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +23 -0
  841. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +124 -0
  842. package/src/__tests__/injection-kind-owner.test-d.ts +14 -0
  843. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +719 -0
  844. package/src/__tests__/light-buffer-layout.unit.test.ts +85 -0
  845. package/src/__tests__/material-contract-inventory.unit.test.ts +24 -0
  846. package/src/__tests__/material-cooked-projection.unit.test.ts +177 -0
  847. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +69 -0
  848. package/src/__tests__/material-derived-payload.integration.test.ts +164 -0
  849. package/src/__tests__/material-snapshot-mutation.integration.test.ts +58 -0
  850. package/src/__tests__/material-static-dynamic-route.unit.test.ts +113 -0
  851. package/src/__tests__/material-stride-surface.unit.test.ts +32 -0
  852. package/src/__tests__/materials.unit.test.ts +25 -0
  853. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +107 -0
  854. package/src/__tests__/mesh-material-bindings.unit.test.ts +89 -0
  855. package/src/__tests__/mesh-stride-surface.unit.test.ts +16 -0
  856. package/src/__tests__/morph-culling-reentry.dawn.test.ts +166 -0
  857. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +78 -0
  858. package/src/__tests__/morph-visual-evidence.integration.test.ts +66 -0
  859. package/src/__tests__/nineslice-handle-surface.unit.test.ts +14 -0
  860. package/src/__tests__/param-schema-projection-census.unit.test.ts +40 -0
  861. package/src/__tests__/persistent-render-scene.unit.test.ts +1311 -0
  862. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +167 -0
  863. package/src/__tests__/pipeline-pass-trace.test.ts +92 -0
  864. package/src/__tests__/pipeline-stage-owner.test-d.ts +13 -0
  865. package/src/__tests__/plugin.test.ts +25 -0
  866. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +208 -0
  867. package/src/__tests__/prepared-buffer-kind-owner.test-d.ts +29 -0
  868. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +129 -0
  869. package/src/__tests__/prepared-graphics-capability.unit.test.ts +140 -0
  870. package/src/__tests__/prepared-graphics-generation.unit.test.ts +175 -0
  871. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +206 -0
  872. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +29 -0
  873. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +180 -0
  874. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +287 -0
  875. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +105 -0
  876. package/src/__tests__/prepared-graphics-store.unit.test.ts +154 -0
  877. package/src/__tests__/prepared-graphics-validation.unit.test.ts +176 -0
  878. package/src/__tests__/profiler-default-off.test.ts +22 -0
  879. package/src/__tests__/profiler-phase-catalog.test.ts +66 -0
  880. package/src/__tests__/profiler-phase-integration.test.ts +70 -0
  881. package/src/__tests__/profiler-phase-token.test.ts +84 -0
  882. package/src/__tests__/public-pipeline-id.test-d.ts +6 -0
  883. package/src/__tests__/public-surface.test-d.ts +32 -0
  884. package/src/__tests__/recover-error-policy-owner.unit.test.ts +127 -0
  885. package/src/__tests__/render-dispatch-membership.unit.test.ts +117 -0
  886. package/src/__tests__/render-error-code-owner.test-d.ts +115 -0
  887. package/src/__tests__/render-error-detail-ssot.test-d.ts +234 -0
  888. package/src/__tests__/render-error-exhaustive.test-d.ts +84 -0
  889. package/src/__tests__/render-feature-assembly.test-d.ts +51 -0
  890. package/src/__tests__/render-feature-construction.unit.test.ts +124 -0
  891. package/src/__tests__/render-feature-context.test-d.ts +81 -0
  892. package/src/__tests__/render-feature-contract.test-d.ts +58 -0
  893. package/src/__tests__/render-feature-diagnostics.unit.test.ts +151 -0
  894. package/src/__tests__/render-feature-docs.unit.test.ts +88 -0
  895. package/src/__tests__/render-feature-error-code-owner.test-d.ts +27 -0
  896. package/src/__tests__/render-feature-errors.unit.test.ts +47 -0
  897. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +46 -0
  898. package/src/__tests__/render-feature-gpu-work.integration.test.ts +377 -0
  899. package/src/__tests__/render-feature-graph.integration.test.ts +205 -0
  900. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +200 -0
  901. package/src/__tests__/render-feature-order.unit.test.ts +66 -0
  902. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +101 -0
  903. package/src/__tests__/render-feature-prepared-errors.test-d.ts +82 -0
  904. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +141 -0
  905. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +122 -0
  906. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +59 -0
  907. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +107 -0
  908. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +96 -0
  909. package/src/__tests__/render-feature-prepared-graphics.unit.test.ts +121 -0
  910. package/src/__tests__/render-feature-public-surface.test-d.ts +75 -0
  911. package/src/__tests__/render-feature-retry.unit.test.ts +128 -0
  912. package/src/__tests__/render-feature-scheduling.unit.test.ts +122 -0
  913. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +146 -0
  914. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +236 -0
  915. package/src/__tests__/render-feature-staging.unit.test.ts +94 -0
  916. package/src/__tests__/render-feature-visibility-context.test-d.ts +38 -0
  917. package/src/__tests__/render-feature-visibility-context.unit.test.ts +38 -0
  918. package/src/__tests__/render-feature-zero-work.unit.test.ts +82 -0
  919. package/src/__tests__/render-graph-compute-raster-gpu.ts +342 -0
  920. package/src/__tests__/render-graph-compute-raster.browser.test.ts +16 -0
  921. package/src/__tests__/render-graph-compute-raster.dawn.test.ts +22 -0
  922. package/src/__tests__/render-graph-hzb-gpu.ts +239 -0
  923. package/src/__tests__/render-graph-hzb.browser.test.ts +16 -0
  924. package/src/__tests__/render-graph-hzb.dawn.test.ts +23 -0
  925. package/src/__tests__/render-graph-primitives.unit.test.ts +22 -0
  926. package/src/__tests__/render-graph-storage-indirect-gpu.ts +162 -0
  927. package/src/__tests__/render-graph-storage-indirect.browser.test.ts +21 -0
  928. package/src/__tests__/render-graph-storage-indirect.dawn.test.ts +28 -0
  929. package/src/__tests__/render-scene-projection.unit.test.ts +206 -0
  930. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +125 -0
  931. package/src/__tests__/renderer-lifecycle.integration.test.ts +10 -0
  932. package/src/__tests__/renderer-render-scene-public.test-d.ts +27 -0
  933. package/src/__tests__/rhi-backend-package-boundary.unit.test.ts +11 -0
  934. package/src/__tests__/scene-temporal-coverage.unit.test.ts +259 -0
  935. package/src/__tests__/scriptable-pack-consumer.test-d.ts +14 -0
  936. package/src/__tests__/shader-stage-surface.unit.test.ts +38 -0
  937. package/src/__tests__/ssao-kernel-surface.unit.test.ts +15 -0
  938. package/src/__tests__/sun-snapshot-consumers.test.ts +35 -0
  939. package/src/__tests__/surface-backend-kind-owner.test-d.ts +42 -0
  940. package/src/__tests__/surface-configuration.unit.test.ts +92 -0
  941. package/src/__tests__/taa-history-store.unit.test.ts +196 -0
  942. package/src/__tests__/temporal-frame-transaction.integration.test.ts +537 -0
  943. package/src/__tests__/temporal-inspection.unit.test.ts +138 -0
  944. package/src/__tests__/texture-usage-surface.unit.test.ts +61 -0
  945. package/src/__tests__/typed-pipeline-topology.unit.test.ts +389 -0
  946. package/src/__tests__/urp-pipeline-targets.unit.test.ts +52 -0
  947. package/src/__tests__/urp-pipeline.unit.test.ts +14 -0
  948. package/src/__tests__/vertex-color-pipeline.unit.test.ts +124 -0
  949. package/src/__tests__/vertex-layout-consumer.unit.test.ts +25 -0
  950. package/src/__tests__/visibility-diagnostics.integration.test.ts +66 -0
  951. package/src/__tests__/visibility-extract.integration.test.ts +89 -0
  952. package/src/__tests__/visibility-extract.perf.test.ts +96 -0
  953. package/src/__tests__/visibility-feature-dedup.integration.test.ts +57 -0
  954. package/src/__tests__/visibility-hidden-report.unit.test.ts +37 -0
  955. package/src/__tests__/visibility-instances.integration.test.ts +50 -0
  956. package/src/__tests__/visibility-multi-world.integration.test.ts +54 -0
  957. package/src/__tests__/visibility-producer-matrix.integration.test.ts +191 -0
  958. package/src/__tests__/visibility-producer-matrix.unit.test.ts +96 -0
  959. package/src/__tests__/visibility-public-surface.test-d.ts +26 -0
  960. package/src/__tests__/visibility-resolver.unit.test.ts +84 -0
  961. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +59 -0
  962. package/src/__tests__/vocabulary.unit.test.ts +21 -0
  963. package/src/assets/__tests__/asset-decoders.unit.test.ts +92 -0
  964. package/src/assets/__tests__/mipmap-generator.unit.test.ts +52 -0
  965. package/src/assets/__tests__/render-asset-port.unit.test.ts +54 -0
  966. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +47 -0
  967. package/src/assets/asset-decoders.ts +158 -0
  968. package/src/assets/render-asset-port.ts +44 -0
  969. package/src/assets/resolve-render-asset.ts +13 -0
  970. package/src/authoring.ts +24 -0
  971. package/src/cluster-binner.ts +700 -0
  972. package/src/components/__tests__/atmosphere-red.test.ts +51 -0
  973. package/src/components/__tests__/atmosphere.test.ts +79 -0
  974. package/src/components/__tests__/fog.test-d.ts +49 -0
  975. package/src/components/__tests__/fog.test.ts +60 -0
  976. package/src/components/__tests__/schema-parity.unit.test.ts +25 -0
  977. package/src/components/__tests__/visibility-schema.unit.test.ts +35 -0
  978. package/src/components/atmosphere.ts +64 -0
  979. package/src/components/camera.ts +512 -0
  980. package/src/components/directional-light.ts +120 -0
  981. package/src/components/environment.ts +206 -0
  982. package/src/components/glyph-text.ts +63 -0
  983. package/src/components/index.ts +49 -0
  984. package/src/components/instances.ts +207 -0
  985. package/src/components/layer.ts +69 -0
  986. package/src/components/light-helpers.ts +188 -0
  987. package/src/components/mesh-filter.ts +59 -0
  988. package/src/components/mesh-renderer.ts +61 -0
  989. package/src/components/point-light-shadow.ts +43 -0
  990. package/src/components/point-light.ts +65 -0
  991. package/src/components/post-process-params.ts +35 -0
  992. package/src/components/scene-instance.ts +193 -0
  993. package/src/components/sort-key.ts +75 -0
  994. package/src/components/spot-light.ts +124 -0
  995. package/src/components/sprite-animation.ts +169 -0
  996. package/src/components/sprite-instances.ts +179 -0
  997. package/src/components/sprite-playback-mode.ts +73 -0
  998. package/src/components/sprite-region-override.ts +106 -0
  999. package/src/components/tile-layer.ts +161 -0
  1000. package/src/components/tilemap.ts +48 -0
  1001. package/src/components/visibility.ts +53 -0
  1002. package/src/construct-renderer.ts +4 -0
  1003. package/src/debug-draw-glue.ts +169 -0
  1004. package/src/deferred-lighting.ts +92 -0
  1005. package/src/dynamic-texture-store.ts +111 -0
  1006. package/src/engine-metrics.ts +89 -0
  1007. package/src/environment/README.md +76 -0
  1008. package/src/environment/__tests__/failure-injection.test.ts +50 -0
  1009. package/src/environment/__tests__/generation-red.test.ts +64 -0
  1010. package/src/environment/__tests__/generation.test.ts +37 -0
  1011. package/src/environment/__tests__/graph-transaction.test.ts +85 -0
  1012. package/src/environment/__tests__/inspection-red.test.ts +53 -0
  1013. package/src/environment/__tests__/lifecycle-evidence.test.ts +40 -0
  1014. package/src/environment/__tests__/pipeline-topology.test.ts +33 -0
  1015. package/src/environment/__tests__/readiness.test.ts +42 -0
  1016. package/src/environment/__tests__/recovery.test.ts +62 -0
  1017. package/src/environment/__tests__/resize-dispose.test.ts +30 -0
  1018. package/src/environment/__tests__/signature-red.test.ts +45 -0
  1019. package/src/environment/__tests__/signature.test.ts +60 -0
  1020. package/src/environment/descriptors.ts +7 -0
  1021. package/src/environment/extracted-environment.ts +239 -0
  1022. package/src/environment/generation.ts +158 -0
  1023. package/src/environment/gpu-bundle.ts +144 -0
  1024. package/src/environment/graph.ts +588 -0
  1025. package/src/environment/inspection.ts +107 -0
  1026. package/src/environment/lifecycle.ts +124 -0
  1027. package/src/environment/readiness.ts +76 -0
  1028. package/src/environment/signature.ts +185 -0
  1029. package/src/errors/ecs-validation.ts +16 -0
  1030. package/src/errors/index.ts +3 -0
  1031. package/src/errors/recover.ts +119 -0
  1032. package/src/errors/render.ts +1244 -0
  1033. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +391 -0
  1034. package/src/extract/__tests__/environment-source.test.ts +105 -0
  1035. package/src/extract/__tests__/schema-readers.unit.test.ts +16 -0
  1036. package/src/extract/directional-csm.ts +959 -0
  1037. package/src/extract/index.ts +10 -0
  1038. package/src/extract/material-interface.ts +604 -0
  1039. package/src/extract/schema-readers.ts +27 -0
  1040. package/src/extract/visibility.ts +120 -0
  1041. package/src/features/graph-contribution.ts +577 -0
  1042. package/src/features/host.ts +1097 -0
  1043. package/src/features/index.ts +100 -0
  1044. package/src/features/morph/index.ts +24 -0
  1045. package/src/features/morph/morph-bounds.ts +123 -0
  1046. package/src/features/morph/morph-feature.ts +287 -0
  1047. package/src/features/prepared-gpu-work.ts +902 -0
  1048. package/src/features/prepared-graphics-store.ts +435 -0
  1049. package/src/features/prepared-graphics.ts +479 -0
  1050. package/src/features/render-graph-compute.ts +60 -0
  1051. package/src/features/render-graph-contribution.ts +95 -0
  1052. package/src/features/render-graph-raster.ts +308 -0
  1053. package/src/features/render-graph-resources.ts +36 -0
  1054. package/src/features/scene-temporal.ts +274 -0
  1055. package/src/features/taa-resolve.ts +244 -0
  1056. package/src/features/targets.ts +83 -0
  1057. package/src/features/types.ts +291 -0
  1058. package/src/frame-chain.ts +21 -0
  1059. package/src/fullscreen-post-process-pass.ts +406 -0
  1060. package/src/glyph-text-layout-system.ts +447 -0
  1061. package/src/gpu-driven/batch-topology.ts +423 -0
  1062. package/src/gpu-driven/production-raster.ts +1705 -0
  1063. package/src/gpu-driven/view-gpu.ts +849 -0
  1064. package/src/gpu-driven/view-reference.ts +110 -0
  1065. package/src/gpu-resource-store.ts +1921 -0
  1066. package/src/gpu-resource.ts +159 -0
  1067. package/src/gpu-scene-schema.ts +224 -0
  1068. package/src/gpu-scene.ts +855 -0
  1069. package/src/gpu-stage.ts +9 -0
  1070. package/src/gpu-texture-usage.ts +12 -0
  1071. package/src/gpu-usage.ts +14 -0
  1072. package/src/hdrp-buffers.ts +689 -0
  1073. package/src/hdrp-cluster-membership.ts +70 -0
  1074. package/src/hdrp-pipeline.ts +525 -0
  1075. package/src/ibl/IblPipelineCache.ts +1246 -0
  1076. package/src/ibl/cubemap-projection.ts +60 -0
  1077. package/src/ibl/face-uniforms.ts +150 -0
  1078. package/src/ibl/skylight-bind-group.ts +513 -0
  1079. package/src/index.ts +271 -0
  1080. package/src/instance-buffer-cache.ts +123 -0
  1081. package/src/internal.ts +88 -0
  1082. package/src/lifecycle.ts +123 -0
  1083. package/src/light-buffer-layout.ts +346 -0
  1084. package/src/materials.ts +236 -0
  1085. package/src/mesh-material-bindings.ts +104 -0
  1086. package/src/mesh-update-errors.ts +113 -0
  1087. package/src/mipmap-generator.ts +244 -0
  1088. package/src/param-schema-projection-census.ts +73 -0
  1089. package/src/pbr-pipeline.ts +749 -0
  1090. package/src/persistent-render-scene.ts +1752 -0
  1091. package/src/pipeline/index.ts +40 -0
  1092. package/src/pipeline-builder.ts +386 -0
  1093. package/src/pipeline-errors.ts +172 -0
  1094. package/src/pipeline-spec.ts +1768 -0
  1095. package/src/plugin.ts +137 -0
  1096. package/src/post-process-errors.ts +304 -0
  1097. package/src/prepare/__tests__/schema-readers.unit.test.ts +16 -0
  1098. package/src/prepare/index.ts +8 -0
  1099. package/src/prepare/prepared-graphics-resolver.ts +455 -0
  1100. package/src/prepare/schema-readers.ts +20 -0
  1101. package/src/record/__tests__/environment-record.test.ts +35 -0
  1102. package/src/record/__tests__/frame-targets.unit.test.ts +54 -0
  1103. package/src/record/__tests__/material-bg-cache.unit.test.ts +41 -0
  1104. package/src/record/__tests__/material-slot-plan.unit.test.ts +76 -0
  1105. package/src/record/__tests__/membership-timing.unit.test.ts +524 -0
  1106. package/src/record/__tests__/render-submission.integration.test.ts +76 -0
  1107. package/src/record/__tests__/render-submission.perf.test.ts +141 -0
  1108. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +88 -0
  1109. package/src/record/__tests__/video-texture-view.unit.test.ts +90 -0
  1110. package/src/record/__tests__/view-ubo-layout.unit.test.ts +101 -0
  1111. package/src/record/frame-lighting.ts +1183 -0
  1112. package/src/record/frame-observation.ts +122 -0
  1113. package/src/record/frame-snapshot.ts +515 -0
  1114. package/src/record/frame-targets.ts +372 -0
  1115. package/src/record/frame.ts +1874 -0
  1116. package/src/record/helpers.ts +289 -0
  1117. package/src/record/index.ts +15 -0
  1118. package/src/record/main-pass-geometry.ts +1014 -0
  1119. package/src/record/main-pass-material.ts +716 -0
  1120. package/src/record/main-pass-skin.ts +51 -0
  1121. package/src/record/main-pass-sprite-draws.ts +1056 -0
  1122. package/src/record/main-pass-sprite.ts +166 -0
  1123. package/src/record/main-pass.ts +588 -0
  1124. package/src/record/material-payload.ts +292 -0
  1125. package/src/record/material-slot-plan.ts +68 -0
  1126. package/src/record/membership-timing.ts +1012 -0
  1127. package/src/record/mesh-ssbo.ts +406 -0
  1128. package/src/record/shadow-caster-uniform.ts +37 -0
  1129. package/src/record/shadow-pass.ts +2387 -0
  1130. package/src/record/shadow-submit-mode.ts +277 -0
  1131. package/src/record/skybox-post-pass.ts +594 -0
  1132. package/src/record/typed-frame-graph.ts +499 -0
  1133. package/src/record/view-ubo.ts +206 -0
  1134. package/src/render-data.ts +385 -0
  1135. package/src/render-dispatch-membership.ts +155 -0
  1136. package/src/render-graph-primitives.ts +1586 -0
  1137. package/src/render-pipeline-context.ts +332 -0
  1138. package/src/render-pipeline-target.ts +96 -0
  1139. package/src/render-pipeline.ts +343 -0
  1140. package/src/render-scene-projection.ts +1738 -0
  1141. package/src/render-system-extract.ts +5203 -0
  1142. package/src/render-system-fold.ts +531 -0
  1143. package/src/render-system.ts +3258 -0
  1144. package/src/renderer/asset-service.ts +32 -0
  1145. package/src/renderer/backend-selection.ts +121 -0
  1146. package/src/renderer/environment-classify.ts +30 -0
  1147. package/src/renderer/environment-error.ts +19 -0
  1148. package/src/renderer/material/assembly.ts +53 -0
  1149. package/src/renderer/material/pipeline-projection.ts +140 -0
  1150. package/src/renderer/renderer-factory.ts +9062 -0
  1151. package/src/renderer.ts +940 -0
  1152. package/src/scene-instances/post-spawn-resolve-joints.ts +168 -0
  1153. package/src/scene-utils/collect-subtree.ts +40 -0
  1154. package/src/shadow-atlas.ts +244 -0
  1155. package/src/ssao-buffers.ts +175 -0
  1156. package/src/ssao-config.ts +61 -0
  1157. package/src/ssao-data.ts +106 -0
  1158. package/src/surface-format.ts +37 -0
  1159. package/src/systems/active-camera.ts +116 -0
  1160. package/src/systems/pass-selector.ts +49 -0
  1161. package/src/systems/skin-palette-allocator.ts +294 -0
  1162. package/src/systems/transparent-sort-config.ts +211 -0
  1163. package/src/taa-history-store.ts +429 -0
  1164. package/src/temporal-coverage.ts +106 -0
  1165. package/src/temporal-frame-transaction.ts +301 -0
  1166. package/src/temporal-inspection.ts +194 -0
  1167. package/src/temporal-view.ts +174 -0
  1168. package/src/tilemap/resolve-tileset-runtime.ts +72 -0
  1169. package/src/tilemap-chunk-extract-system.ts +1307 -0
  1170. package/src/typed-render-graph-primitives.ts +530 -0
  1171. package/src/typed-shadow-passes.ts +195 -0
  1172. package/src/urp-pipeline.ts +340 -0
@@ -0,0 +1,1768 @@
1
+ // PipelineSpec 4-axis SSOT — single-file type + derive-fn + entrypoint + error model.
2
+ //
3
+ // feat-20260615-pipeline-spec-ssot M1: Establish PipelineSpec 4-axis type SSOT.
4
+ // M1-T1: type definitions + KNOWN_PASS_KINDS + PipelineSpecError closed union.
5
+ // M1-T2: 6 pure derive functions.
6
+ // M1-T3: deriveBglShapeFromShader helper.
7
+ // M1-T4: getOrBuildPipeline entrypoint + PipelineCache.
8
+ // M1-T5: 12 SPEC_CONST boot-time table.
9
+ //
10
+ // Design axiom: PipelineSpec is business-agnostic — no 'pbr' / 'sprite' / 'skybox'
11
+ // / 'fullscreen-*' strings appear on the type surface (plan-strategy D-7).
12
+ // BGL shape taxonomy lives in ShaderRegistry internal reflection, not in spec.
13
+ //
14
+ // Charter alignment:
15
+ // F1: single file entrypoint (getOrBuildPipeline) — AI user indexes once
16
+ // P1: progressive disclosure — types at top, fns mid, error model bottom
17
+ // P3: explicit failure — closed PipelineSpecError union, no silent routes
18
+ // P4: consistent abstraction — 4-axis aligns with wgpu/Bevy/Three.js
19
+
20
+ import {
21
+ deriveVertexBufferLayout,
22
+ deriveVertexLayoutProjection,
23
+ type VertexLayoutProjection,
24
+ } from '@forgeax/engine-geometry';
25
+ import {
26
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
27
+ DEFAULT_UNLIT_PARAM_SCHEMA,
28
+ type RegisteredMaterialShaderEntry,
29
+ type ShaderRegistry,
30
+ } from '@forgeax/engine-shader';
31
+ import {
32
+ type BindGroupLayoutEntry,
33
+ type DerivedMaterialInterface,
34
+ derive,
35
+ KNOWN_PASS_KINDS,
36
+ type MaterialRenderState,
37
+ type ParamSchemaEntry,
38
+ type PrimitiveTopology,
39
+ type VertexAttributeMap,
40
+ } from '@forgeax/engine-types';
41
+ import { GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX } from './gpu-stage';
42
+ import { createHdrpBindGroupLayoutDescriptor } from './hdrp-buffers';
43
+ import {
44
+ appendInjection,
45
+ buildPbrMaterialUserRegionEntries,
46
+ buildPbrViewBglEntries,
47
+ type PbrCaps,
48
+ } from './pbr-pipeline';
49
+
50
+ const DEFAULT_STANDARD_PBR_PROJECTION = derive(DEFAULT_STANDARD_PBR_PARAM_SCHEMA);
51
+ const DEFAULT_UNLIT_PROJECTION = derive(DEFAULT_UNLIT_PARAM_SCHEMA);
52
+
53
+ // Re-export KNOWN_PASS_KINDS from @forgeax/engine-types for single-file discoverability (charter F1).
54
+ export { KNOWN_PASS_KINDS };
55
+
56
+ /**
57
+ * The engine-owned deferred material target layout. `fs_gbuffer` returns
58
+ * normal+roughness, albedo+metallic, and emissive+AO in this order.
59
+ */
60
+ export const DEFERRED_COLOR_FORMATS: readonly GPUTextureFormat[] = [
61
+ 'rgba16float',
62
+ 'rgba8unorm',
63
+ 'rgba16float',
64
+ ];
65
+
66
+ /** Derive the color attachment shape for a material pass kind. */
67
+ export function colorFormatsForPassKind(
68
+ passKind: string,
69
+ defaultColorFormat: GPUTextureFormat,
70
+ ): readonly GPUTextureFormat[] {
71
+ if (passKind === 'shadow-caster') return [];
72
+ if (passKind === 'deferred') return DEFERRED_COLOR_FORMATS;
73
+ return [defaultColorFormat];
74
+ }
75
+
76
+ // ══════════════════════════════════════════════════════════════════════════════
77
+ // PipelineSpec — immutable 4-axis data description (D-7: business-agnostic)
78
+ // ══════════════════════════════════════════════════════════════════════════════
79
+
80
+ /**
81
+ * Pipeline specification — immutable 4-axis data that completely determines
82
+ * what `device.createRenderPipeline(...)` does for a material shader pass.
83
+ *
84
+ * The 4 axes are:
85
+ * - `shader`: which WGSL source + material param schema + pass kind + variant set
86
+ * - `attachments`: color/depth/stencil formats + sample count (MSAA)
87
+ * - `geometry`: primitive topology + vertex attribute layout + index format
88
+ * - `renderState`: optional per-material render-state overrides (blend/cull/depth/stencil)
89
+ *
90
+ * Business-agnostic: no `'pbr'` / `'sprite'` / `'skybox'` strings pollute this
91
+ * type. BGL shape taxonomy is derived from `ShaderRegistry` internal reflection
92
+ * and never appears on the spec surface (plan-strategy D-7).
93
+ *
94
+ * @see plan-strategy §1 (4-axis) · D-7 (business-agnostic) · requirements §3.1
95
+ */
96
+ export interface PipelineSpec {
97
+ /** Shader identity + routing axis. */
98
+ readonly shader: {
99
+ /** Registered shader identifier (e.g. `'forgeax::default-standard-pbr'`). */
100
+ readonly id: string;
101
+ /** Pass kind for attachment shape selection. Must be in {@link KNOWN_PASS_KINDS} or registered. */
102
+ readonly passKind: string;
103
+ /** Shader variant set string (e.g. `'SKIN_AVAILABLE=1'`). `undefined` for no variant. */
104
+ readonly variantSet: string | undefined;
105
+ /** Fragment entry point; omitted means the shader's standard `fs_main`. */
106
+ readonly fragmentEntry?: string | undefined;
107
+ };
108
+ /** Attachment format + sample-count axis. */
109
+ readonly attachments: {
110
+ /** Colour attachment formats in draw order. Empty for depth-only passes (shadow-caster). */
111
+ readonly colorFormats: readonly GPUTextureFormat[];
112
+ /** Depth-stencil format, or `undefined` when no depth target is bound. */
113
+ readonly depthFormat: GPUTextureFormat | undefined;
114
+ /** Sample count: 1 (no MSAA) or 4 (4x MSAA). */
115
+ readonly sampleCount: 1 | 4;
116
+ };
117
+ /** Geometry layout axis. */
118
+ readonly geometry: {
119
+ /** Primitive topology baked into the PSO. */
120
+ readonly topology: PrimitiveTopology;
121
+ /** Strip index format (uint16 / uint32), only meaningful for strip topologies. */
122
+ readonly stripIndexFormat?: 'uint16' | 'uint32' | undefined;
123
+ /** Per-vertex attribute layout (position / normal / uv / tangent / skinIndex / skinWeight). */
124
+ readonly vertexLayout: VertexAttributeMap;
125
+ /** Canonical geometry-owned projection; derived when omitted for legacy callers. */
126
+ readonly vertexLayoutProjection?: VertexLayoutProjection | undefined;
127
+ /**
128
+ * Number of UV sets declared by the shader (derived from @location reflection).
129
+ * Forwarded to deriveVertexBufferLayout for clamp-to-last alias (D-1 / D-4).
130
+ * Undefined = fallback to mesh-provided UV count (no clamping).
131
+ * feat-20260629-multi-uv-set-support m3-w5: plumbed placeholder.
132
+ * TODO(M4/m4-w3): fill from naga reflection JSON when available.
133
+ */
134
+ readonly shaderUvSetCount?: number | undefined;
135
+ };
136
+ /** Per-material render-state overrides (optional — engine defaults applied when absent). */
137
+ readonly renderState: MaterialRenderState | undefined;
138
+ }
139
+
140
+ // ══════════════════════════════════════════════════════════════════════════════
141
+ // PipelineSpecError — closed union (5 + 2 transit codes)
142
+ // ══════════════════════════════════════════════════════════════════════════════
143
+
144
+ /**
145
+ * Closed union of PipelineSpec error codes.
146
+ *
147
+ * 5 business codes:
148
+ * - `'spec-inconsistent'`: axis mutual exclusion violated
149
+ * - `'unknown-pass-kind'`: passKind not in KNOWN_PASS_KINDS or registered
150
+ * - `'shader-bgl-reflection-mismatch'`: reflected BGL shape != shader declaration
151
+ * - `'attachment-format-incompatible'`: depth/stencil format vs PSO mismatch
152
+ * - `'unsupported-vertex-layout'`: vertex attributes don't match shader vs_main
153
+ *
154
+ * 2 transit codes:
155
+ * - `'pipeline-build-failed'`: wraps RhiError from device.createRenderPipeline
156
+ * - `'shader-not-registered'`: ShaderRegistry.lookup returned undefined
157
+ *
158
+ * @see requirements §3.4 · AC-10 · charter P3
159
+ */
160
+ export type PipelineSpecErrorCode =
161
+ | 'spec-inconsistent'
162
+ | 'unknown-pass-kind'
163
+ | 'shader-bgl-reflection-mismatch'
164
+ | 'attachment-format-incompatible'
165
+ | 'unsupported-vertex-layout'
166
+ | 'pipeline-build-failed'
167
+ | 'shader-not-registered';
168
+
169
+ /**
170
+ * Structured pipeline-spec error — carries `.code` (discriminated union) +
171
+ * `.detail` (narrowed per code) + `.hint` (AI-user actionable prose).
172
+ *
173
+ * Inherits from `Error` so it integrates with existing catch blocks; the
174
+ * `.code` field enables exhaustive `switch` narrowing without string parsing
175
+ * (charter P3).
176
+ */
177
+ export class PipelineSpecError extends Error {
178
+ readonly code: PipelineSpecErrorCode;
179
+ /**
180
+ * Narrowed detail payload — shape depends on `code`.
181
+ *
182
+ * - `'spec-inconsistent'`: `{ reason: string }`
183
+ * - `'unknown-pass-kind'`: `{ expected: readonly string[]; actual: string; hint?: string }`
184
+ * - `'shader-bgl-reflection-mismatch'`: `{ reflected: unknown; declared: unknown }`
185
+ * - `'attachment-format-incompatible'`: `{ reason: string; expected?: string; actual?: string }`
186
+ * - `'unsupported-vertex-layout'`: `{ specAttrs: string[]; shaderAttrs: string[] }`
187
+ * - `'pipeline-build-failed'`: `{ gpuMessage?: string; cause?: unknown }`
188
+ * - `'shader-not-registered'`: `{ shaderId: string; hint?: string }`
189
+ */
190
+ readonly detail: Record<string, unknown>;
191
+
192
+ constructor(args: {
193
+ code: PipelineSpecErrorCode;
194
+ detail: Record<string, unknown>;
195
+ hint?: string;
196
+ }) {
197
+ super(
198
+ args.hint !== undefined
199
+ ? `PipelineSpecError [${args.code}]: ${args.hint}`
200
+ : `PipelineSpecError [${args.code}]`,
201
+ );
202
+ this.name = 'PipelineSpecError';
203
+ this.code = args.code;
204
+ this.detail = args.detail;
205
+ }
206
+ }
207
+
208
+ // ══════════════════════════════════════════════════════════════════════════════
209
+ // BindGroupLayoutShape — reflection-derived BGL descriptor
210
+ // ══════════════════════════════════════════════════════════════════════════════
211
+
212
+ /**
213
+ * Bind group layout shape derived from ShaderRegistry reflection.
214
+ *
215
+ * `entries` mirrors `GPUBindGroupLayoutDescriptor.entries` — the binding
216
+ * slot layout the shader expects for a given variantSet.
217
+ */
218
+ export interface BindGroupLayoutShape {
219
+ readonly entries: readonly BindGroupLayoutEntry[];
220
+ }
221
+
222
+ // ══════════════════════════════════════════════════════════════════════════════
223
+ // deriveBglShapeFromShader — reflection helper (D-1)
224
+ // ══════════════════════════════════════════════════════════════════════════════
225
+
226
+ /**
227
+ * Derive BGL shape from a registered shader entry's paramSchema.
228
+ *
229
+ * Pure function: same `entry` always yields the same shape (no variant-set
230
+ * dispatch — that role moved into `BglKind` after D-13's closed-union
231
+ * dispatch landed; see plan-decisions.md). The `_variantSet` parameter is
232
+ * preserved for backward signature compat but ignored — variant routing is
233
+ * now explicit at the BglKind level (see `buildBindGroupLayoutDescriptor`
234
+ * arms `pbr-skin-mesh-array` vs `hdrp-7-slot` vs `pbr-mesh-array`).
235
+ *
236
+ * This helper lives in `pipeline-spec.ts` (not ShaderRegistry) per D-1:
237
+ * it wraps the existing `derive(paramSchema).bglEntries` from
238
+ * `@forgeax/engine-types` so cacheKeyOf can hash BGL shape deterministically
239
+ * without expanding the ShaderRegistry public interface.
240
+ *
241
+ * @param entry - material shader entry from ShaderRegistry.findMaterialArtifact
242
+ * @param _variantSet - unused (post D-13); kept for backward signature compat
243
+ * @returns the BGL shape for the given entry
244
+ * @see plan-decisions.md D-13
245
+ */
246
+ export function deriveBglShapeFromShader(
247
+ entry: RegisteredMaterialShaderEntry,
248
+ _variantSet?: string | undefined,
249
+ ): BindGroupLayoutShape {
250
+ // derive() from @forgeax/engine-types is the actual SSOT; we invoke it
251
+ // here so that cacheKeyOf can hash BGL shape deterministically.
252
+ return {
253
+ entries: entry.paramSchemaProjection.derivedInterface.bglEntries,
254
+ };
255
+ }
256
+
257
+ // ══════════════════════════════════════════════════════════════════════════════
258
+ // renderStateHashSuffix — deterministic hash of MaterialRenderState
259
+ // ══════════════════════════════════════════════════════════════════════════════
260
+
261
+ /**
262
+ * Material snapshots hand the renderer immutable render-state objects. Keep
263
+ * the serialized suffix by object identity just like the vertex-layout
264
+ * digest below; the hot path otherwise sorts keys and serializes the same
265
+ * state once per renderable. Callers must not mutate a MaterialRenderState
266
+ * after passing it to the renderer (the PipelineSpec contract is immutable).
267
+ */
268
+ const RENDER_STATE_HASH_CACHE = new WeakMap<object, string>();
269
+
270
+ /**
271
+ * Deterministic hash suffix for MaterialRenderState (sorted keys, JSON.stringify).
272
+ *
273
+ * Returns `''` when `renderState` is `undefined` or has zero entries,
274
+ * preserving cache-key byte-compatibility with the pre-M1 shape.
275
+ */
276
+ export function renderStateHash(renderState: MaterialRenderState | undefined): string {
277
+ if (renderState === undefined) return '';
278
+ const cached = RENDER_STATE_HASH_CACHE.get(renderState);
279
+ if (cached !== undefined) return cached;
280
+ const sorted = Object.keys(renderState).sort();
281
+ if (sorted.length === 0) {
282
+ RENDER_STATE_HASH_CACHE.set(renderState, '');
283
+ return '';
284
+ }
285
+ const payload: Record<string, unknown> = {};
286
+ for (const k of sorted) {
287
+ const v = renderState[k as keyof MaterialRenderState];
288
+ if (v !== undefined) payload[k] = v;
289
+ }
290
+ const result = `:${JSON.stringify(payload)}`;
291
+ RENDER_STATE_HASH_CACHE.set(renderState, result);
292
+ return result;
293
+ }
294
+
295
+ // ══════════════════════════════════════════════════════════════════════════════
296
+ // 6 pure derive functions (M1-T2)
297
+ // ══════════════════════════════════════════════════════════════════════════════
298
+
299
+ /**
300
+ * Compute a deterministic cache key from a PipelineSpec.
301
+ *
302
+ * The key covers all 4 axes + BGL shape hash (derived from ShaderRegistry
303
+ * reflection via {@link deriveBglShapeFromShader}). Two specs that produce
304
+ * the same cache key MUST produce byte-identical PSO descriptors.
305
+ *
306
+ * Algorithm: concatenate each axis segment with `:` separators, hash the
307
+ * BGL shape for compactness, and emit a single cache-key string.
308
+ *
309
+ * @see plan-strategy §3.1 · requirements AC-02
310
+ */
311
+ export function cacheKeyOf(spec: PipelineSpec): string {
312
+ const { shader, attachments, geometry, renderState } = spec;
313
+ const topoSegment = geometry.topology;
314
+ const stripSegment =
315
+ (topoSegment === 'line-strip' || topoSegment === 'triangle-strip') &&
316
+ geometry.stripIndexFormat !== undefined
317
+ ? `:${geometry.stripIndexFormat}`
318
+ : '';
319
+
320
+ // Hash vertexLayout deterministically — the digest is identity-cached for
321
+ // immutable mesh-asset maps reused across submeshes and frames.
322
+ const vlDigest =
323
+ geometry.vertexLayoutProjection?.digest ??
324
+ deriveVertexLayoutProjection(geometry.vertexLayout).digest;
325
+
326
+ const uvSetCountSegment =
327
+ geometry.shaderUvSetCount !== undefined ? `:uvsc${geometry.shaderUvSetCount}` : '';
328
+
329
+ // bug-20260708 M2 (b): sentinel `~` distinguishes `variantSet=undefined`
330
+ // (no-variant / default-variant request) from canonical all-true key `''`
331
+ // (all variant axes true). Prior `?? ''` collapsed the two into the same
332
+ // cache key, causing the first-cached pipeline to win and unrelated
333
+ // variantSet requests to reuse its shader module (research R-11 / R-12).
334
+ // `~` (ASCII 0x7E) is a reserved sentinel char — no legitimate
335
+ // variantSet literal contains it; guarded by
336
+ // `pipeline-cache-keying.unit.test.ts` sentinel-conflict assertions.
337
+ const variantSegment = shader.variantSet === undefined ? '~' : shader.variantSet;
338
+ const fragmentEntrySegment = shader.fragmentEntry ?? 'fs_main';
339
+ return (
340
+ [
341
+ shader.id,
342
+ shader.passKind,
343
+ variantSegment,
344
+ fragmentEntrySegment,
345
+ attachments.colorFormats.join(','),
346
+ attachments.depthFormat ?? '',
347
+ String(attachments.sampleCount),
348
+ topoSegment,
349
+ stripSegment,
350
+ `vl:${vlDigest}`,
351
+ renderStateHash(renderState),
352
+ ].join(':') + uvSetCountSegment
353
+ );
354
+ }
355
+
356
+ /**
357
+ * Build a `GPURenderPipelineDescriptor` from a PipelineSpec + shader modules.
358
+ *
359
+ * Pure derivation: same (spec, modules) always produces the same descriptor.
360
+ * Consumed by `getOrBuildPipeline` on cache miss; also available as a public
361
+ * helper for AI users who want the descriptor shape without going through the
362
+ * cache entrypoint.
363
+ *
364
+ * @param spec - the pipeline spec (4 axes)
365
+ * @param modules - `{ vertex: GPUShaderModule; fragment: GPUShaderModule }`
366
+ * @returns a complete WebGPU render-pipeline descriptor
367
+ * @see plan-strategy §3.2 · requirements AC-02
368
+ */
369
+ export function buildPipelineDescriptor(
370
+ spec: PipelineSpec,
371
+ modules: {
372
+ vertex: unknown;
373
+ fragment: unknown;
374
+ vertexEntryPoint?: string;
375
+ fragmentEntryPoint?: string;
376
+ layout?: unknown;
377
+ },
378
+ ): Record<string, unknown> {
379
+ // M2-T4: derive vertex buffers from spec.geometry.vertexLayout via
380
+ // deriveVertexBufferLayout (imported from vertex-attribute-layout.ts).
381
+ // Empty vertexLayout (fullscreen-post passes) → [].
382
+ // Non-empty (material shaders) → interleaved single-buffer layout.
383
+ //
384
+ // Entry points default to 'vs_main' / 'fs_main' for the 3 standard material
385
+ // shaders; fullscreen-post passes (skybox 'skybox_fs', SSAO 'vs_ssao' / 'fs_ssao_calc')
386
+ // pass custom entry points through the modules parameter.
387
+ //
388
+ // The optional `layout` field, when present, is forwarded to the descriptor
389
+ // so that the provider can detect it is already set and avoid overwriting.
390
+
391
+ const { attachments, geometry, renderState } = spec;
392
+
393
+ const isShadowCaster = spec.shader.passKind === 'shadow-caster';
394
+ const isStrip = geometry.topology === 'line-strip' || geometry.topology === 'triangle-strip';
395
+
396
+ // A supplied projection is already the geometry owner's immutable GPU
397
+ // descriptor. Do not re-derive it from the caller's attribute map: that
398
+ // would permit a stale map to disagree with the uploaded interleaved bytes.
399
+ // Legacy callers without a projection retain the UV aliasing derivation.
400
+ const vertexBuffers =
401
+ geometry.vertexLayoutProjection === undefined
402
+ ? deriveVertexBufferLayout(geometry.vertexLayout, {
403
+ ...(geometry.shaderUvSetCount !== undefined
404
+ ? { shaderUvSetCount: geometry.shaderUvSetCount }
405
+ : {}),
406
+ })
407
+ : geometry.vertexLayoutProjection.attributes.length === 0
408
+ ? []
409
+ : [
410
+ {
411
+ arrayStride: geometry.vertexLayoutProjection.arrayStride,
412
+ attributes: geometry.vertexLayoutProjection.attributes.map(
413
+ ({ shaderLocation, offset, format }) => ({
414
+ shaderLocation,
415
+ offset,
416
+ format,
417
+ }),
418
+ ),
419
+ },
420
+ ];
421
+
422
+ const descriptor: Record<string, unknown> = {
423
+ vertex: {
424
+ module: modules.vertex,
425
+ entryPoint: modules.vertexEntryPoint ?? 'vs_main',
426
+ buffers: vertexBuffers,
427
+ },
428
+ };
429
+
430
+ // Fragment stage: absent for shadow-caster (depth-only), present for forward.
431
+ if (!isShadowCaster && attachments.colorFormats.length > 0) {
432
+ descriptor.fragment = {
433
+ module: modules.fragment,
434
+ entryPoint: modules.fragmentEntryPoint ?? 'fs_main',
435
+ targets: attachments.colorFormats.map((fmt) => {
436
+ const target: Record<string, unknown> = { format: fmt };
437
+ if (renderState?.blend !== undefined) {
438
+ target.blend = renderState.blend;
439
+ }
440
+ return target;
441
+ }),
442
+ };
443
+ }
444
+
445
+ // Layout: forward if provided by caller (fullscreen-post passes set it).
446
+ if (modules.layout !== undefined) {
447
+ descriptor.layout = modules.layout;
448
+ }
449
+
450
+ // Primitive state.
451
+ const primitive: Record<string, unknown> = {
452
+ topology: geometry.topology,
453
+ cullMode: renderState?.cullMode ?? 'back',
454
+ frontFace: renderState?.frontFace ?? 'ccw',
455
+ };
456
+ if (isStrip && geometry.stripIndexFormat !== undefined) {
457
+ primitive.stripIndexFormat = geometry.stripIndexFormat;
458
+ }
459
+ descriptor.primitive = primitive;
460
+
461
+ // Depth-stencil state.
462
+ if (attachments.depthFormat !== undefined) {
463
+ const ds: Record<string, unknown> = {
464
+ format: attachments.depthFormat,
465
+ depthWriteEnabled: renderState?.depthWriteEnabled ?? true,
466
+ depthCompare: renderState?.depthCompare ?? 'less',
467
+ };
468
+ if (renderState?.stencilReadMask !== undefined) {
469
+ ds.stencilReadMask = renderState.stencilReadMask;
470
+ }
471
+ if (renderState?.stencilWriteMask !== undefined) {
472
+ ds.stencilWriteMask = renderState.stencilWriteMask;
473
+ }
474
+ if (renderState?.stencil !== undefined) {
475
+ ds.stencilFront = renderState.stencil;
476
+ ds.stencilBack = renderState.stencil;
477
+ }
478
+ descriptor.depthStencil = ds;
479
+ }
480
+
481
+ // Multisample: absent for sampleCount=1 (undefined). For any value > 1,
482
+ // emit { count: sampleCount } so forward-compat sample counts (2, 8, …)
483
+ // flow through to the descriptor without requiring a type change.
484
+ if (attachments.sampleCount > 1) {
485
+ descriptor.multisample = {
486
+ count: attachments.sampleCount,
487
+ ...(renderState?.alphaToCoverageEnabled === true && { alphaToCoverageEnabled: true }),
488
+ };
489
+ }
490
+
491
+ return descriptor;
492
+ }
493
+
494
+ // ══════════════════════════════════════════════════════════════════════════════
495
+ // BglKind dispatch (M3 / D-13) — closed union of BGL shapes the runtime ships
496
+ // ══════════════════════════════════════════════════════════════════════════════
497
+
498
+ /**
499
+ * Closed union of bind-group-layout shapes the runtime constructs.
500
+ *
501
+ * Each kind names one physically distinct BGL the runtime has historically
502
+ * built by hand. {@link buildBindGroupLayoutDescriptor} dispatches on this
503
+ * union so every `device.createBindGroupLayout(...)` call site shares one
504
+ * SSOT for entries / labels (plan-strategy §3.2; D-13 round-2 decision).
505
+ *
506
+ * Three groups by derivation source:
507
+ * 1. Shader-derived (paramSchema reflection + injection chain):
508
+ * - `'pbr-material-merged'` — derived user region + Skylight 7 + lightmap 4
509
+ * - `'unlit-material'` — 7 entries: base PBR material only (no inject)
510
+ * - `'hdrp-7-slot'` — 7 entries (binding 0 + 3..8): HDRP cluster + SSAO group(2) BGL
511
+ * 2. Caps-driven literal shapes (no shader):
512
+ * - `'pbr-view'` — 10 entries: view UBO + lights + 6 shadow bindings
513
+ * (directional 3/4, point 5/6, cascade 7, spot atlas 8, spot
514
+ * lightViewProj matrices 9 — feat-20260625)
515
+ * - `'pbr-mesh-array'` — 1 entry: per-entity mesh SSBO (dynamic-offset)
516
+ * - `'pbr-instances'` — 1 entry: per-instance SSBO (no dynamic-offset)
517
+ * - `'pbr-skin-mesh-array'` — 3 entries: meshes + current/previous skin palettes
518
+ * 3. Attachment-driven (fullscreen post-process):
519
+ * - `'fullscreen-post'` — 2 entries: input texture + sampler. The texture
520
+ * `sampleType` is derived from `spec.attachments` (plan §R3 fix):
521
+ * `'depth32float'` → `'depth'`; `'r32float'` → `'unfilterable-float'`;
522
+ * else → `'float'`.
523
+ * - `'fullscreen-post-with-params'` — 3 entries: the same texture@0 +
524
+ * sampler@1 as `'fullscreen-post'`, plus a `buffer@2` uniform for the
525
+ * per-frame params UBO (feat-20260621 D-2: `entry.params !== undefined`
526
+ * passes route here; the layout stays group(1), q3=B). `'fullscreen-post'`
527
+ * stays byte-identical so param-less consumers degrade with no change.
528
+ * - `'fullscreen-post-with-scene-depth-msaa'` — the depth-read layout with
529
+ * `texture.multisampled=true`, selected for a 4-sample scene depth target.
530
+ */
531
+ export type BglKind =
532
+ | 'pbr-view'
533
+ | 'pbr-material-merged'
534
+ | 'pbr-mesh-array'
535
+ | 'pbr-instances'
536
+ | 'pbr-skin-mesh-array'
537
+ | 'unlit-material'
538
+ | 'hdrp-7-slot'
539
+ | 'fullscreen-post'
540
+ | 'fullscreen-post-with-params'
541
+ | 'fullscreen-post-with-scene-depth'
542
+ | 'fullscreen-post-with-scene-depth-msaa'
543
+ | 'fullscreen-post-with-gbuffer-depth';
544
+
545
+ /**
546
+ * Output shape of {@link buildBindGroupLayoutDescriptor}: matches the RHI
547
+ * `BindGroupLayoutDescriptor` (label + entries with `ExplicitUndefined`) so
548
+ * the result can be passed directly to `device.createBindGroupLayout(...)`.
549
+ *
550
+ * `entries` is a mutable `Array` to match `GPUBindGroupLayoutDescriptor`
551
+ * (WebGPU types declare it mutable). Callers MUST treat the array as
552
+ * read-only — the dispatcher freezes neither the array nor its entries
553
+ * for hot-path performance.
554
+ */
555
+ export interface BindGroupLayoutDescriptorOutput {
556
+ readonly label: string | undefined;
557
+ readonly entries: GPUBindGroupLayoutEntry[];
558
+ }
559
+
560
+ /**
561
+ * Build a `GPUBindGroupLayoutDescriptor` from a PipelineSpec, dispatching on
562
+ * `options.kind` to one of 9 closed BGL shapes (D-13 round-2).
563
+ *
564
+ * Shader-derived kinds (`'pbr-material-merged'` / `'unlit-material'` /
565
+ * `'hdrp-7-slot'`) require `options.registry` to look up the shader entry
566
+ * and reflect its `paramSchema` via {@link deriveBglShapeFromShader}; they
567
+ * compose the per-entry injection chain (Skylight + lightmap for material;
568
+ * HDRP variantSet for cluster-forward).
569
+ *
570
+ * Caps-driven kinds (`'pbr-view'` / `'pbr-mesh-array'` / `'pbr-instances'` /
571
+ * `'pbr-skin-mesh-array'`) require `options.caps` for the storage-buffer
572
+ * vs uniform-buffer fallback (RhiCaps.storageBuffer; PBR feat-20260526 M3 /
573
+ * w9). They are wholly determined by the caps shape.
574
+ *
575
+ * Attachment-driven kind (`'fullscreen-post'`) reads
576
+ * `spec.attachments.depthFormat` and `spec.attachments.colorFormats[0]` to
577
+ * pick the texture binding's `sampleType` (R3 fix: `'depth32float'` → `'depth'`,
578
+ * `'r32float'` → `'unfilterable-float'`, else → `'float'`).
579
+ *
580
+ * @param spec - the pipeline spec (axis source for reflection / caps fallback)
581
+ * @param options.kind - which BGL shape to build (closed {@link BglKind} union)
582
+ * @param options.registry - ShaderRegistry for shader-derived kinds
583
+ * @param options.caps - caps shape for caps-driven kinds (storageBuffer)
584
+ * @returns a WebGPU bind-group-layout descriptor (entries + label)
585
+ * @see plan-strategy §3.2 · plan-decisions D-13 · requirements AC-02
586
+ */
587
+ /**
588
+ * Resolve the material paramSchema for a per-shader user-region BGL derivation.
589
+ *
590
+ * Priority (D-1): explicit `options.materialParamSchema` > registry lookup of
591
+ * `spec.shader.id` > `undefined` (the user-region builder then falls back to
592
+ * the built-in standard-PBR 4-texture schema, whose user region is 9 entries).
593
+ */
594
+ function resolveMaterialProjection(
595
+ spec: PipelineSpec,
596
+ options: { registry?: ShaderRegistry; materialParamSchema?: readonly ParamSchemaEntry[] },
597
+ ): DerivedMaterialInterface | undefined {
598
+ if (options.registry !== undefined) {
599
+ const lookup = options.registry.findMaterialArtifact(spec.shader.id);
600
+ if (lookup.ok) return lookup.value.paramSchemaProjection.derivedInterface;
601
+ }
602
+ // Compatibility seam for callers that have not reached ShaderRegistry
603
+ // admission yet. Runtime registry callers always take the branch above.
604
+ if (options.materialParamSchema !== undefined) return derive(options.materialParamSchema);
605
+ return undefined;
606
+ }
607
+
608
+ export function buildBindGroupLayoutDescriptor(
609
+ spec: PipelineSpec,
610
+ options: {
611
+ kind: BglKind;
612
+ registry?: ShaderRegistry;
613
+ caps?: PbrCaps;
614
+ /**
615
+ * Material paramSchema for the per-shader user-region derivation
616
+ * (`'pbr-material-merged'` / `'unlit-material'`). When supplied it is the
617
+ * authoritative source for the user-region BGL shape (D-1); when omitted,
618
+ * `buildPbrMaterialUserRegionEntries` falls back to the built-in
619
+ * standard-PBR 4-texture schema (user region is 9 entries), so
620
+ * the caps-driven `buildPbrPipelineLayouts` seam keeps working unchanged.
621
+ * A registry + resolvable shader id takes precedence over this field.
622
+ */
623
+ materialParamSchema?: readonly ParamSchemaEntry[];
624
+ },
625
+ ): BindGroupLayoutDescriptorOutput {
626
+ switch (options.kind) {
627
+ case 'pbr-view': {
628
+ const caps = options.caps ?? { storageBuffer: true };
629
+ return {
630
+ label: 'pbr-view-bgl',
631
+ entries: buildPbrViewBglEntries(caps),
632
+ };
633
+ }
634
+ case 'pbr-mesh-array': {
635
+ const caps = options.caps ?? { storageBuffer: true };
636
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
637
+ ? 'read-only-storage'
638
+ : 'uniform';
639
+ // sprite-lit's fragment stage does not read the mesh SSBO -- worldPos
640
+ // is carried through the VsOut interpolant. Visibility is kept widened
641
+ // to VERTEX|FRAGMENT because the BGL JSON is compared byte-identically
642
+ // across the sprite / sprite-lit / PBR pipelines that share this
643
+ // descriptor; narrowing here would change every sibling pipeline's
644
+ // BGL fingerprint. WebGPU rejects createRenderPipeline when a fragment
645
+ // stage accesses a binding whose BGL visibility excludes FRAGMENT --
646
+ // widening is permissive (validation-only, no perf cost).
647
+ return {
648
+ label: 'pbr-mesh-array-bgl',
649
+ entries: [
650
+ {
651
+ binding: 0,
652
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
653
+ buffer: { type: meshBufType, hasDynamicOffset: true },
654
+ },
655
+ ],
656
+ };
657
+ }
658
+ case 'pbr-instances': {
659
+ const caps = options.caps ?? { storageBuffer: true };
660
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
661
+ ? 'read-only-storage'
662
+ : 'uniform';
663
+ return {
664
+ label: 'pbr-instances-bgl',
665
+ entries: [
666
+ {
667
+ binding: 0,
668
+ visibility: GPU_SHADER_STAGE_VERTEX,
669
+ buffer: { type: meshBufType, hasDynamicOffset: false },
670
+ },
671
+ ],
672
+ };
673
+ }
674
+ case 'pbr-skin-mesh-array': {
675
+ const caps = options.caps ?? { storageBuffer: true };
676
+ const meshBufType: GPUBufferBindingType = caps.storageBuffer
677
+ ? 'read-only-storage'
678
+ : 'uniform';
679
+ return {
680
+ label: 'pbr-skin-mesh-array-bgl',
681
+ entries: [
682
+ {
683
+ binding: 0,
684
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
685
+ buffer: { type: meshBufType, hasDynamicOffset: true },
686
+ },
687
+ {
688
+ binding: 1,
689
+ visibility: GPU_SHADER_STAGE_VERTEX,
690
+ buffer: { type: meshBufType, hasDynamicOffset: true },
691
+ },
692
+ {
693
+ binding: 2,
694
+ visibility: GPU_SHADER_STAGE_VERTEX,
695
+ buffer: { type: meshBufType, hasDynamicOffset: true },
696
+ },
697
+ ],
698
+ };
699
+ }
700
+ case 'pbr-material-merged': {
701
+ // Material BGL: per-shader user-region (derive(paramSchema).bglEntries)
702
+ // + IBL injection (7). Emissive and occlusion are material texture
703
+ // parameters in the derived user-region; they are not a second
704
+ // engine-owned lightmap ledger.
705
+ //
706
+ // Schema source priority (D-1): explicit materialParamSchema option >
707
+ // registry lookup of spec.shader.id > built-in standard-PBR fallback.
708
+ const resolvedProjection =
709
+ resolveMaterialProjection(spec, options) ?? DEFAULT_STANDARD_PBR_PROJECTION;
710
+ const userRegion = buildPbrMaterialUserRegionEntries(resolvedProjection);
711
+ const afterIbl = [...userRegion, ...appendInjection(userRegion, 'ibl')];
712
+ return {
713
+ label: 'pbr-material-skylight-bgl',
714
+ entries: afterIbl,
715
+ };
716
+ }
717
+ case 'unlit-material': {
718
+ // Unlit material BGL: per-shader user-region only. No IBL/lightmap
719
+ // injection (D-5 round-4: unlit demos do not pay for IBL state).
720
+ const resolvedProjection =
721
+ resolveMaterialProjection(spec, options) ?? DEFAULT_UNLIT_PROJECTION;
722
+ return {
723
+ label: 'unlit-material-bgl',
724
+ entries: buildPbrMaterialUserRegionEntries(resolvedProjection),
725
+ };
726
+ }
727
+ case 'hdrp-7-slot': {
728
+ // HDRP unified BGL for group(2): 9 entries (binding 0 + 3..8). The
729
+ // shape depends on caps.storageBuffer for the cluster-buffer fallback.
730
+ const caps = options.caps ?? { storageBuffer: true };
731
+ const desc = createHdrpBindGroupLayoutDescriptor(caps.storageBuffer);
732
+ if (options.registry !== undefined) {
733
+ const lookup = options.registry.findMaterialArtifact(spec.shader.id);
734
+ if (lookup.ok) {
735
+ deriveBglShapeFromShader(lookup.value, spec.shader.variantSet);
736
+ }
737
+ }
738
+ return {
739
+ label: desc.label ?? 'hdrp-unified-bgl-group2',
740
+ entries: desc.entries ?? [],
741
+ };
742
+ }
743
+ case 'fullscreen-post': {
744
+ // Fullscreen post-process BGL: 2 entries (input texture + sampler).
745
+ // R3 fix: derive sampleType from spec.attachments. Depth attachments
746
+ // (depth32float) need `sampleType: 'depth'`; r32float needs
747
+ // `'unfilterable-float'`; everything else (rgba8unorm-srgb, rgba16float,
748
+ // bgra8unorm, …) is filterable `'float'`.
749
+ return {
750
+ label: 'fullscreen-post-bgl',
751
+ entries: buildFullscreenPostInputEntries(spec),
752
+ };
753
+ }
754
+ case 'fullscreen-post-with-params': {
755
+ // feat-20260621 D-2: the same input texture@0 + sampler@1 as
756
+ // 'fullscreen-post', plus binding 2 = per-frame params UBO (uniform).
757
+ // The first two entries reuse buildFullscreenPostInputEntries so the
758
+ // sampleType derivation stays a single SSOT; 'fullscreen-post' is
759
+ // untouched (param-less zero-regression, R-A7).
760
+ return {
761
+ label: 'fullscreen-post-with-params-bgl',
762
+ entries: [
763
+ ...buildFullscreenPostInputEntries(spec),
764
+ {
765
+ binding: 2,
766
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
767
+ buffer: { type: 'uniform' },
768
+ },
769
+ ],
770
+ };
771
+ }
772
+ case 'fullscreen-post-with-scene-depth': {
773
+ // plan-strategy D-3: 5-entry BGL for post-process passes that read the
774
+ // camera scene depth. color@0 + sampler@1 reuse buildFullscreenPostInputEntries
775
+ // (float+filtering for color). depthTex@3 uses `sampleType: 'depth'` and
776
+ // `dimension: '2d'`; depthSampler@4 uses `type: 'non-filtering'` (nearest
777
+ // + clamp-to-edge, D-2 — NOT comparison). params@2 is always present
778
+ // (uniform) to avoid a 2x2 kind explosion per D-3.
779
+ return {
780
+ label: 'fullscreen-post-with-scene-depth-bgl',
781
+ entries: [
782
+ ...buildFullscreenPostInputEntries(spec),
783
+ {
784
+ binding: 2,
785
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
786
+ buffer: { type: 'uniform' },
787
+ },
788
+ {
789
+ binding: 3,
790
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
791
+ texture: { sampleType: 'depth', viewDimension: '2d' },
792
+ },
793
+ {
794
+ binding: 4,
795
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
796
+ sampler: { type: 'non-filtering' },
797
+ },
798
+ ],
799
+ };
800
+ }
801
+ case 'fullscreen-post-with-scene-depth-msaa': {
802
+ return {
803
+ label: 'fullscreen-post-with-scene-depth-msaa-bgl',
804
+ entries: [
805
+ ...buildFullscreenPostInputEntries(spec),
806
+ {
807
+ binding: 2,
808
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
809
+ buffer: { type: 'uniform' },
810
+ },
811
+ {
812
+ binding: 3,
813
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
814
+ texture: { sampleType: 'depth', viewDimension: '2d', multisampled: true },
815
+ },
816
+ {
817
+ binding: 4,
818
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
819
+ sampler: { type: 'non-filtering' },
820
+ },
821
+ ],
822
+ };
823
+ }
824
+ case 'fullscreen-post-with-gbuffer-depth': {
825
+ return {
826
+ label: 'fullscreen-post-with-gbuffer-depth-bgl',
827
+ entries: [
828
+ ...buildFullscreenPostInputEntries(spec),
829
+ {
830
+ binding: 2,
831
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
832
+ buffer: { type: 'uniform' },
833
+ },
834
+ {
835
+ binding: 3,
836
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
837
+ texture: { sampleType: 'depth', viewDimension: '2d' },
838
+ },
839
+ {
840
+ binding: 4,
841
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
842
+ sampler: { type: 'non-filtering' },
843
+ },
844
+ {
845
+ binding: 5,
846
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
847
+ texture: { sampleType: 'float', viewDimension: '2d' },
848
+ },
849
+ {
850
+ binding: 6,
851
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
852
+ texture: { sampleType: 'float', viewDimension: '2d' },
853
+ },
854
+ ],
855
+ };
856
+ }
857
+ }
858
+ }
859
+
860
+ /**
861
+ * The shared texture@0 + sampler@1 entries for fullscreen post-process BGLs.
862
+ * sampleType is derived from `spec.attachments` (R3 fix): depth attachments →
863
+ * `'depth'` + `'comparison'` sampler; `'r32float'` → `'unfilterable-float'`;
864
+ * else → `'float'` + `'filtering'`. Both `'fullscreen-post'` and
865
+ * `'fullscreen-post-with-params'` reuse this so the derivation is one SSOT.
866
+ */
867
+ function buildFullscreenPostInputEntries(spec: PipelineSpec): GPUBindGroupLayoutEntry[] {
868
+ const inputFormat: GPUTextureFormat | undefined =
869
+ spec.attachments.depthFormat ?? spec.attachments.colorFormats[0];
870
+ const sampleType: GPUTextureSampleType =
871
+ inputFormat === 'depth32float' ||
872
+ inputFormat === 'depth24plus' ||
873
+ inputFormat === 'depth24plus-stencil8' ||
874
+ inputFormat === 'depth16unorm'
875
+ ? 'depth'
876
+ : inputFormat === 'r32float'
877
+ ? 'unfilterable-float'
878
+ : 'float';
879
+ return [
880
+ {
881
+ binding: 0,
882
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
883
+ texture: { sampleType, viewDimension: '2d' },
884
+ },
885
+ {
886
+ binding: 1,
887
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
888
+ sampler: {
889
+ type: sampleType === 'depth' ? 'comparison' : 'filtering',
890
+ },
891
+ },
892
+ ];
893
+ }
894
+
895
+ // ══════════════════════════════════════════════════════════════════════════════
896
+ // passKindPolicyTable — closed map: passKind → attachment shape + default ops
897
+ // ══════════════════════════════════════════════════════════════════════════════
898
+
899
+ /**
900
+ * Default colour-attachment ops carried by a passKind policy.
901
+ *
902
+ * `clearValue` is `undefined` for `loadOp='load'` policies (no clear value
903
+ * is emitted into the descriptor when the prior contents are loaded).
904
+ */
905
+ export interface AttachmentColorOps {
906
+ readonly loadOp: 'clear' | 'load';
907
+ readonly storeOp: 'store' | 'discard';
908
+ readonly clearValue: GPUColor | undefined;
909
+ }
910
+
911
+ /**
912
+ * Default depth-attachment ops carried by a passKind policy.
913
+ *
914
+ * `stencilLoadOp` / `stencilStoreOp` are absent on the policy itself — the
915
+ * stencil-op gate is auto-derived from `specAttachments.depthFormat` at call
916
+ * time (`'depth24plus-stencil8'` → `'clear'+'discard'`; everything else
917
+ * elides stencil ops). This collapses the R3/R5 stencil-op duplicates that
918
+ * previously lived inline at every forward-pass beginRenderPass call site.
919
+ */
920
+ export interface AttachmentDepthOps {
921
+ readonly loadOp: 'clear' | 'load';
922
+ readonly storeOp: 'store' | 'discard';
923
+ readonly clearValue: number;
924
+ }
925
+
926
+ /**
927
+ * Attachment policy for a single passKind — declares the colour / depth shape
928
+ * the pass produces and the default load/store ops. Per-call-site overrides
929
+ * (skybox vs main forward differing on `colorLoadOp`, sprite-split forward
930
+ * differing on both `colorLoadOp` and `depthLoadOp`) flow through the
931
+ * `options` parameter of {@link buildBeginRenderPassDescriptor}.
932
+ *
933
+ * `shape` discriminator drives which attachment slots the descriptor emits:
934
+ * - `'depth-only'` → empty `colorAttachments[]`, `depthStencilAttachment` set
935
+ * - `'color-only'` → populated `colorAttachments[]`, no `depthStencilAttachment`
936
+ * - `'color-and-depth'` → both
937
+ */
938
+ export interface PassKindAttachmentPolicy {
939
+ readonly shape: 'depth-only' | 'color-only' | 'color-and-depth';
940
+ readonly defaultColorOps: AttachmentColorOps | undefined;
941
+ readonly defaultDepthOps: AttachmentDepthOps | undefined;
942
+ }
943
+
944
+ /**
945
+ * Closed map of passKind → attachment policy. Covers the 10 attachment shapes
946
+ * the runtime ships (per plan-strategy M4):
947
+ *
948
+ * 1. `'forward'` — main geometry pass: color+depth(+stencil-gated)
949
+ * 2. `'deferred'` — HDRP G-Buffer geometry pass: MRT color+depth
950
+ * 3. `'shadow-caster'` — directional shadow caster: depth-only
951
+ * 4. `'point-shadow-caster'` — HDRP point-shadow caster: depth-only
952
+ * 5. `'skybox'` — fullscreen skybox: color-only clear/store
953
+ * 6. `'tonemap'` — HDR→LDR tonemap fullscreen: color-only clear/store
954
+ * 7. `'bloom-bright'` / `'bloom-blur'` — bloom downsample/blur: color-only
955
+ * clear/store
956
+ * 8. `'bloom-composite'` — bloom add-back: color-only load/store (NOT clear)
957
+ * 9. `'fxaa'` — fullscreen FXAA: color-only clear/store
958
+ * 10. `'post-process'` — generic fullscreen primitive (SSAO, render-graph
959
+ * fullscreen-post-process-pass dispatcher, M2 tonemap pre-warm slot):
960
+ * color-only clear/store
961
+ *
962
+ * Sprite-split forward sub-pass reuses the `'forward'` policy with
963
+ * `options.colorLoadOp='load'` + `options.depthLoadOp='load'`.
964
+ *
965
+ * Stencil-op gate is NOT in this table — it is derived from
966
+ * `specAttachments.depthFormat` inside the helper (depth24plus-stencil8
967
+ * → emit `stencilLoadOp:'clear' / stencilStoreOp:'discard'`).
968
+ */
969
+ export const passKindPolicyTable: Readonly<Record<string, PassKindAttachmentPolicy>> = {
970
+ forward: {
971
+ shape: 'color-and-depth',
972
+ defaultColorOps: {
973
+ loadOp: 'clear',
974
+ storeOp: 'store',
975
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
976
+ },
977
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
978
+ },
979
+ deferred: {
980
+ shape: 'color-and-depth',
981
+ defaultColorOps: {
982
+ loadOp: 'clear',
983
+ storeOp: 'store',
984
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
985
+ },
986
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
987
+ },
988
+ temporal: {
989
+ shape: 'color-and-depth',
990
+ defaultColorOps: {
991
+ loadOp: 'clear',
992
+ storeOp: 'store',
993
+ clearValue: { r: 0, g: 0, b: -1, a: 1 },
994
+ },
995
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
996
+ },
997
+ 'shadow-caster': {
998
+ shape: 'depth-only',
999
+ defaultColorOps: undefined,
1000
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
1001
+ },
1002
+ 'point-shadow-caster': {
1003
+ shape: 'depth-only',
1004
+ defaultColorOps: undefined,
1005
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
1006
+ },
1007
+ skybox: {
1008
+ shape: 'color-only',
1009
+ defaultColorOps: {
1010
+ loadOp: 'clear',
1011
+ storeOp: 'store',
1012
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1013
+ },
1014
+ defaultDepthOps: undefined,
1015
+ },
1016
+ tonemap: {
1017
+ shape: 'color-only',
1018
+ defaultColorOps: {
1019
+ loadOp: 'clear',
1020
+ storeOp: 'store',
1021
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1022
+ },
1023
+ defaultDepthOps: undefined,
1024
+ },
1025
+ 'bloom-bright': {
1026
+ shape: 'color-only',
1027
+ defaultColorOps: {
1028
+ loadOp: 'clear',
1029
+ storeOp: 'store',
1030
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1031
+ },
1032
+ defaultDepthOps: undefined,
1033
+ },
1034
+ 'bloom-blur': {
1035
+ shape: 'color-only',
1036
+ defaultColorOps: {
1037
+ loadOp: 'clear',
1038
+ storeOp: 'store',
1039
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1040
+ },
1041
+ defaultDepthOps: undefined,
1042
+ },
1043
+ 'bloom-composite': {
1044
+ shape: 'color-only',
1045
+ defaultColorOps: {
1046
+ loadOp: 'load',
1047
+ storeOp: 'store',
1048
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1049
+ },
1050
+ defaultDepthOps: undefined,
1051
+ },
1052
+ fxaa: {
1053
+ shape: 'color-only',
1054
+ defaultColorOps: {
1055
+ loadOp: 'clear',
1056
+ storeOp: 'store',
1057
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1058
+ },
1059
+ defaultDepthOps: undefined,
1060
+ },
1061
+ 'post-process': {
1062
+ shape: 'color-only',
1063
+ defaultColorOps: {
1064
+ loadOp: 'clear',
1065
+ storeOp: 'store',
1066
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
1067
+ },
1068
+ defaultDepthOps: undefined,
1069
+ },
1070
+ };
1071
+
1072
+ /**
1073
+ * Build a `GPURenderPassDescriptor` from spec attachments + resolved views +
1074
+ * a passKind policy lookup.
1075
+ *
1076
+ * The helper is the single SSOT for `device.beginRenderPass(...)` descriptor
1077
+ * shape — every record-stage call site routes through it (plan-strategy M4
1078
+ * AC-06). It dispatches on `passKindPolicyTable[passKind]` to pick the
1079
+ * attachment shape (depth-only / color-only / color-and-depth) and applies
1080
+ * default color/depth load+store ops; per-call overrides (sprite-split's
1081
+ * `loadOp:'load'`, main pass's dynamic `mainColorLoadOp`, skybox's specific
1082
+ * clearColor) flow through `options`.
1083
+ *
1084
+ * Stencil-op gate is auto-derived from `specAttachments.depthFormat`:
1085
+ * - `'depth24plus-stencil8'` → emits `stencilLoadOp:'clear', stencilStoreOp:'discard'`
1086
+ * - any other depth format → omits stencil ops entirely
1087
+ *
1088
+ * This collapses the R3/R5 stencil-op duplicates that previously lived inline
1089
+ * at every forward-pass beginRenderPass site.
1090
+ *
1091
+ * @param specAttachments - the attachments axis from a PipelineSpec
1092
+ * @param viewBindings - resolved texture views: `{ colorViews, depthView?, resolveTargets? }`
1093
+ * @param passKind - one of the keys in {@link passKindPolicyTable}
1094
+ * @param options - per-call ops overrides (loadOp / clearValue / label)
1095
+ * @returns a WebGPU render-pass descriptor
1096
+ * @throws PipelineSpecError(`'unknown-pass-kind'`) when passKind is not registered
1097
+ * @see plan-strategy M4 · requirements AC-06
1098
+ */
1099
+ export function buildBeginRenderPassDescriptor(
1100
+ specAttachments: PipelineSpec['attachments'],
1101
+ viewBindings: {
1102
+ readonly colorViews: readonly unknown[];
1103
+ readonly resolveTargets?: readonly (unknown | undefined)[];
1104
+ readonly depthView?: unknown;
1105
+ },
1106
+ passKind: string,
1107
+ options?: {
1108
+ readonly colorLoadOp?: 'clear' | 'load';
1109
+ readonly colorStoreOp?: 'store' | 'discard';
1110
+ readonly clearColor?: GPUColor;
1111
+ readonly depthLoadOp?: 'clear' | 'load';
1112
+ readonly depthStoreOp?: 'store' | 'discard';
1113
+ readonly label?: string;
1114
+ },
1115
+ ): Record<string, unknown> {
1116
+ const policy = passKindPolicyTable[passKind];
1117
+ if (policy === undefined) {
1118
+ throw new PipelineSpecError({
1119
+ code: 'unknown-pass-kind',
1120
+ detail: { expected: Object.keys(passKindPolicyTable), actual: passKind },
1121
+ hint: `passKind '${passKind}' is not in passKindPolicyTable; register an attachment policy or pick an existing one (e.g. 'post-process' for fullscreen-quad passes)`,
1122
+ });
1123
+ }
1124
+
1125
+ const out: Record<string, unknown> = {};
1126
+ if (options?.label !== undefined) {
1127
+ out.label = options.label;
1128
+ }
1129
+
1130
+ // Colour attachments: depth-only → empty array; otherwise iterate colorViews
1131
+ // and apply policy default ops + per-call overrides. resolveTargets[i] === undefined
1132
+ // means "no resolve for this slot"; only present slots emit a `resolveTarget`.
1133
+ if (policy.shape === 'depth-only') {
1134
+ out.colorAttachments = [];
1135
+ } else {
1136
+ const colorOps = policy.defaultColorOps;
1137
+ if (colorOps === undefined) {
1138
+ throw new PipelineSpecError({
1139
+ code: 'spec-inconsistent',
1140
+ detail: {
1141
+ reason: 'policy-shape-color-without-colorOps',
1142
+ actual: passKind,
1143
+ },
1144
+ hint: `passKind '${passKind}' has shape='${policy.shape}' but no defaultColorOps; fix passKindPolicyTable entry`,
1145
+ });
1146
+ }
1147
+ const loadOp = options?.colorLoadOp ?? colorOps.loadOp;
1148
+ const storeOp = options?.colorStoreOp ?? colorOps.storeOp;
1149
+ const clearValue = options?.clearColor ?? colorOps.clearValue;
1150
+
1151
+ out.colorAttachments = viewBindings.colorViews.map((view, i) => {
1152
+ const slot: Record<string, unknown> = {
1153
+ view,
1154
+ loadOp,
1155
+ storeOp,
1156
+ };
1157
+ const resolveTarget = viewBindings.resolveTargets?.[i];
1158
+ if (resolveTarget !== undefined) {
1159
+ slot.resolveTarget = resolveTarget;
1160
+ }
1161
+ // Emit clearValue only when load is 'clear' AND a value is available.
1162
+ if (loadOp === 'clear' && clearValue !== undefined) {
1163
+ slot.clearValue = clearValue;
1164
+ }
1165
+ return slot;
1166
+ });
1167
+ }
1168
+
1169
+ // Depth-stencil attachment: emitted iff policy declares depth ops AND
1170
+ // the spec carries a depthFormat. Stencil ops auto-derived from format.
1171
+ if (policy.shape !== 'color-only' && policy.defaultDepthOps !== undefined) {
1172
+ const dOps = policy.defaultDepthOps;
1173
+ const depthLoadOp = options?.depthLoadOp ?? dOps.loadOp;
1174
+ const depthStoreOp = options?.depthStoreOp ?? dOps.storeOp;
1175
+ const ds: Record<string, unknown> = {
1176
+ view: viewBindings.depthView,
1177
+ depthLoadOp,
1178
+ depthStoreOp,
1179
+ };
1180
+ if (depthLoadOp === 'clear') {
1181
+ ds.depthClearValue = dOps.clearValue;
1182
+ }
1183
+ // Stencil-op gate: only depth24plus-stencil8 carries a stencil aspect.
1184
+ if (specAttachments.depthFormat === 'depth24plus-stencil8') {
1185
+ ds.stencilClearValue = 0;
1186
+ ds.stencilLoadOp = 'clear';
1187
+ ds.stencilStoreOp = 'discard';
1188
+ }
1189
+ out.depthStencilAttachment = ds;
1190
+ }
1191
+
1192
+ return out;
1193
+ }
1194
+
1195
+ /**
1196
+ * Dev-mode equality check: two PipelineSpec instances are structurally equal
1197
+ * when every axis field is `===` (shallow compare).
1198
+ *
1199
+ * Not intended for runtime hot paths — use `cacheKeyOf(a) === cacheKeyOf(b)`
1200
+ * for cache-hit checks. This function exists for dev-time assertions
1201
+ * (`assert(specsEqual(specA, specB))`) and unit-test round-trip verification.
1202
+ *
1203
+ * @see plan-strategy §3.2 · requirements AC-02
1204
+ */
1205
+ export function specsEqual(a: PipelineSpec, b: PipelineSpec): boolean {
1206
+ if (
1207
+ a.shader.id !== b.shader.id ||
1208
+ a.shader.passKind !== b.shader.passKind ||
1209
+ a.shader.variantSet !== b.shader.variantSet ||
1210
+ a.attachments.colorFormats.length !== b.attachments.colorFormats.length ||
1211
+ !a.attachments.colorFormats.every((f, i) => f === b.attachments.colorFormats[i]) ||
1212
+ a.attachments.depthFormat !== b.attachments.depthFormat ||
1213
+ a.attachments.sampleCount !== b.attachments.sampleCount ||
1214
+ a.geometry.topology !== b.geometry.topology ||
1215
+ a.geometry.stripIndexFormat !== b.geometry.stripIndexFormat
1216
+ ) {
1217
+ return false;
1218
+ }
1219
+
1220
+ // VertexLayout: same reference or structurally equal keys + byte lengths
1221
+ if (a.geometry.vertexLayout !== b.geometry.vertexLayout) {
1222
+ const aKeys = Object.keys(a.geometry.vertexLayout).sort();
1223
+ const bKeys = Object.keys(b.geometry.vertexLayout).sort();
1224
+ if (aKeys.length !== bKeys.length || !aKeys.every((k, i) => k === bKeys[i])) return false;
1225
+ for (const k of aKeys) {
1226
+ const aBuf = a.geometry.vertexLayout[k as keyof VertexAttributeMap];
1227
+ const bBuf = b.geometry.vertexLayout[k as keyof VertexAttributeMap];
1228
+ if (aBuf === bBuf) continue;
1229
+ if (aBuf === undefined || bBuf === undefined) return false;
1230
+ if ((aBuf as ArrayBuffer).byteLength !== (bBuf as ArrayBuffer).byteLength) return false;
1231
+ }
1232
+ }
1233
+
1234
+ // RenderState: same reference or JSON-equal
1235
+ if (a.renderState !== b.renderState) {
1236
+ if (a.renderState === undefined || b.renderState === undefined) return false;
1237
+ const aSorted = Object.keys(a.renderState).sort();
1238
+ const bSorted = Object.keys(b.renderState).sort();
1239
+ if (aSorted.length !== bSorted.length || !aSorted.every((k, i) => k === bSorted[i]))
1240
+ return false;
1241
+ for (const k of aSorted) {
1242
+ if (
1243
+ a.renderState[k as keyof MaterialRenderState] !==
1244
+ b.renderState[k as keyof MaterialRenderState]
1245
+ )
1246
+ return false;
1247
+ }
1248
+ }
1249
+
1250
+ return true;
1251
+ }
1252
+
1253
+ /**
1254
+ * Validate a PipelineSpec before attempting to build.
1255
+ *
1256
+ * Fail-fast checks (charter P5) covering axis mutual-exclusion rules.
1257
+ * Returns `Result<void, PipelineSpecError>` — ok for valid specs,
1258
+ * err with structured code + detail for invalid ones.
1259
+ *
1260
+ * Checks:
1261
+ * 1. `sampleCount=4` with empty `colorFormats` → `'spec-inconsistent'`
1262
+ * 2. Pass kind not in `KNOWN_PASS_KINDS` → `'unknown-pass-kind'`
1263
+ * 3. `depthFormat` undefined but `renderState` implies depth testing →
1264
+ * `'attachment-format-incompatible'`
1265
+ *
1266
+ * @see plan-strategy §3.2 · requirements AC-02 · charter P5
1267
+ */
1268
+ export function validateSpec(
1269
+ spec: PipelineSpec,
1270
+ ):
1271
+ | { ok: true }
1272
+ | { ok: false; code: PipelineSpecErrorCode; detail: Record<string, unknown>; hint?: string } {
1273
+ // Check 1: sampleCount=4 with empty colorFormats is inconsistent —
1274
+ // multisample requires a colour target to resolve to.
1275
+ if (spec.attachments.sampleCount === 4 && spec.attachments.colorFormats.length === 0) {
1276
+ return {
1277
+ ok: false,
1278
+ code: 'spec-inconsistent',
1279
+ detail: { reason: 'sample-count-format-incompatible' },
1280
+ hint: 'sampleCount=4 requires at least one colorFormat; shadow-caster (depth-only) passes should use sampleCount=1',
1281
+ };
1282
+ }
1283
+
1284
+ // Check 2: unknown pass kind
1285
+ if (!KNOWN_PASS_KINDS.includes(spec.shader.passKind)) {
1286
+ return {
1287
+ ok: false,
1288
+ code: 'unknown-pass-kind',
1289
+ detail: { expected: KNOWN_PASS_KINDS, actual: spec.shader.passKind },
1290
+ hint: `passKind '${spec.shader.passKind}' is not in KNOWN_PASS_KINDS; register custom pass kinds via ShaderRegistry`,
1291
+ };
1292
+ }
1293
+
1294
+ // Check 3: depth-testing renderState without a depthFormat
1295
+ if (spec.attachments.depthFormat === undefined && spec.renderState?.depthCompare !== undefined) {
1296
+ return {
1297
+ ok: false,
1298
+ code: 'attachment-format-incompatible',
1299
+ detail: {
1300
+ reason: 'depth-compare-without-depth-format',
1301
+ expected: 'depthFormat must be set when renderState.depthCompare is defined',
1302
+ actual: `depthFormat=${String(spec.attachments.depthFormat)}, depthCompare=${spec.renderState.depthCompare}`,
1303
+ },
1304
+ hint: 'set attachments.depthFormat (e.g. depth24plus-stencil8 or depth32float) when renderState specifies depthCompare',
1305
+ };
1306
+ }
1307
+
1308
+ return { ok: true };
1309
+ }
1310
+
1311
+ // ══════════════════════════════════════════════════════════════════════════════
1312
+ // PipelineCache — Map<string, RenderPipeline> container (D-12)
1313
+ // ══════════════════════════════════════════════════════════════════════════════
1314
+
1315
+ /**
1316
+ * Pipeline cache — Map from cacheKeyOf(spec) to opaque RenderPipeline handle.
1317
+ *
1318
+ * Constructed once at createRenderer boot time; shared across all call sites.
1319
+ * Consumers call `getOrBuildPipeline(spec, deviceProvider, cache)` — the
1320
+ * entrypoint does cache lookup internally; consumers never touch the Map
1321
+ * directly.
1322
+ *
1323
+ * @see plan-strategy D-12 · requirements §3.2
1324
+ */
1325
+ export type PipelineCache = Map<string, unknown>;
1326
+
1327
+ // ══════════════════════════════════════════════════════════════════════════════
1328
+ // getOrBuildPipeline — single entrypoint (D-12)
1329
+ // ══════════════════════════════════════════════════════════════════════════════
1330
+
1331
+ /**
1332
+ * Device factory interface consumed by {@link getOrBuildPipeline}.
1333
+ *
1334
+ * Slim abstraction: only `createRenderPipeline` is needed; the entrypoint
1335
+ * does not depend on the full `RhiDevice` interface so it can be tested
1336
+ * with a mock.
1337
+ */
1338
+ export interface PipelineDeviceProvider {
1339
+ createRenderPipeline(
1340
+ descriptor: Record<string, unknown>,
1341
+ ): { ok: true; value: unknown } | { ok: false; error: unknown };
1342
+ }
1343
+
1344
+ /**
1345
+ * Single entrypoint for obtaining a render pipeline from a spec.
1346
+ *
1347
+ * Cache-hit path: key = cacheKeyOf(spec), returns cached handle immediately.
1348
+ * Cache-miss path: validates spec → builds descriptor → calls device.createRenderPipeline
1349
+ * → caches result → returns handle.
1350
+ * Build failure: throws PipelineSpecError (charter P3 fail-fast, no silent fallback).
1351
+ *
1352
+ * Pure function: same (spec, deviceProvider, cache) always produces the same result.
1353
+ * Boot-time call site: createRenderer wires the real device; record-stage call site
1354
+ * uses ctx.runtime.device (same entrypoint, same signature).
1355
+ *
1356
+ * @param spec - immutable 4-axis pipeline specification
1357
+ * @param deviceProvider - factory with createRenderPipeline method
1358
+ * @param cache - the PipelineCache (shared across boot + record stage)
1359
+ * @returns a RenderPipeline handle (opaque, typed as unknown for M1)
1360
+ * @throws PipelineSpecError on validation failure or build failure
1361
+ * @see plan-strategy D-12 · requirements AC-03 · charter F1
1362
+ */
1363
+ export function getOrBuildPipeline(
1364
+ spec: PipelineSpec,
1365
+ deviceProvider: PipelineDeviceProvider,
1366
+ cache: PipelineCache,
1367
+ modules?: {
1368
+ vertex: unknown;
1369
+ fragment: unknown;
1370
+ vertexEntryPoint?: string;
1371
+ fragmentEntryPoint?: string;
1372
+ layout?: unknown;
1373
+ },
1374
+ ): unknown {
1375
+ const key = cacheKeyOf(spec);
1376
+
1377
+ // Cache hit — return immediately.
1378
+ const cached = cache.get(key);
1379
+ if (cached !== undefined) return cached;
1380
+
1381
+ // Cache miss — validate, build, cache, return.
1382
+ const validation = validateSpec(spec);
1383
+ if (!validation.ok) {
1384
+ throw new PipelineSpecError({
1385
+ code: validation.code,
1386
+ detail: validation.detail,
1387
+ ...(validation.hint !== undefined ? { hint: validation.hint } : {}),
1388
+ });
1389
+ }
1390
+
1391
+ const descriptor = buildPipelineDescriptor(
1392
+ spec,
1393
+ modules ?? { vertex: undefined, fragment: undefined },
1394
+ );
1395
+ const result = deviceProvider.createRenderPipeline(descriptor);
1396
+
1397
+ if (!result.ok) {
1398
+ throw new PipelineSpecError({
1399
+ code: 'pipeline-build-failed',
1400
+ detail: { cause: result.error },
1401
+ hint: 'device.createRenderPipeline failed for spec; inspect gpuMessage on the error detail',
1402
+ });
1403
+ }
1404
+
1405
+ cache.set(key, result.value);
1406
+ return result.value;
1407
+ }
1408
+
1409
+ // ══════════════════════════════════════════════════════════════════════════════
1410
+ // SPEC_CONST_TABLE — 12 boot-time pre-warm variants (M1-T5)
1411
+ // ══════════════════════════════════════════════════════════════════════════════
1412
+
1413
+ const PROCEDURAL_ATTR_LAYOUT: VertexAttributeMap = {
1414
+ position: new Float32Array(0),
1415
+ normal: new Float32Array(0),
1416
+ uv: new Float32Array(0),
1417
+ tangent: new Float32Array(0),
1418
+ };
1419
+
1420
+ const HDR_FORMAT: GPUTextureFormat = 'rgba16float' as unknown as GPUTextureFormat;
1421
+ const DEPTH_DS: GPUTextureFormat = 'depth24plus-stencil8' as unknown as GPUTextureFormat;
1422
+
1423
+ /**
1424
+ * Default LDR view format used when callers ask for the SPEC_CONST table
1425
+ * without an explicit swap-chain format. Kept for the backward-compatible
1426
+ * `SPEC_CONST_TABLE` export consumed by unit tests that exercise the
1427
+ * spec/cache-keying layer in isolation. Runtime callers always pass the
1428
+ * format selected by `selectSwapChainFormat` (Channel 2 BGRA / Channel 3
1429
+ * RGBA / dawn-node RGBA — see bug-20260615 fix-up note in `createRenderer`).
1430
+ */
1431
+ const DEFAULT_LDR_FORMAT: GPUTextureFormat = 'bgra8unorm-srgb' as unknown as GPUTextureFormat;
1432
+
1433
+ const TRI_GEOMETRY = {
1434
+ topology: 'triangle-list' as PrimitiveTopology,
1435
+ stripIndexFormat: undefined,
1436
+ vertexLayout: PROCEDURAL_ATTR_LAYOUT,
1437
+ };
1438
+
1439
+ // feat-city-glb multi-UV tiling: the built-in standard PBR shader now declares
1440
+ // UV sets @location(6..12), so naga reflects uvSetCount=8 for it and the URP
1441
+ // record path threads `shaderUvSetCount: 8` into every standard-pbr spec
1442
+ // (createRenderer.ts buildPipelineContext / getMaterialShaderPipeline).
1443
+ // The boot-time prewarm must match on both axes: the PSO vertex layout includes
1444
+ // all declared UV slots, and the cacheKey carries `:uvsc8`. For single-UV
1445
+ // meshes deriveVertexBufferLayout clamp-to-last aliases every missing set onto
1446
+ // the last mesh set (48-byte stride unchanged), so existing geometry remains
1447
+ // byte-stable.
1448
+ // unlit stays on TRI_GEOMETRY (its shader declares only @location(0..3)).
1449
+ const TRI_GEOMETRY_PBR = {
1450
+ topology: 'triangle-list' as PrimitiveTopology,
1451
+ stripIndexFormat: undefined,
1452
+ vertexLayout: PROCEDURAL_ATTR_LAYOUT,
1453
+ shaderUvSetCount: 8,
1454
+ };
1455
+
1456
+ // M6 fix-up: URP-variant key string for the standard PBR shader. Mirrors the
1457
+ // boot-time variantSet computed at createRenderer.ts step 1b when
1458
+ // `isHdrpActive=false` and `storageBufferCapable=true` (the URP default
1459
+ // surface). The URP record path requests this exact string at every
1460
+ // `getMaterialShaderPipeline` call site, so seeding the table with these
1461
+ // variants keeps the URP cache lookup hot from frame 1 instead of
1462
+ // skip-drawing the first ~1 frames while the async compile resolves.
1463
+ const URP_PBR_VARIANT_SET = 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true';
1464
+
1465
+ /**
1466
+ * Build the boot-time pre-warm table: 15 standard PipelineSpec variants.
1467
+ *
1468
+ * feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12): the
1469
+ * four `forgeax::default-sprite` entries (LDR S1 + LDR S4 + HDR S1 + HDR S4)
1470
+ * are gone — sprite PSO lands lazily through the generic
1471
+ * per-MaterialShader pipeline cache. Pre-feat count was 19; post-feat 15.
1472
+ *
1473
+ * Matrix:
1474
+ * - 8 base material variants — {unlit, standard-pbr} x {LDR, HDR} x {S1, S4}
1475
+ * - 4 URP-variant standard-pbr — standard-pbr (variantSet=URP_PBR_VARIANT_SET)
1476
+ * x {LDR, HDR} x {S1, S4}; URP record path requests these specs by
1477
+ * `getMaterialShaderPipeline` keying off `cacheKeyOf` so the boot-time
1478
+ * prewarm seeds `materialShaderPipelineCache` and avoids a 1-frame
1479
+ * async-compile skip-draw (M6 fix-up; see render-system-record.ts §URP)
1480
+ * - 3 fullscreen-post — tonemap (LDR S1) + skybox (HDR S1, HDR S4)
1481
+ *
1482
+ * Total: 15. The URP variant is PBR-only because:
1483
+ * - unlit URP record path passes `variantSet=undefined` (the no-variant
1484
+ * boot-default entries already cover it; createRenderer.ts §unlitRsp)
1485
+ * - sprite goes through `getMaterialShaderPipeline('forgeax::sprite', ...)`
1486
+ * lazily at first transparent-LDR-split draw — no boot-time pre-warm.
1487
+ * - HDRP variant (`variantSet=''` or compound `=true` form) is registered
1488
+ * lazily on `installPipeline(hdrpAsset)`, not at boot — adding HDRP
1489
+ * prewarm here would build PSOs against the URP layout (the boot-time
1490
+ * `pbrModule` is the URP variant when `isHdrpActive=false`)
1491
+ *
1492
+ * `ldrViewFormat` parameterises the LDR color attachment format. Callers
1493
+ * pass the runtime-resolved swap-chain view format (Channel 2 typically
1494
+ * `bgra8unorm-srgb`; Channel 3 wgpu-wasm and dawn-node typically
1495
+ * `rgba8unorm-srgb`). Hard-coding `bgra8unorm-srgb` at module load made
1496
+ * the pre-warmed PSOs incompatible with the actual RenderPass color
1497
+ * attachment on Channel 3 / dawn-node, producing whole-commandBuffer
1498
+ * invalid errors on every frame (bug-20260615 fix-up — see
1499
+ * `createRenderer` boot-time pre-warm site).
1500
+ *
1501
+ * Fullscreen passes (fxaa / bloom x 3 / SSAO x 2) are lazy-build — they
1502
+ * use the same getOrBuildPipeline entrypoint but are not in this table.
1503
+ *
1504
+ * @see plan-strategy D-4 · research R-D4 · requirements AC-16
1505
+ * @see bug-20260612-webgpu-canvas-format-prefer-bgra-shipped (same trap shape)
1506
+ */
1507
+ export function buildSpecConstTable(
1508
+ ldrViewFormat: GPUTextureFormat,
1509
+ ): readonly Readonly<PipelineSpec>[] {
1510
+ const TRI_ATTACHMENTS_LDR_S1 = {
1511
+ colorFormats: [ldrViewFormat],
1512
+ depthFormat: DEPTH_DS,
1513
+ sampleCount: 1 as const,
1514
+ };
1515
+
1516
+ const TRI_ATTACHMENTS_LDR_S4 = {
1517
+ colorFormats: [ldrViewFormat],
1518
+ depthFormat: DEPTH_DS,
1519
+ sampleCount: 4 as const,
1520
+ };
1521
+
1522
+ // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12 / D-7):
1523
+ // SPRITE_ATTACHMENTS_LDR_S1 / S4 (the dedicated non-srgb storage-format
1524
+ // attachments the sprite spec entries consumed) were deleted alongside the
1525
+ // four `forgeax::default-sprite` SPEC_CONST entries. The bgra8unorm storage
1526
+ // format itself is still enforced at the LDR sprite sub-pass attachment
1527
+ // level (the WebGPU pipeline `colorFormats` derive from the actual render
1528
+ // pass attachment view, which is built off `pipelineState.format` =
1529
+ // swap-chain storage format — see `render-system-record.ts` LDR split
1530
+ // beginRenderPass call). The triggering source migrated from the
1531
+ // spec-table id to `material.transparent` (derived by the extract stage
1532
+ // from `passes[0].renderState.blend !== undefined`, the
1533
+ // post-feat-20260626-collapse SSOT; w7 onwards).
1534
+
1535
+ const TRI_ATTACHMENTS_HDR_S1 = {
1536
+ colorFormats: [HDR_FORMAT],
1537
+ depthFormat: DEPTH_DS,
1538
+ sampleCount: 1 as const,
1539
+ };
1540
+
1541
+ const TRI_ATTACHMENTS_HDR_S4 = {
1542
+ colorFormats: [HDR_FORMAT],
1543
+ depthFormat: DEPTH_DS,
1544
+ sampleCount: 4 as const,
1545
+ };
1546
+
1547
+ return [
1548
+ // unlit LDR S1
1549
+ {
1550
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1551
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1552
+ geometry: TRI_GEOMETRY,
1553
+ renderState: undefined,
1554
+ },
1555
+ // unlit LDR S4
1556
+ {
1557
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1558
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1559
+ geometry: TRI_GEOMETRY,
1560
+ renderState: undefined,
1561
+ },
1562
+ // unlit HDR S1
1563
+ {
1564
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1565
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1566
+ geometry: TRI_GEOMETRY,
1567
+ renderState: undefined,
1568
+ },
1569
+ // unlit HDR S4
1570
+ {
1571
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1572
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1573
+ geometry: TRI_GEOMETRY,
1574
+ renderState: undefined,
1575
+ },
1576
+ // standard LDR S1
1577
+ {
1578
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1579
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1580
+ geometry: TRI_GEOMETRY_PBR,
1581
+ renderState: undefined,
1582
+ },
1583
+ // standard LDR S4
1584
+ {
1585
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1586
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1587
+ geometry: TRI_GEOMETRY_PBR,
1588
+ renderState: undefined,
1589
+ },
1590
+ // standard HDR S1
1591
+ {
1592
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1593
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1594
+ geometry: TRI_GEOMETRY_PBR,
1595
+ renderState: undefined,
1596
+ },
1597
+ // standard HDR S4
1598
+ {
1599
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1600
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1601
+ geometry: TRI_GEOMETRY_PBR,
1602
+ renderState: undefined,
1603
+ },
1604
+
1605
+ // ── M6 fix-up: URP-variant standard-pbr prewarm ─────────────────────────
1606
+ // URP record path (`getMaterialShaderPipeline`) requests
1607
+ // `variantSet=URP_PBR_VARIANT_SET` for standard-shading entities; pre-M6
1608
+ // the silent `selectStandardFallbackPipeline` shim served the no-variant
1609
+ // boot prewarm during the 1-frame async-compile warmup. With M6's
1610
+ // explicit-failure surface, those URP requests must hit the boot prewarm
1611
+ // by their own variantSet — these 4 entries close that gap.
1612
+
1613
+ // standard PBR URP LDR S1
1614
+ {
1615
+ shader: {
1616
+ id: 'forgeax::default-standard-pbr',
1617
+ passKind: 'forward',
1618
+ variantSet: URP_PBR_VARIANT_SET,
1619
+ },
1620
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1621
+ geometry: TRI_GEOMETRY_PBR,
1622
+ renderState: undefined,
1623
+ },
1624
+ // standard PBR URP LDR S4
1625
+ {
1626
+ shader: {
1627
+ id: 'forgeax::default-standard-pbr',
1628
+ passKind: 'forward',
1629
+ variantSet: URP_PBR_VARIANT_SET,
1630
+ },
1631
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1632
+ geometry: TRI_GEOMETRY_PBR,
1633
+ renderState: undefined,
1634
+ },
1635
+ // standard PBR URP HDR S1
1636
+ {
1637
+ shader: {
1638
+ id: 'forgeax::default-standard-pbr',
1639
+ passKind: 'forward',
1640
+ variantSet: URP_PBR_VARIANT_SET,
1641
+ },
1642
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1643
+ geometry: TRI_GEOMETRY_PBR,
1644
+ renderState: undefined,
1645
+ },
1646
+ // standard PBR URP HDR S4
1647
+ {
1648
+ shader: {
1649
+ id: 'forgeax::default-standard-pbr',
1650
+ passKind: 'forward',
1651
+ variantSet: URP_PBR_VARIANT_SET,
1652
+ },
1653
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1654
+ geometry: TRI_GEOMETRY_PBR,
1655
+ renderState: undefined,
1656
+ },
1657
+
1658
+ // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12 / D-7):
1659
+ // the four `forgeax::default-sprite` boot-time pre-warm entries (LDR S1
1660
+ // + LDR S4 + HDR S1 + HDR S4) are gone. Sprite PSO lands lazily through
1661
+ // the generic per-MaterialShader pipeline cache keyed on
1662
+ // `forgeax::sprite` + premultiplied-alpha renderState; SPEC_CONST_TABLE
1663
+ // shrinks from 19 to 15 entries (-4 boot-time PSOs).
1664
+
1665
+ // ── M2-T4: fullscreen-post boot-time pre-warm (tonemap + skybox) ──────────
1666
+ //
1667
+ // Tonemap (LDR S1): fullscreen triangle writes to swap-chain LDR view format
1668
+ // (parameterised — `ldrViewFormat`; see buildSpecConstTable jsdoc + bug-20260615).
1669
+ // Skybox (HDR S1 + S4): fullscreen triangle writes to rgba16float; MSAA variant
1670
+ // has sampleCount=4. Both use empty vertexLayout (fullscreen triangle, no
1671
+ // attributes) and cullMode='none' (forward cull for fullscreen-quad passthrough).
1672
+ //
1673
+ // Shadow-probe / fxaa / bloom 4-stage / SSAO 2-stage are lazy-build — not in
1674
+ // SPEC_CONST_TABLE (R-D4 decision: only entries that are always-present on
1675
+ // every boot).
1676
+
1677
+ // tonemap LDR S1 (writes to runtime-resolved swap-chain LDR view format)
1678
+ {
1679
+ shader: { id: 'forgeax::post::tonemap', passKind: 'post-process', variantSet: undefined },
1680
+ attachments: {
1681
+ colorFormats: [ldrViewFormat],
1682
+ depthFormat: undefined,
1683
+ sampleCount: 1 as const,
1684
+ },
1685
+ geometry: {
1686
+ topology: 'triangle-list' as PrimitiveTopology,
1687
+ stripIndexFormat: undefined,
1688
+ vertexLayout: {},
1689
+ },
1690
+ renderState: {
1691
+ cullMode: 'none',
1692
+ },
1693
+ },
1694
+
1695
+ // skybox HDR S1 (writes to rgba16float, no depth)
1696
+ {
1697
+ shader: { id: 'forgeax::skybox::cube', passKind: 'skybox', variantSet: undefined },
1698
+ attachments: {
1699
+ colorFormats: [HDR_FORMAT],
1700
+ depthFormat: undefined,
1701
+ sampleCount: 1 as const,
1702
+ },
1703
+ geometry: {
1704
+ topology: 'triangle-list' as PrimitiveTopology,
1705
+ stripIndexFormat: undefined,
1706
+ vertexLayout: {},
1707
+ },
1708
+ renderState: {
1709
+ cullMode: 'none',
1710
+ },
1711
+ },
1712
+
1713
+ // skybox HDR S4 (MSAA variant)
1714
+ {
1715
+ shader: { id: 'forgeax::skybox::cube', passKind: 'skybox', variantSet: undefined },
1716
+ attachments: {
1717
+ colorFormats: [HDR_FORMAT],
1718
+ depthFormat: undefined,
1719
+ sampleCount: 4 as const,
1720
+ },
1721
+ geometry: {
1722
+ topology: 'triangle-list' as PrimitiveTopology,
1723
+ stripIndexFormat: undefined,
1724
+ vertexLayout: {},
1725
+ },
1726
+ renderState: {
1727
+ cullMode: 'none',
1728
+ },
1729
+ },
1730
+ ];
1731
+ }
1732
+
1733
+ /**
1734
+ * Derive the material-only pre-warm table for a native linear-LDR target.
1735
+ *
1736
+ * The regular SPEC_CONST table targets the swap-chain view, while the
1737
+ * tonemap=none path records geometry directly into the graph-owned
1738
+ * `rgba16float` target. Keep that second attachment matrix derived from the
1739
+ * same material specs so the first frame does not depend on an asynchronous
1740
+ * lazy PSO build.
1741
+ */
1742
+ export function buildLinearLdrMaterialSpecTable(
1743
+ ldrViewFormat: GPUTextureFormat,
1744
+ ): readonly Readonly<PipelineSpec>[] {
1745
+ return buildSpecConstTable(ldrViewFormat)
1746
+ .filter(
1747
+ (spec) =>
1748
+ spec.shader.passKind === 'forward' && spec.attachments.colorFormats[0] === ldrViewFormat,
1749
+ )
1750
+ .map((spec) => ({
1751
+ ...spec,
1752
+ attachments: {
1753
+ ...spec.attachments,
1754
+ colorFormats: [HDR_FORMAT],
1755
+ },
1756
+ }));
1757
+ }
1758
+
1759
+ /**
1760
+ * Backward-compatible SPEC_CONST_TABLE — the table built with the default
1761
+ * LDR view format (`bgra8unorm-srgb`). Unit tests that exercise the
1762
+ * spec/cache-keying layer in isolation import this directly. Runtime
1763
+ * callers MUST call `buildSpecConstTable(swapChainFormats.view)` instead
1764
+ * so the pre-warmed PSO color format matches the actual RenderPass color
1765
+ * attachment on every backend (bug-20260615 fix-up).
1766
+ */
1767
+ export const SPEC_CONST_TABLE: readonly Readonly<PipelineSpec>[] =
1768
+ buildSpecConstTable(DEFAULT_LDR_FORMAT);