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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (891) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +647 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/authoring-path.unit.test.d.ts +2 -0
  5. package/dist/__tests__/authoring-path.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts +2 -0
  7. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts.map +1 -0
  8. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  9. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/cluster-binner.test.d.ts +2 -0
  11. package/dist/__tests__/cluster-binner.test.d.ts.map +1 -0
  12. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts +2 -0
  13. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts +2 -0
  15. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts +2 -0
  17. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts.map +1 -0
  18. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts +2 -0
  19. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts +2 -0
  21. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts.map +1 -0
  22. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts +2 -0
  23. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/factory-contract.integration.test.d.ts +2 -0
  25. package/dist/__tests__/factory-contract.integration.test.d.ts.map +1 -0
  26. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts +2 -0
  27. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/frame-observation.contract.test.d.ts +2 -0
  29. package/dist/__tests__/frame-observation.contract.test.d.ts.map +1 -0
  30. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts +2 -0
  31. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts +2 -0
  33. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts +6 -0
  35. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -0
  36. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts +2 -0
  37. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts.map +1 -0
  38. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts +2 -0
  39. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts.map +1 -0
  40. package/dist/__tests__/gpu-driven-production.integration.test.d.ts +2 -0
  41. package/dist/__tests__/gpu-driven-production.integration.test.d.ts.map +1 -0
  42. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts +2 -0
  43. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts.map +1 -0
  44. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +18 -0
  45. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -0
  46. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts +2 -0
  47. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts.map +1 -0
  48. package/dist/__tests__/gpu-driven-view-reference.d.ts +15 -0
  49. package/dist/__tests__/gpu-driven-view-reference.d.ts.map +1 -0
  50. package/dist/__tests__/gpu-driven-view.browser.test.d.ts +2 -0
  51. package/dist/__tests__/gpu-driven-view.browser.test.d.ts.map +1 -0
  52. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts +2 -0
  53. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts.map +1 -0
  54. package/dist/__tests__/gpu-driven-view.unit.test.d.ts +2 -0
  55. package/dist/__tests__/gpu-driven-view.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts +2 -0
  57. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts +7 -0
  59. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -0
  60. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts +2 -0
  61. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts.map +1 -0
  62. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts +2 -0
  63. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts.map +1 -0
  64. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts +2 -0
  65. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/gpu-scene.dawn.test.d.ts +2 -0
  67. package/dist/__tests__/gpu-scene.dawn.test.d.ts.map +1 -0
  68. package/dist/__tests__/gpu-scene.unit.test.d.ts +2 -0
  69. package/dist/__tests__/gpu-scene.unit.test.d.ts.map +1 -0
  70. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts +2 -0
  71. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts.map +1 -0
  72. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts +2 -0
  73. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts.map +1 -0
  74. package/dist/__tests__/injection-kind-owner.test-d.d.ts +2 -0
  75. package/dist/__tests__/injection-kind-owner.test-d.d.ts.map +1 -0
  76. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts +2 -0
  77. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts.map +1 -0
  78. package/dist/__tests__/light-buffer-layout.unit.test.d.ts +2 -0
  79. package/dist/__tests__/light-buffer-layout.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/material-contract-inventory.unit.test.d.ts +2 -0
  81. package/dist/__tests__/material-contract-inventory.unit.test.d.ts.map +1 -0
  82. package/dist/__tests__/material-cooked-projection.unit.test.d.ts +2 -0
  83. package/dist/__tests__/material-cooked-projection.unit.test.d.ts.map +1 -0
  84. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts +2 -0
  85. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts.map +1 -0
  86. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts +2 -0
  87. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/material-stride-surface.unit.test.d.ts +2 -0
  89. package/dist/__tests__/material-stride-surface.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts +2 -0
  91. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts.map +1 -0
  92. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts +2 -0
  93. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts.map +1 -0
  94. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts +2 -0
  95. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts.map +1 -0
  96. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts +2 -0
  97. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts.map +1 -0
  98. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts +2 -0
  99. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts.map +1 -0
  100. package/dist/__tests__/morph-feature-plan.unit.test.d.ts +2 -0
  101. package/dist/__tests__/morph-feature-plan.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts +2 -0
  103. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts.map +1 -0
  104. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts +2 -0
  105. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts +2 -0
  107. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts +2 -0
  109. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts.map +1 -0
  110. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts +2 -0
  111. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts.map +1 -0
  112. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts +2 -0
  113. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts.map +1 -0
  114. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts +2 -0
  115. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts +2 -0
  117. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts.map +1 -0
  118. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts +2 -0
  119. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts.map +1 -0
  120. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts +2 -0
  121. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts.map +1 -0
  122. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts +2 -0
  123. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts +2 -0
  125. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts.map +1 -0
  126. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  127. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  128. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  129. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  130. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  131. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  132. package/dist/__tests__/profiler-phase-token.test.d.ts +2 -0
  133. package/dist/__tests__/profiler-phase-token.test.d.ts.map +1 -0
  134. package/dist/__tests__/public-surface.test-d.d.ts +2 -0
  135. package/dist/__tests__/public-surface.test-d.d.ts.map +1 -0
  136. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts +2 -0
  137. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts.map +1 -0
  138. package/dist/__tests__/render-error-code-owner.test-d.d.ts +2 -0
  139. package/dist/__tests__/render-error-code-owner.test-d.d.ts.map +1 -0
  140. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts +2 -0
  141. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts.map +1 -0
  142. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +2 -0
  143. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  144. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  145. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  146. package/dist/__tests__/render-feature-context.test-d.d.ts +2 -0
  147. package/dist/__tests__/render-feature-context.test-d.d.ts.map +1 -0
  148. package/dist/__tests__/render-feature-contract.test-d.d.ts +2 -0
  149. package/dist/__tests__/render-feature-contract.test-d.d.ts.map +1 -0
  150. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts +2 -0
  151. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts.map +1 -0
  152. package/dist/__tests__/render-feature-docs.unit.test.d.ts +2 -0
  153. package/dist/__tests__/render-feature-docs.unit.test.d.ts.map +1 -0
  154. package/dist/__tests__/render-feature-errors.unit.test.d.ts +2 -0
  155. package/dist/__tests__/render-feature-errors.unit.test.d.ts.map +1 -0
  156. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts +2 -0
  157. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts.map +1 -0
  158. package/dist/__tests__/render-feature-plan.test-d.d.ts +2 -0
  159. package/dist/__tests__/render-feature-plan.test-d.d.ts.map +1 -0
  160. package/dist/__tests__/render-feature-plan.unit.test.d.ts +2 -0
  161. package/dist/__tests__/render-feature-plan.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts +2 -0
  163. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts +2 -0
  165. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts.map +1 -0
  166. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  167. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts +2 -0
  169. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts.map +1 -0
  170. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts +2 -0
  171. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts.map +1 -0
  172. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts +2 -0
  173. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts.map +1 -0
  174. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts +2 -0
  175. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts.map +1 -0
  176. package/dist/__tests__/render-feature-public-surface.test-d.d.ts +2 -0
  177. package/dist/__tests__/render-feature-public-surface.test-d.d.ts.map +1 -0
  178. package/dist/__tests__/render-feature-retry.unit.test.d.ts +2 -0
  179. package/dist/__tests__/render-feature-retry.unit.test.d.ts.map +1 -0
  180. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts +2 -0
  181. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts.map +1 -0
  182. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts +2 -0
  183. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts.map +1 -0
  184. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts +2 -0
  185. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts.map +1 -0
  186. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts +2 -0
  187. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts.map +1 -0
  188. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts +2 -0
  189. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts.map +1 -0
  190. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts +2 -0
  191. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts.map +1 -0
  192. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts +7 -0
  193. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts.map +1 -0
  194. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts +2 -0
  195. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts.map +1 -0
  196. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts +2 -0
  197. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts.map +1 -0
  198. package/dist/__tests__/render-graph-hzb-gpu.d.ts +7 -0
  199. package/dist/__tests__/render-graph-hzb-gpu.d.ts.map +1 -0
  200. package/dist/__tests__/render-graph-hzb.browser.test.d.ts +2 -0
  201. package/dist/__tests__/render-graph-hzb.browser.test.d.ts.map +1 -0
  202. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts +2 -0
  203. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts.map +1 -0
  204. package/dist/__tests__/render-graph-primitives.unit.test.d.ts +2 -0
  205. package/dist/__tests__/render-graph-primitives.unit.test.d.ts.map +1 -0
  206. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts +12 -0
  207. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts.map +1 -0
  208. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts +2 -0
  209. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts.map +1 -0
  210. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts +2 -0
  211. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts.map +1 -0
  212. package/dist/__tests__/render-scene-projection.unit.test.d.ts +2 -0
  213. package/dist/__tests__/render-scene-projection.unit.test.d.ts.map +1 -0
  214. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts +2 -0
  215. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts.map +1 -0
  216. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  217. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  218. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts +2 -0
  219. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts.map +1 -0
  220. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts +2 -0
  221. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts.map +1 -0
  222. package/dist/__tests__/shader-stage-surface.unit.test.d.ts +2 -0
  223. package/dist/__tests__/shader-stage-surface.unit.test.d.ts.map +1 -0
  224. package/dist/__tests__/ssao-config.unit.test.d.ts +2 -0
  225. package/dist/__tests__/ssao-config.unit.test.d.ts.map +1 -0
  226. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts +2 -0
  227. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts.map +1 -0
  228. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts +2 -0
  229. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts.map +1 -0
  230. package/dist/__tests__/standard-descriptors.test-d.d.ts +2 -0
  231. package/dist/__tests__/standard-descriptors.test-d.d.ts.map +1 -0
  232. package/dist/__tests__/standard-pipeline.dawn.test.d.ts +2 -0
  233. package/dist/__tests__/standard-pipeline.dawn.test.d.ts.map +1 -0
  234. package/dist/__tests__/standard-pipeline.integration.test.d.ts +2 -0
  235. package/dist/__tests__/standard-pipeline.integration.test.d.ts.map +1 -0
  236. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts +2 -0
  237. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts.map +1 -0
  238. package/dist/__tests__/surface-configuration.unit.test.d.ts +2 -0
  239. package/dist/__tests__/surface-configuration.unit.test.d.ts.map +1 -0
  240. package/dist/__tests__/texture-usage-surface.unit.test.d.ts +2 -0
  241. package/dist/__tests__/texture-usage-surface.unit.test.d.ts.map +1 -0
  242. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts +2 -0
  243. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts.map +1 -0
  244. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts +2 -0
  245. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts.map +1 -0
  246. package/dist/__tests__/urp-pipeline.unit.test.d.ts +2 -0
  247. package/dist/__tests__/urp-pipeline.unit.test.d.ts.map +1 -0
  248. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts +2 -0
  249. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts.map +1 -0
  250. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts +2 -0
  251. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts.map +1 -0
  252. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts +2 -0
  253. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts.map +1 -0
  254. package/dist/__tests__/visibility-extract.integration.test.d.ts +2 -0
  255. package/dist/__tests__/visibility-extract.integration.test.d.ts.map +1 -0
  256. package/dist/__tests__/visibility-extract.perf.test.d.ts +2 -0
  257. package/dist/__tests__/visibility-extract.perf.test.d.ts.map +1 -0
  258. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts +2 -0
  259. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts.map +1 -0
  260. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts +2 -0
  261. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/visibility-instances.integration.test.d.ts +2 -0
  263. package/dist/__tests__/visibility-instances.integration.test.d.ts.map +1 -0
  264. package/dist/__tests__/visibility-multi-world.integration.test.d.ts +2 -0
  265. package/dist/__tests__/visibility-multi-world.integration.test.d.ts.map +1 -0
  266. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts +2 -0
  267. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts.map +1 -0
  268. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts +2 -0
  269. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts.map +1 -0
  270. package/dist/__tests__/visibility-public-surface.test-d.d.ts +2 -0
  271. package/dist/__tests__/visibility-public-surface.test-d.d.ts.map +1 -0
  272. package/dist/__tests__/visibility-resolver.unit.test.d.ts +2 -0
  273. package/dist/__tests__/visibility-resolver.unit.test.d.ts.map +1 -0
  274. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts +2 -0
  275. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts.map +1 -0
  276. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts +2 -0
  277. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts.map +1 -0
  278. package/dist/__tests__/vocabulary.unit.test.d.ts +2 -0
  279. package/dist/__tests__/vocabulary.unit.test.d.ts.map +1 -0
  280. package/dist/assembly/backend-contract.d.ts +37 -0
  281. package/dist/assembly/backend-contract.d.ts.map +1 -0
  282. package/dist/assembly/factory.d.ts +207 -0
  283. package/dist/assembly/factory.d.ts.map +1 -0
  284. package/dist/assembly/host-contract.d.ts +84 -0
  285. package/dist/assembly/host-contract.d.ts.map +1 -0
  286. package/dist/assembly/material/assembly.d.ts +21 -0
  287. package/dist/assembly/material/assembly.d.ts.map +1 -0
  288. package/dist/assembly/material/pipeline-projection.d.ts +30 -0
  289. package/dist/assembly/material/pipeline-projection.d.ts.map +1 -0
  290. package/dist/assets/asset-decoders.d.ts +5 -0
  291. package/dist/assets/asset-decoders.d.ts.map +1 -0
  292. package/dist/assets/render-asset-port.d.ts +17 -0
  293. package/dist/assets/render-asset-port.d.ts.map +1 -0
  294. package/dist/assets/resolve-render-asset.d.ts +6 -0
  295. package/dist/assets/resolve-render-asset.d.ts.map +1 -0
  296. package/dist/authoring.d.ts +12 -0
  297. package/dist/authoring.d.ts.map +1 -0
  298. package/dist/authoring.mjs +27 -0
  299. package/dist/authoring.mjs.map +1 -0
  300. package/dist/chunk-CQXZC5XI.mjs +182 -0
  301. package/dist/chunk-CQXZC5XI.mjs.map +1 -0
  302. package/dist/chunk-HCOGPHKS.mjs +93 -0
  303. package/dist/chunk-HCOGPHKS.mjs.map +1 -0
  304. package/dist/chunk-YEJIUW7D.mjs +1152 -0
  305. package/dist/chunk-YEJIUW7D.mjs.map +1 -0
  306. package/dist/cluster-binner.d.ts +152 -0
  307. package/dist/cluster-binner.d.ts.map +1 -0
  308. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts +2 -0
  309. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts.map +1 -0
  310. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts +2 -0
  311. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts.map +1 -0
  312. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  313. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  314. package/dist/components/__tests__/schema-parity.unit.test.d.ts +2 -0
  315. package/dist/components/__tests__/schema-parity.unit.test.d.ts.map +1 -0
  316. package/dist/components/__tests__/visibility-schema.unit.test.d.ts +2 -0
  317. package/dist/components/__tests__/visibility-schema.unit.test.d.ts.map +1 -0
  318. package/dist/components/camera.d.ts +311 -0
  319. package/dist/components/camera.d.ts.map +1 -0
  320. package/dist/components/directional-light.d.ts +76 -0
  321. package/dist/components/directional-light.d.ts.map +1 -0
  322. package/dist/components/glyph-text.d.ts +26 -0
  323. package/dist/components/glyph-text.d.ts.map +1 -0
  324. package/dist/components/index.d.ts +24 -0
  325. package/dist/components/index.d.ts.map +1 -0
  326. package/dist/components/instances.d.ts +41 -0
  327. package/dist/components/instances.d.ts.map +1 -0
  328. package/dist/components/layer.d.ts +34 -0
  329. package/dist/components/layer.d.ts.map +1 -0
  330. package/dist/components/light-helpers.d.ts +53 -0
  331. package/dist/components/light-helpers.d.ts.map +1 -0
  332. package/dist/components/lines.d.ts +5 -0
  333. package/dist/components/lines.d.ts.map +1 -0
  334. package/dist/components/mesh-filter.d.ts +24 -0
  335. package/dist/components/mesh-filter.d.ts.map +1 -0
  336. package/dist/components/mesh-renderer.d.ts +33 -0
  337. package/dist/components/mesh-renderer.d.ts.map +1 -0
  338. package/dist/components/point-light-shadow.d.ts +27 -0
  339. package/dist/components/point-light-shadow.d.ts.map +1 -0
  340. package/dist/components/point-light.d.ts +35 -0
  341. package/dist/components/point-light.d.ts.map +1 -0
  342. package/dist/components/points.d.ts +15 -0
  343. package/dist/components/points.d.ts.map +1 -0
  344. package/dist/components/post-process-params.d.ts +5 -0
  345. package/dist/components/post-process-params.d.ts.map +1 -0
  346. package/dist/components/scene-instance.d.ts +140 -0
  347. package/dist/components/scene-instance.d.ts.map +1 -0
  348. package/dist/components/skybox-background.d.ts +56 -0
  349. package/dist/components/skybox-background.d.ts.map +1 -0
  350. package/dist/components/skylight.d.ts +55 -0
  351. package/dist/components/skylight.d.ts.map +1 -0
  352. package/dist/components/sort-key.d.ts +44 -0
  353. package/dist/components/sort-key.d.ts.map +1 -0
  354. package/dist/components/spot-light.d.ts +81 -0
  355. package/dist/components/spot-light.d.ts.map +1 -0
  356. package/dist/components/sprite-animation.d.ts +74 -0
  357. package/dist/components/sprite-animation.d.ts.map +1 -0
  358. package/dist/components/sprite-instances.d.ts +51 -0
  359. package/dist/components/sprite-instances.d.ts.map +1 -0
  360. package/dist/components/sprite-playback-mode.d.ts +42 -0
  361. package/dist/components/sprite-playback-mode.d.ts.map +1 -0
  362. package/dist/components/sprite-region-override.d.ts +46 -0
  363. package/dist/components/sprite-region-override.d.ts.map +1 -0
  364. package/dist/components/tile-layer.d.ts +106 -0
  365. package/dist/components/tile-layer.d.ts.map +1 -0
  366. package/dist/components/tilemap.d.ts +25 -0
  367. package/dist/components/tilemap.d.ts.map +1 -0
  368. package/dist/components/visibility.d.ts +22 -0
  369. package/dist/components/visibility.d.ts.map +1 -0
  370. package/dist/construct-renderer.d.ts +19 -0
  371. package/dist/construct-renderer.d.ts.map +1 -0
  372. package/dist/construct-renderer.mjs +27462 -0
  373. package/dist/construct-renderer.mjs.map +1 -0
  374. package/dist/debug-draw-glue.d.ts +5 -0
  375. package/dist/debug-draw-glue.d.ts.map +1 -0
  376. package/dist/device/device-scope.d.ts +83 -0
  377. package/dist/device/device-scope.d.ts.map +1 -0
  378. package/dist/device/gpu-residency.d.ts +337 -0
  379. package/dist/device/gpu-residency.d.ts.map +1 -0
  380. package/dist/device/resource-types.d.ts +8 -0
  381. package/dist/device/resource-types.d.ts.map +1 -0
  382. package/dist/engine-metrics.d.ts +23 -0
  383. package/dist/engine-metrics.d.ts.map +1 -0
  384. package/dist/errors/ecs-validation.d.ts +3 -0
  385. package/dist/errors/ecs-validation.d.ts.map +1 -0
  386. package/dist/errors/index.d.ts +4 -0
  387. package/dist/errors/index.d.ts.map +1 -0
  388. package/dist/errors/recover.d.ts +105 -0
  389. package/dist/errors/recover.d.ts.map +1 -0
  390. package/dist/errors/render.d.ts +705 -0
  391. package/dist/errors/render.d.ts.map +1 -0
  392. package/dist/extract/visibility.d.ts +26 -0
  393. package/dist/extract/visibility.d.ts.map +1 -0
  394. package/dist/features/fullscreen.d.ts +19 -0
  395. package/dist/features/fullscreen.d.ts.map +1 -0
  396. package/dist/features/host.d.ts +106 -0
  397. package/dist/features/host.d.ts.map +1 -0
  398. package/dist/features/morph/morph-feature.d.ts +79 -0
  399. package/dist/features/morph/morph-feature.d.ts.map +1 -0
  400. package/dist/features/plan.d.ts +182 -0
  401. package/dist/features/plan.d.ts.map +1 -0
  402. package/dist/features/prepared-gpu-work.d.ts +117 -0
  403. package/dist/features/prepared-gpu-work.d.ts.map +1 -0
  404. package/dist/features/prepared-graphics-store.d.ts +66 -0
  405. package/dist/features/prepared-graphics-store.d.ts.map +1 -0
  406. package/dist/features/prepared-graphics.d.ts +215 -0
  407. package/dist/features/prepared-graphics.d.ts.map +1 -0
  408. package/dist/features/render-graph-compute.d.ts +13 -0
  409. package/dist/features/render-graph-compute.d.ts.map +1 -0
  410. package/dist/features/render-graph-contribution.d.ts +12 -0
  411. package/dist/features/render-graph-contribution.d.ts.map +1 -0
  412. package/dist/features/render-graph-raster.d.ts +38 -0
  413. package/dist/features/render-graph-raster.d.ts.map +1 -0
  414. package/dist/features/render-graph-resources.d.ts +11 -0
  415. package/dist/features/render-graph-resources.d.ts.map +1 -0
  416. package/dist/features/targets.d.ts +32 -0
  417. package/dist/features/targets.d.ts.map +1 -0
  418. package/dist/features/types.d.ts +68 -0
  419. package/dist/features/types.d.ts.map +1 -0
  420. package/dist/features/vocabulary.d.ts +14 -0
  421. package/dist/features/vocabulary.d.ts.map +1 -0
  422. package/dist/fullscreen-post-process-pass.d.ts +157 -0
  423. package/dist/fullscreen-post-process-pass.d.ts.map +1 -0
  424. package/dist/glyph-text-layout-system.d.ts +19 -0
  425. package/dist/glyph-text-layout-system.d.ts.map +1 -0
  426. package/dist/gpu-driven/batch-topology.d.ts +55 -0
  427. package/dist/gpu-driven/batch-topology.d.ts.map +1 -0
  428. package/dist/gpu-driven/production-raster.d.ts +51 -0
  429. package/dist/gpu-driven/production-raster.d.ts.map +1 -0
  430. package/dist/gpu-driven/view-gpu.d.ts +85 -0
  431. package/dist/gpu-driven/view-gpu.d.ts.map +1 -0
  432. package/dist/gpu-resource.d.ts +73 -0
  433. package/dist/gpu-resource.d.ts.map +1 -0
  434. package/dist/gpu-scene-schema.d.ts +78 -0
  435. package/dist/gpu-scene-schema.d.ts.map +1 -0
  436. package/dist/gpu-scene.d.ts +55 -0
  437. package/dist/gpu-scene.d.ts.map +1 -0
  438. package/dist/gpu-stage.d.ts +4 -0
  439. package/dist/gpu-stage.d.ts.map +1 -0
  440. package/dist/gpu-texture-usage.d.ts +6 -0
  441. package/dist/gpu-texture-usage.d.ts.map +1 -0
  442. package/dist/gpu-usage.d.ts +9 -0
  443. package/dist/gpu-usage.d.ts.map +1 -0
  444. package/dist/hdrp-buffers.d.ts +163 -0
  445. package/dist/hdrp-buffers.d.ts.map +1 -0
  446. package/dist/ibl/IblPipelineCache.d.ts +168 -0
  447. package/dist/ibl/IblPipelineCache.d.ts.map +1 -0
  448. package/dist/ibl/skylight-bind-group.d.ts +130 -0
  449. package/dist/ibl/skylight-bind-group.d.ts.map +1 -0
  450. package/dist/index.d.ts +31 -0
  451. package/dist/index.d.ts.map +1 -0
  452. package/dist/index.mjs +169 -0
  453. package/dist/index.mjs.map +1 -0
  454. package/dist/inspection-types.d.ts +72 -0
  455. package/dist/inspection-types.d.ts.map +1 -0
  456. package/dist/instance-buffer-cache.d.ts +56 -0
  457. package/dist/instance-buffer-cache.d.ts.map +1 -0
  458. package/dist/internal.d.ts +2 -0
  459. package/dist/internal.d.ts.map +1 -0
  460. package/dist/internal.mjs +3 -0
  461. package/dist/internal.mjs.map +1 -0
  462. package/dist/lifecycle.d.ts +62 -0
  463. package/dist/lifecycle.d.ts.map +1 -0
  464. package/dist/light-buffer-layout.d.ts +164 -0
  465. package/dist/light-buffer-layout.d.ts.map +1 -0
  466. package/dist/materials.d.ts +47 -0
  467. package/dist/materials.d.ts.map +1 -0
  468. package/dist/mesh-material-bindings.d.ts +43 -0
  469. package/dist/mesh-material-bindings.d.ts.map +1 -0
  470. package/dist/pbr-pipeline.d.ts +301 -0
  471. package/dist/pbr-pipeline.d.ts.map +1 -0
  472. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  473. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  474. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  475. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  476. package/dist/pipeline/standard-profile.d.ts +40 -0
  477. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  478. package/dist/pipeline-builder.d.ts +122 -0
  479. package/dist/pipeline-builder.d.ts.map +1 -0
  480. package/dist/pipeline-spec-types.d.ts +24 -0
  481. package/dist/pipeline-spec-types.d.ts.map +1 -0
  482. package/dist/pipeline-spec.d.ts +367 -0
  483. package/dist/pipeline-spec.d.ts.map +1 -0
  484. package/dist/plugin.d.ts +4 -0
  485. package/dist/plugin.d.ts.map +1 -0
  486. package/dist/points-lines/__tests__/bounds.unit.test.d.ts +2 -0
  487. package/dist/points-lines/__tests__/bounds.unit.test.d.ts.map +1 -0
  488. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts +2 -0
  489. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts.map +1 -0
  490. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts +2 -0
  491. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts.map +1 -0
  492. package/dist/points-lines/__tests__/inspection.unit.test.d.ts +2 -0
  493. package/dist/points-lines/__tests__/inspection.unit.test.d.ts.map +1 -0
  494. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts +2 -0
  495. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts.map +1 -0
  496. package/dist/points-lines/__tests__/points-lines.bench.d.ts +2 -0
  497. package/dist/points-lines/__tests__/points-lines.bench.d.ts.map +1 -0
  498. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts +2 -0
  499. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts.map +1 -0
  500. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts +2 -0
  501. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts.map +1 -0
  502. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts +2 -0
  503. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts.map +1 -0
  504. package/dist/points-lines/admission.d.ts +36 -0
  505. package/dist/points-lines/admission.d.ts.map +1 -0
  506. package/dist/points-lines/bounds.d.ts +8 -0
  507. package/dist/points-lines/bounds.d.ts.map +1 -0
  508. package/dist/points-lines/expansion-cache.d.ts +28 -0
  509. package/dist/points-lines/expansion-cache.d.ts.map +1 -0
  510. package/dist/points-lines/inspection.d.ts +53 -0
  511. package/dist/points-lines/inspection.d.ts.map +1 -0
  512. package/dist/points-lines/prepare.d.ts +67 -0
  513. package/dist/points-lines/prepare.d.ts.map +1 -0
  514. package/dist/points-lines/record.d.ts +60 -0
  515. package/dist/points-lines/record.d.ts.map +1 -0
  516. package/dist/points-lines/snapshot.d.ts +49 -0
  517. package/dist/points-lines/snapshot.d.ts.map +1 -0
  518. package/dist/post-process-errors.d.ts +182 -0
  519. package/dist/post-process-errors.d.ts.map +1 -0
  520. package/dist/prepare/prepared-graphics-resolver.d.ts +59 -0
  521. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -0
  522. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts +2 -0
  523. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts.map +1 -0
  524. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts +2 -0
  525. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts.map +1 -0
  526. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  527. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  528. package/dist/record/__tests__/video-texture-view.unit.test.d.ts +2 -0
  529. package/dist/record/__tests__/video-texture-view.unit.test.d.ts.map +1 -0
  530. package/dist/record/frame-lighting.d.ts +121 -0
  531. package/dist/record/frame-lighting.d.ts.map +1 -0
  532. package/dist/record/frame-snapshot.d.ts +429 -0
  533. package/dist/record/frame-snapshot.d.ts.map +1 -0
  534. package/dist/record/frame-targets.d.ts +20 -0
  535. package/dist/record/frame-targets.d.ts.map +1 -0
  536. package/dist/record/frame.d.ts +71 -0
  537. package/dist/record/frame.d.ts.map +1 -0
  538. package/dist/record/helpers.d.ts +102 -0
  539. package/dist/record/helpers.d.ts.map +1 -0
  540. package/dist/record/main-pass-geometry.d.ts +28 -0
  541. package/dist/record/main-pass-geometry.d.ts.map +1 -0
  542. package/dist/record/main-pass-material.d.ts +204 -0
  543. package/dist/record/main-pass-material.d.ts.map +1 -0
  544. package/dist/record/main-pass-sprite-draws.d.ts +43 -0
  545. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -0
  546. package/dist/record/main-pass.d.ts +20 -0
  547. package/dist/record/main-pass.d.ts.map +1 -0
  548. package/dist/record/mesh-ssbo.d.ts +446 -0
  549. package/dist/record/mesh-ssbo.d.ts.map +1 -0
  550. package/dist/record/render-context.d.ts +252 -0
  551. package/dist/record/render-context.d.ts.map +1 -0
  552. package/dist/record/shadow-pass.d.ts +52 -0
  553. package/dist/record/shadow-pass.d.ts.map +1 -0
  554. package/dist/record/skybox-post-pass.d.ts +33 -0
  555. package/dist/record/skybox-post-pass.d.ts.map +1 -0
  556. package/dist/record/typed-frame-graph.d.ts +35 -0
  557. package/dist/record/typed-frame-graph.d.ts.map +1 -0
  558. package/dist/record/view-ubo.d.ts +45 -0
  559. package/dist/record/view-ubo.d.ts.map +1 -0
  560. package/dist/render-contract.d.ts +424 -0
  561. package/dist/render-contract.d.ts.map +1 -0
  562. package/dist/render-data.d.ts +143 -0
  563. package/dist/render-data.d.ts.map +1 -0
  564. package/dist/render-graph-primitives.d.ts +76 -0
  565. package/dist/render-graph-primitives.d.ts.map +1 -0
  566. package/dist/render-pipeline.d.ts +110 -0
  567. package/dist/render-pipeline.d.ts.map +1 -0
  568. package/dist/render-system-extract.d.ts +868 -0
  569. package/dist/render-system-extract.d.ts.map +1 -0
  570. package/dist/render-system.d.ts +125 -0
  571. package/dist/render-system.d.ts.map +1 -0
  572. package/dist/scene/render-scene-types.d.ts +61 -0
  573. package/dist/scene/render-scene-types.d.ts.map +1 -0
  574. package/dist/scene/render-scene.d.ts +112 -0
  575. package/dist/scene/render-scene.d.ts.map +1 -0
  576. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +30 -0
  577. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -0
  578. package/dist/shadow-atlas.d.ts +117 -0
  579. package/dist/shadow-atlas.d.ts.map +1 -0
  580. package/dist/ssao-buffers.d.ts +50 -0
  581. package/dist/ssao-buffers.d.ts.map +1 -0
  582. package/dist/ssao-config.d.ts +28 -0
  583. package/dist/ssao-config.d.ts.map +1 -0
  584. package/dist/systems/active-camera.d.ts +53 -0
  585. package/dist/systems/active-camera.d.ts.map +1 -0
  586. package/dist/systems/pass-selector.d.ts +24 -0
  587. package/dist/systems/pass-selector.d.ts.map +1 -0
  588. package/dist/systems/skin-palette-allocator.d.ts +49 -0
  589. package/dist/systems/skin-palette-allocator.d.ts.map +1 -0
  590. package/dist/systems/skin-palette-types.d.ts +14 -0
  591. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  592. package/dist/systems/transparent-sort-config.d.ts +112 -0
  593. package/dist/systems/transparent-sort-config.d.ts.map +1 -0
  594. package/dist/tilemap-chunk-extract-system.d.ts +143 -0
  595. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -0
  596. package/dist/typed-render-graph-primitives.d.ts +57 -0
  597. package/dist/typed-render-graph-primitives.d.ts.map +1 -0
  598. package/dist/typed-shadow-passes.d.ts +11 -0
  599. package/dist/typed-shadow-passes.d.ts.map +1 -0
  600. package/package.json +94 -0
  601. package/src/__tests__/authoring-path.unit.test.ts +23 -0
  602. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +21 -0
  603. package/src/__tests__/callback-inference.test-d.ts +8 -0
  604. package/src/__tests__/cluster-binner.test.ts +272 -0
  605. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +20 -0
  606. package/src/__tests__/construct-renderer-identity.unit.test.ts +23 -0
  607. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  608. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  609. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +23 -0
  610. package/src/__tests__/direct-light-snapshot.unit.test.ts +61 -0
  611. package/src/__tests__/factory-contract.integration.test.ts +280 -0
  612. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +15 -0
  613. package/src/__tests__/frame-observation.contract.test.ts +112 -0
  614. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  615. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +167 -0
  616. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +350 -0
  617. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +12 -0
  618. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +16 -0
  619. package/src/__tests__/gpu-driven-production.integration.test.ts +436 -0
  620. package/src/__tests__/gpu-driven-scaling.unit.test.ts +87 -0
  621. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +271 -0
  622. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +290 -0
  623. package/src/__tests__/gpu-driven-view-reference.ts +111 -0
  624. package/src/__tests__/gpu-driven-view.browser.test.ts +30 -0
  625. package/src/__tests__/gpu-driven-view.dawn.test.ts +28 -0
  626. package/src/__tests__/gpu-driven-view.unit.test.ts +199 -0
  627. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +59 -0
  628. package/src/__tests__/gpu-scene-render-graph-gpu.ts +308 -0
  629. package/src/__tests__/gpu-scene-render-graph.browser.test.ts +19 -0
  630. package/src/__tests__/gpu-scene-render-graph.dawn.test.ts +19 -0
  631. package/src/__tests__/gpu-scene-schema.unit.test.ts +16 -0
  632. package/src/__tests__/gpu-scene.dawn.test.ts +205 -0
  633. package/src/__tests__/gpu-scene.unit.test.ts +147 -0
  634. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  635. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +92 -0
  636. package/src/__tests__/injection-kind-owner.test-d.ts +14 -0
  637. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +728 -0
  638. package/src/__tests__/light-buffer-layout.unit.test.ts +40 -0
  639. package/src/__tests__/material-contract-inventory.unit.test.ts +24 -0
  640. package/src/__tests__/material-cooked-projection.unit.test.ts +150 -0
  641. package/src/__tests__/material-snapshot-mutation.integration.test.ts +53 -0
  642. package/src/__tests__/material-static-dynamic-route.unit.test.ts +94 -0
  643. package/src/__tests__/material-stride-surface.unit.test.ts +32 -0
  644. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +106 -0
  645. package/src/__tests__/mesh-material-bindings.unit.test.ts +89 -0
  646. package/src/__tests__/mesh-stride-surface.unit.test.ts +16 -0
  647. package/src/__tests__/morph-culling-reentry.dawn.test.ts +157 -0
  648. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +80 -0
  649. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  650. package/src/__tests__/morph-visual-evidence.integration.test.ts +80 -0
  651. package/src/__tests__/nineslice-handle-surface.unit.test.ts +19 -0
  652. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +201 -0
  653. package/src/__tests__/prepared-buffer-kind-owner.test-d.ts +29 -0
  654. package/src/__tests__/prepared-graphics-capability.unit.test.ts +65 -0
  655. package/src/__tests__/prepared-graphics-generation.unit.test.ts +161 -0
  656. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +138 -0
  657. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +29 -0
  658. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +285 -0
  659. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +105 -0
  660. package/src/__tests__/prepared-graphics-store.unit.test.ts +154 -0
  661. package/src/__tests__/prepared-graphics-validation.unit.test.ts +176 -0
  662. package/src/__tests__/profiler-default-off.test.ts +22 -0
  663. package/src/__tests__/profiler-phase-catalog.test.ts +66 -0
  664. package/src/__tests__/profiler-phase-integration.test.ts +62 -0
  665. package/src/__tests__/profiler-phase-token.test.ts +79 -0
  666. package/src/__tests__/public-surface.test-d.ts +94 -0
  667. package/src/__tests__/recover-error-policy-owner.unit.test.ts +107 -0
  668. package/src/__tests__/render-error-code-owner.test-d.ts +116 -0
  669. package/src/__tests__/render-error-detail-ssot.test-d.ts +139 -0
  670. package/src/__tests__/render-error-exhaustive.test-d.ts +110 -0
  671. package/src/__tests__/render-feature-assembly.test-d.ts +43 -0
  672. package/src/__tests__/render-feature-context.test-d.ts +57 -0
  673. package/src/__tests__/render-feature-contract.test-d.ts +49 -0
  674. package/src/__tests__/render-feature-diagnostics.unit.test.ts +149 -0
  675. package/src/__tests__/render-feature-docs.unit.test.ts +89 -0
  676. package/src/__tests__/render-feature-errors.unit.test.ts +47 -0
  677. package/src/__tests__/render-feature-gpu-work.integration.test.ts +316 -0
  678. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  679. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  680. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +90 -0
  681. package/src/__tests__/render-feature-prepared-errors.test-d.ts +79 -0
  682. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +80 -0
  683. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +72 -0
  684. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +36 -0
  685. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +74 -0
  686. package/src/__tests__/render-feature-prepared-graphics.unit.test.ts +121 -0
  687. package/src/__tests__/render-feature-public-surface.test-d.ts +57 -0
  688. package/src/__tests__/render-feature-retry.unit.test.ts +87 -0
  689. package/src/__tests__/render-feature-scheduling.unit.test.ts +110 -0
  690. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +137 -0
  691. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +146 -0
  692. package/src/__tests__/render-feature-visibility-context.test-d.ts +33 -0
  693. package/src/__tests__/render-feature-visibility-context.unit.test.ts +37 -0
  694. package/src/__tests__/render-feature-zero-work.unit.test.ts +76 -0
  695. package/src/__tests__/render-graph-compute-raster-gpu.ts +342 -0
  696. package/src/__tests__/render-graph-compute-raster.browser.test.ts +16 -0
  697. package/src/__tests__/render-graph-compute-raster.dawn.test.ts +22 -0
  698. package/src/__tests__/render-graph-hzb-gpu.ts +239 -0
  699. package/src/__tests__/render-graph-hzb.browser.test.ts +16 -0
  700. package/src/__tests__/render-graph-hzb.dawn.test.ts +23 -0
  701. package/src/__tests__/render-graph-primitives.unit.test.ts +22 -0
  702. package/src/__tests__/render-graph-storage-indirect-gpu.ts +162 -0
  703. package/src/__tests__/render-graph-storage-indirect.browser.test.ts +21 -0
  704. package/src/__tests__/render-graph-storage-indirect.dawn.test.ts +28 -0
  705. package/src/__tests__/render-scene-projection.unit.test.ts +168 -0
  706. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +121 -0
  707. package/src/__tests__/renderer-lifecycle.integration.test.ts +58 -0
  708. package/src/__tests__/rhi-backend-package-boundary.unit.test.ts +11 -0
  709. package/src/__tests__/scriptable-pack-consumer.test-d.ts +14 -0
  710. package/src/__tests__/shader-stage-surface.unit.test.ts +43 -0
  711. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  712. package/src/__tests__/ssao-kernel-surface.unit.test.ts +14 -0
  713. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  714. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  715. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  716. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  717. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  718. package/src/__tests__/surface-configuration.unit.test.ts +91 -0
  719. package/src/__tests__/texture-usage-surface.unit.test.ts +58 -0
  720. package/src/__tests__/typed-pipeline-topology.unit.test.ts +223 -0
  721. package/src/__tests__/urp-pipeline-targets.unit.test.ts +42 -0
  722. package/src/__tests__/urp-pipeline.unit.test.ts +14 -0
  723. package/src/__tests__/vertex-color-pipeline.unit.test.ts +132 -0
  724. package/src/__tests__/vertex-layout-consumer.unit.test.ts +25 -0
  725. package/src/__tests__/visibility-diagnostics.integration.test.ts +62 -0
  726. package/src/__tests__/visibility-extract.integration.test.ts +98 -0
  727. package/src/__tests__/visibility-extract.perf.test.ts +130 -0
  728. package/src/__tests__/visibility-feature-dedup.integration.test.ts +55 -0
  729. package/src/__tests__/visibility-hidden-report.unit.test.ts +36 -0
  730. package/src/__tests__/visibility-instances.integration.test.ts +46 -0
  731. package/src/__tests__/visibility-multi-world.integration.test.ts +86 -0
  732. package/src/__tests__/visibility-producer-matrix.integration.test.ts +168 -0
  733. package/src/__tests__/visibility-producer-matrix.unit.test.ts +96 -0
  734. package/src/__tests__/visibility-public-surface.test-d.ts +27 -0
  735. package/src/__tests__/visibility-resolver.unit.test.ts +85 -0
  736. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  737. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +60 -0
  738. package/src/__tests__/vocabulary.unit.test.ts +21 -0
  739. package/src/assembly/backend-contract.ts +57 -0
  740. package/src/assembly/factory.ts +8130 -0
  741. package/src/assembly/host-contract.ts +101 -0
  742. package/src/assembly/material/assembly.ts +48 -0
  743. package/src/assembly/material/pipeline-projection.ts +63 -0
  744. package/src/assets/asset-decoders.ts +158 -0
  745. package/src/assets/render-asset-port.ts +44 -0
  746. package/src/assets/resolve-render-asset.ts +13 -0
  747. package/src/authoring.ts +17 -0
  748. package/src/cluster-binner.ts +700 -0
  749. package/src/components/__tests__/points-lines-admission.unit.test.ts +219 -0
  750. package/src/components/__tests__/points-lines-schema.unit.test.ts +56 -0
  751. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  752. package/src/components/__tests__/schema-parity.unit.test.ts +25 -0
  753. package/src/components/__tests__/visibility-schema.unit.test.ts +35 -0
  754. package/src/components/camera.ts +512 -0
  755. package/src/components/directional-light.ts +120 -0
  756. package/src/components/glyph-text.ts +64 -0
  757. package/src/components/index.ts +54 -0
  758. package/src/components/instances.ts +206 -0
  759. package/src/components/layer.ts +69 -0
  760. package/src/components/light-helpers.ts +188 -0
  761. package/src/components/lines.ts +18 -0
  762. package/src/components/mesh-filter.ts +60 -0
  763. package/src/components/mesh-renderer.ts +61 -0
  764. package/src/components/point-light-shadow.ts +43 -0
  765. package/src/components/point-light.ts +65 -0
  766. package/src/components/points.ts +40 -0
  767. package/src/components/post-process-params.ts +35 -0
  768. package/src/components/scene-instance.ts +193 -0
  769. package/src/components/skybox-background.ts +103 -0
  770. package/src/components/skylight.ts +97 -0
  771. package/src/components/sort-key.ts +75 -0
  772. package/src/components/spot-light.ts +124 -0
  773. package/src/components/sprite-animation.ts +168 -0
  774. package/src/components/sprite-instances.ts +179 -0
  775. package/src/components/sprite-playback-mode.ts +79 -0
  776. package/src/components/sprite-region-override.ts +105 -0
  777. package/src/components/tile-layer.ts +167 -0
  778. package/src/components/tilemap.ts +48 -0
  779. package/src/components/visibility.ts +53 -0
  780. package/src/construct-renderer.ts +67 -0
  781. package/src/debug-draw-glue.ts +48 -0
  782. package/src/device/device-scope.ts +306 -0
  783. package/src/device/gpu-residency.ts +1822 -0
  784. package/src/device/resource-types.ts +20 -0
  785. package/src/engine-metrics.ts +82 -0
  786. package/src/errors/ecs-validation.ts +16 -0
  787. package/src/errors/index.ts +3 -0
  788. package/src/errors/recover.ts +161 -0
  789. package/src/errors/render.ts +1284 -0
  790. package/src/extract/visibility.ts +120 -0
  791. package/src/features/fullscreen.ts +46 -0
  792. package/src/features/host.ts +1363 -0
  793. package/src/features/morph/morph-feature.ts +377 -0
  794. package/src/features/plan.ts +447 -0
  795. package/src/features/prepared-gpu-work.ts +959 -0
  796. package/src/features/prepared-graphics-store.ts +449 -0
  797. package/src/features/prepared-graphics.ts +420 -0
  798. package/src/features/render-graph-compute.ts +69 -0
  799. package/src/features/render-graph-contribution.ts +75 -0
  800. package/src/features/render-graph-raster.ts +332 -0
  801. package/src/features/render-graph-resources.ts +38 -0
  802. package/src/features/targets.ts +70 -0
  803. package/src/features/types.ts +103 -0
  804. package/src/features/vocabulary.ts +24 -0
  805. package/src/fullscreen-post-process-pass.ts +363 -0
  806. package/src/glyph-text-layout-system.ts +421 -0
  807. package/src/gpu-driven/batch-topology.ts +245 -0
  808. package/src/gpu-driven/production-raster.ts +695 -0
  809. package/src/gpu-driven/view-gpu.ts +703 -0
  810. package/src/gpu-resource.ts +159 -0
  811. package/src/gpu-scene-schema.ts +136 -0
  812. package/src/gpu-scene.ts +722 -0
  813. package/src/gpu-stage.ts +9 -0
  814. package/src/gpu-texture-usage.ts +12 -0
  815. package/src/gpu-usage.ts +14 -0
  816. package/src/hdrp-buffers.ts +480 -0
  817. package/src/ibl/IblPipelineCache.ts +1006 -0
  818. package/src/ibl/skylight-bind-group.ts +513 -0
  819. package/src/index.ts +129 -0
  820. package/src/inspection-types.ts +80 -0
  821. package/src/instance-buffer-cache.ts +95 -0
  822. package/src/internal.ts +9 -0
  823. package/src/lifecycle.ts +168 -0
  824. package/src/light-buffer-layout.ts +346 -0
  825. package/src/materials.ts +214 -0
  826. package/src/mesh-material-bindings.ts +103 -0
  827. package/src/pbr-pipeline.ts +1137 -0
  828. package/src/pipeline/standard-forward-lane.ts +229 -0
  829. package/src/pipeline/standard-pipeline.ts +555 -0
  830. package/src/pipeline/standard-profile.ts +65 -0
  831. package/src/pipeline-builder.ts +382 -0
  832. package/src/pipeline-spec-types.ts +28 -0
  833. package/src/pipeline-spec.ts +1231 -0
  834. package/src/plugin.ts +69 -0
  835. package/src/points-lines/__tests__/bounds.unit.test.ts +21 -0
  836. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +157 -0
  837. package/src/points-lines/__tests__/inspection-lanes.integration.test.ts +146 -0
  838. package/src/points-lines/__tests__/inspection.unit.test.ts +173 -0
  839. package/src/points-lines/__tests__/lane-structural.integration.test.ts +122 -0
  840. package/src/points-lines/__tests__/points-lines.bench.ts +400 -0
  841. package/src/points-lines/__tests__/raster-lane.integration.test.ts +44 -0
  842. package/src/points-lines/__tests__/snapshot.unit.test.ts +101 -0
  843. package/src/points-lines/__tests__/view-ubo.unit.test.ts +73 -0
  844. package/src/points-lines/admission.ts +238 -0
  845. package/src/points-lines/bounds.ts +23 -0
  846. package/src/points-lines/expansion-cache.ts +215 -0
  847. package/src/points-lines/inspection.ts +97 -0
  848. package/src/points-lines/prepare.ts +177 -0
  849. package/src/points-lines/record.ts +125 -0
  850. package/src/points-lines/snapshot.ts +130 -0
  851. package/src/post-process-errors.ts +302 -0
  852. package/src/prepare/prepared-graphics-resolver.ts +456 -0
  853. package/src/record/__tests__/material-bg-cache.unit.test.ts +41 -0
  854. package/src/record/__tests__/material-slot-plan.unit.test.ts +44 -0
  855. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  856. package/src/record/__tests__/video-texture-view.unit.test.ts +90 -0
  857. package/src/record/frame-lighting.ts +1074 -0
  858. package/src/record/frame-snapshot.ts +500 -0
  859. package/src/record/frame-targets.ts +137 -0
  860. package/src/record/frame.ts +1598 -0
  861. package/src/record/helpers.ts +284 -0
  862. package/src/record/main-pass-geometry.ts +1065 -0
  863. package/src/record/main-pass-material.ts +1043 -0
  864. package/src/record/main-pass-sprite-draws.ts +1137 -0
  865. package/src/record/main-pass.ts +610 -0
  866. package/src/record/mesh-ssbo.ts +885 -0
  867. package/src/record/render-context.ts +384 -0
  868. package/src/record/shadow-pass.ts +698 -0
  869. package/src/record/skybox-post-pass.ts +593 -0
  870. package/src/record/typed-frame-graph.ts +461 -0
  871. package/src/record/view-ubo.ts +222 -0
  872. package/src/render-contract.ts +582 -0
  873. package/src/render-data.ts +385 -0
  874. package/src/render-graph-primitives.ts +811 -0
  875. package/src/render-pipeline.ts +259 -0
  876. package/src/render-system-extract.ts +4585 -0
  877. package/src/render-system.ts +1933 -0
  878. package/src/scene/render-scene-types.ts +67 -0
  879. package/src/scene/render-scene.ts +1087 -0
  880. package/src/scene-instances/post-spawn-resolve-joints.ts +165 -0
  881. package/src/shadow-atlas.ts +244 -0
  882. package/src/ssao-buffers.ts +334 -0
  883. package/src/ssao-config.ts +61 -0
  884. package/src/systems/active-camera.ts +116 -0
  885. package/src/systems/pass-selector.ts +49 -0
  886. package/src/systems/skin-palette-allocator.ts +251 -0
  887. package/src/systems/skin-palette-types.ts +14 -0
  888. package/src/systems/transparent-sort-config.ts +233 -0
  889. package/src/tilemap-chunk-extract-system.ts +1290 -0
  890. package/src/typed-render-graph-primitives.ts +541 -0
  891. package/src/typed-shadow-passes.ts +165 -0
@@ -0,0 +1,1231 @@
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 the ShaderCatalog implementation, 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
+ err,
27
+ KNOWN_PASS_KINDS,
28
+ type MaterialRenderState,
29
+ ok,
30
+ type PrimitiveTopology,
31
+ type Result,
32
+ type VertexAttributeMap,
33
+ } from '@forgeax/engine-types';
34
+ import { VertexColorVariantConflictError } from './errors/render';
35
+
36
+ export {
37
+ type BglKind,
38
+ type BindGroupLayoutDescriptorOutput,
39
+ buildBindGroupLayoutDescriptor,
40
+ createHdrpBindGroupLayoutDescriptor,
41
+ } from './pbr-pipeline';
42
+
43
+ // Re-export KNOWN_PASS_KINDS from @forgeax/engine-types for single-file discoverability (charter F1).
44
+ export { KNOWN_PASS_KINDS };
45
+
46
+ /**
47
+ * The engine-owned deferred material target layout. `fs_gbuffer` returns
48
+ * normal+roughness, albedo+metallic, and emissive+AO in this order.
49
+ */
50
+ export const DEFERRED_COLOR_FORMATS: readonly GPUTextureFormat[] = [
51
+ 'rgba16float',
52
+ 'rgba8unorm',
53
+ 'rgba16float',
54
+ ];
55
+
56
+ /** Derive the color attachment shape for a material pass kind. */
57
+ export function colorFormatsForPassKind(
58
+ passKind: string,
59
+ defaultColorFormat: GPUTextureFormat,
60
+ ): readonly GPUTextureFormat[] {
61
+ if (passKindPolicyTable[passKind]?.shape === 'depth-only') return [];
62
+ if (passKind === 'deferred') return DEFERRED_COLOR_FORMATS;
63
+ return [defaultColorFormat];
64
+ }
65
+
66
+ // ══════════════════════════════════════════════════════════════════════════════
67
+ // PipelineSpec — immutable 4-axis data description (D-7: business-agnostic)
68
+ // ══════════════════════════════════════════════════════════════════════════════
69
+
70
+ /**
71
+ * Pipeline specification — immutable 4-axis data that completely determines
72
+ * what `device.createRenderPipeline(...)` does for a material shader pass.
73
+ *
74
+ * The 4 axes are:
75
+ * - `shader`: which WGSL source + material param schema + pass kind + variant set
76
+ * - `attachments`: color/depth/stencil formats + sample count (MSAA)
77
+ * - `geometry`: primitive topology + vertex attribute layout + index format
78
+ * - `renderState`: optional per-material render-state overrides (blend/cull/depth/stencil)
79
+ *
80
+ * Business-agnostic: no `'pbr'` / `'sprite'` / `'skybox'` strings pollute this
81
+ * type. BGL shape taxonomy is derived from `ShaderCatalog` internal reflection
82
+ * and never appears on the spec surface (plan-strategy D-7).
83
+ *
84
+ * @see plan-strategy §1 (4-axis) · D-7 (business-agnostic) · requirements §3.1
85
+ */
86
+ export type { PipelineSpec } from './pipeline-spec-types';
87
+
88
+ import type { PipelineSpec } from './pipeline-spec-types';
89
+ // ══════════════════════════════════════════════════════════════════════════════
90
+ // PipelineSpecError — closed union (5 + 2 transit codes)
91
+ // ══════════════════════════════════════════════════════════════════════════════
92
+
93
+ /**
94
+ * Closed union of PipelineSpec error codes.
95
+ *
96
+ * 5 business codes:
97
+ * - `'spec-inconsistent'`: axis mutual exclusion violated
98
+ * - `'unknown-pass-kind'`: passKind not in KNOWN_PASS_KINDS or registered
99
+ * - `'shader-bgl-reflection-mismatch'`: reflected BGL shape != shader declaration
100
+ * - `'attachment-format-incompatible'`: depth/stencil format vs PSO mismatch
101
+ * - `'unsupported-vertex-layout'`: vertex attributes don't match shader vs_main
102
+ *
103
+ * 2 transit codes:
104
+ * - `'pipeline-build-failed'`: wraps RhiError from device.createRenderPipeline
105
+ * - `'shader-not-registered'`: ShaderCatalog lookup returned undefined
106
+ *
107
+ * @see requirements §3.4 · AC-10 · charter P3
108
+ */
109
+ export type PipelineSpecErrorCode =
110
+ | 'spec-inconsistent'
111
+ | 'unknown-pass-kind'
112
+ | 'shader-bgl-reflection-mismatch'
113
+ | 'attachment-format-incompatible'
114
+ | 'unsupported-vertex-layout'
115
+ | 'pipeline-build-failed'
116
+ | 'shader-not-registered';
117
+
118
+ /**
119
+ * Structured pipeline-spec error — carries `.code` (discriminated union) +
120
+ * `.detail` (narrowed per code) + `.hint` (AI-user actionable prose).
121
+ *
122
+ * Inherits from `Error` so it integrates with existing catch blocks; the
123
+ * `.code` field enables exhaustive `switch` narrowing without string parsing
124
+ * (charter P3).
125
+ */
126
+ export class PipelineSpecError extends Error {
127
+ readonly code: PipelineSpecErrorCode;
128
+ /**
129
+ * Narrowed detail payload — shape depends on `code`.
130
+ *
131
+ * - `'spec-inconsistent'`: `{ reason: string }`
132
+ * - `'unknown-pass-kind'`: `{ expected: readonly string[]; actual: string; hint?: string }`
133
+ * - `'shader-bgl-reflection-mismatch'`: `{ reflected: unknown; declared: unknown }`
134
+ * - `'attachment-format-incompatible'`: `{ reason: string; expected?: string; actual?: string }`
135
+ * - `'unsupported-vertex-layout'`: `{ specAttrs: string[]; shaderAttrs: string[] }`
136
+ * - `'pipeline-build-failed'`: `{ gpuMessage?: string; cause?: unknown }`
137
+ * - `'shader-not-registered'`: `{ shaderId: string; hint?: string }`
138
+ */
139
+ readonly detail: Record<string, unknown>;
140
+
141
+ constructor(args: {
142
+ code: PipelineSpecErrorCode;
143
+ detail: Record<string, unknown>;
144
+ hint?: string;
145
+ }) {
146
+ super(
147
+ args.hint !== undefined
148
+ ? `PipelineSpecError [${args.code}]: ${args.hint}`
149
+ : `PipelineSpecError [${args.code}]`,
150
+ );
151
+ this.name = 'PipelineSpecError';
152
+ this.code = args.code;
153
+ this.detail = args.detail;
154
+ }
155
+ }
156
+
157
+ // ══════════════════════════════════════════════════════════════════════════════
158
+ // renderStateHashSuffix — deterministic hash of MaterialRenderState
159
+ // ══════════════════════════════════════════════════════════════════════════════
160
+
161
+ /**
162
+ * Material snapshots hand the renderer immutable render-state objects. Keep
163
+ * the serialized suffix by object identity just like the vertex-layout
164
+ * digest below; the hot path otherwise sorts keys and serializes the same
165
+ * state once per renderable. Callers must not mutate a MaterialRenderState
166
+ * after passing it to the renderer (the PipelineSpec contract is immutable).
167
+ */
168
+ const RENDER_STATE_HASH_CACHE = new WeakMap<object, string>();
169
+
170
+ /**
171
+ * Deterministic hash suffix for MaterialRenderState (sorted keys, JSON.stringify).
172
+ *
173
+ * Returns `''` when `renderState` is `undefined` or has zero entries,
174
+ * preserving cache-key byte-compatibility with the pre-M1 shape.
175
+ */
176
+ export function renderStateHash(renderState: MaterialRenderState | undefined): string {
177
+ if (renderState === undefined) return '';
178
+ const cached = RENDER_STATE_HASH_CACHE.get(renderState);
179
+ if (cached !== undefined) return cached;
180
+ const sorted = Object.keys(renderState).sort();
181
+ if (sorted.length === 0) {
182
+ RENDER_STATE_HASH_CACHE.set(renderState, '');
183
+ return '';
184
+ }
185
+ const payload: Record<string, unknown> = {};
186
+ for (const k of sorted) {
187
+ const v = renderState[k as keyof MaterialRenderState];
188
+ if (v !== undefined) payload[k] = v;
189
+ }
190
+ const result = `:${JSON.stringify(payload)}`;
191
+ RENDER_STATE_HASH_CACHE.set(renderState, result);
192
+ return result;
193
+ }
194
+
195
+ // ══════════════════════════════════════════════════════════════════════════════
196
+ // 6 pure derive functions (M1-T2)
197
+ // ══════════════════════════════════════════════════════════════════════════════
198
+
199
+ /**
200
+ * Compute a deterministic cache key from a PipelineSpec.
201
+ *
202
+ * The key covers all 4 axes + BGL shape hash (derived from ShaderCatalog
203
+ * reflection via {@link deriveBglShapeFromShader}). Two specs that produce
204
+ * the same cache key MUST produce byte-identical PSO descriptors.
205
+ *
206
+ * Algorithm: concatenate each axis segment with `:` separators, hash the
207
+ * BGL shape for compactness, and emit a single cache-key string.
208
+ *
209
+ * @see plan-strategy §3.1 · requirements AC-02
210
+ */
211
+ export function cacheKeyOf(spec: PipelineSpec): string {
212
+ const { shader, attachments, geometry, renderState } = spec;
213
+ const topoSegment = geometry.topology;
214
+ const stripSegment =
215
+ (topoSegment === 'line-strip' || topoSegment === 'triangle-strip') &&
216
+ geometry.stripIndexFormat !== undefined
217
+ ? `:${geometry.stripIndexFormat}`
218
+ : '';
219
+
220
+ // The geometry owner publishes one immutable projection. Legacy callers may
221
+ // still provide only the map; derive the same projection at this boundary.
222
+ const vlDigest =
223
+ geometry.vertexLayoutProjection?.digest ??
224
+ deriveVertexLayoutProjection(geometry.vertexLayout).digest;
225
+
226
+ const uvSetCountSegment =
227
+ geometry.shaderUvSetCount !== undefined ? `:uvsc${geometry.shaderUvSetCount}` : '';
228
+
229
+ // bug-20260708 M2 (b): sentinel `~` distinguishes `variantSet=undefined`
230
+ // (no-variant / default-variant request) from canonical all-true key `''`
231
+ // (all variant axes true). Prior `?? ''` collapsed the two into the same
232
+ // cache key, causing the first-cached pipeline to win and unrelated
233
+ // variantSet requests to reuse its shader module (research R-11 / R-12).
234
+ // `~` (ASCII 0x7E) is a reserved sentinel char — no legitimate
235
+ // variantSet literal contains it; guarded by
236
+ // `pipeline-cache-keying.unit.test.ts` sentinel-conflict assertions.
237
+ const variantSegment = shader.variantSet === undefined ? '~' : shader.variantSet;
238
+ return (
239
+ [
240
+ shader.id,
241
+ shader.passKind,
242
+ variantSegment,
243
+ attachments.colorFormats.join(','),
244
+ attachments.depthFormat ?? '',
245
+ String(attachments.sampleCount),
246
+ topoSegment,
247
+ stripSegment,
248
+ `vl:${vlDigest}`,
249
+ renderStateHash(renderState),
250
+ ].join(':') + uvSetCountSegment
251
+ );
252
+ }
253
+
254
+ /**
255
+ * Reconcile the authored vertex-color shader axis with the geometry-owned
256
+ * projection. COLOR_0 is a geometry fact and cannot be selected independently
257
+ * by a material variant.
258
+ */
259
+ export function variantSetFromVertexLayoutProjection(
260
+ projection: VertexLayoutProjection,
261
+ authoredVariantSet: string | undefined,
262
+ ): Result<string, VertexColorVariantConflictError> {
263
+ const projected = projection.attributes.some((attribute) => attribute.key === 'color');
264
+ const axis = `VERTEX_COLOR_AVAILABLE=${projected ? 'true' : 'false'}`;
265
+ if (authoredVariantSet === undefined) return ok(axis);
266
+ if (projected && authoredVariantSet === '') return ok(authoredVariantSet);
267
+
268
+ const authoredParts = authoredVariantSet.split('+');
269
+ const authoredColorPart = authoredParts.find((part) =>
270
+ part.startsWith('VERTEX_COLOR_AVAILABLE='),
271
+ );
272
+ if (authoredColorPart === undefined) {
273
+ const parts = authoredParts.filter((part) => part.length > 0);
274
+ parts.push(axis);
275
+ return ok(parts.join('+'));
276
+ }
277
+
278
+ const authoredValue = authoredColorPart.slice('VERTEX_COLOR_AVAILABLE='.length);
279
+ const authored = authoredValue === 'true';
280
+ if ((authoredValue !== 'true' && authoredValue !== 'false') || authored !== projected) {
281
+ return err(new VertexColorVariantConflictError(authoredValue, projected));
282
+ }
283
+ const parts = authoredParts.filter(
284
+ (part) => part.length > 0 && !part.startsWith('VERTEX_COLOR_AVAILABLE='),
285
+ );
286
+ parts.push(axis);
287
+ return ok(parts.join('+'));
288
+ }
289
+
290
+ /**
291
+ * Build a `GPURenderPipelineDescriptor` from a PipelineSpec + shader modules.
292
+ *
293
+ * Pure derivation: same (spec, modules) always produces the same descriptor.
294
+ * Consumed by `getOrBuildPipeline` on cache miss; also available as a public
295
+ * helper for AI users who want the descriptor shape without going through the
296
+ * cache entrypoint.
297
+ *
298
+ * @param spec - the pipeline spec (4 axes)
299
+ * @param modules - `{ vertex: GPUShaderModule; fragment: GPUShaderModule }`
300
+ * @returns a complete WebGPU render-pipeline descriptor
301
+ * @see plan-strategy §3.2 · requirements AC-02
302
+ */
303
+ export function buildPipelineDescriptor(
304
+ spec: PipelineSpec,
305
+ modules: {
306
+ vertex: unknown;
307
+ fragment: unknown;
308
+ vertexEntryPoint?: string;
309
+ fragmentEntryPoint?: string;
310
+ layout?: unknown;
311
+ },
312
+ ): Record<string, unknown> {
313
+ // M2-T4: derive vertex buffers from spec.geometry.vertexLayout via
314
+ // deriveVertexBufferLayout (imported from vertex-attribute-layout.ts).
315
+ // Empty vertexLayout (fullscreen-post passes) → [].
316
+ // Non-empty (material shaders) → interleaved single-buffer layout.
317
+ //
318
+ // Entry points default to 'vs_main' / 'fs_main' for the 3 standard material
319
+ // shaders; fullscreen-post passes (skybox 'skybox_fs', SSAO 'vs_ssao' / 'fs_ssao_calc')
320
+ // pass custom entry points through the modules parameter.
321
+ //
322
+ // The optional `layout` field, when present, is forwarded to the descriptor
323
+ // so that the provider can detect it is already set and avoid overwriting.
324
+
325
+ const { attachments, geometry, renderState } = spec;
326
+
327
+ // A supplied projection is the geometry owner's immutable GPU descriptor.
328
+ // Do not re-derive it from a possibly stale attribute map.
329
+ const vertexBuffers =
330
+ geometry.vertexLayoutProjection === undefined
331
+ ? deriveVertexBufferLayout(geometry.vertexLayout, {
332
+ ...(geometry.shaderUvSetCount !== undefined
333
+ ? { shaderUvSetCount: geometry.shaderUvSetCount }
334
+ : {}),
335
+ })
336
+ : geometry.vertexLayoutProjection.attributes.length === 0
337
+ ? []
338
+ : [
339
+ {
340
+ arrayStride: geometry.vertexLayoutProjection.arrayStride,
341
+ attributes: geometry.vertexLayoutProjection.attributes.map(
342
+ ({ shaderLocation, offset, format }) => ({
343
+ shaderLocation,
344
+ offset,
345
+ format,
346
+ }),
347
+ ),
348
+ },
349
+ ];
350
+
351
+ const descriptor: Record<string, unknown> = {
352
+ vertex: {
353
+ module: modules.vertex,
354
+ entryPoint: modules.vertexEntryPoint ?? 'vs_main',
355
+ buffers: vertexBuffers,
356
+ },
357
+ };
358
+
359
+ // Fragment stage: absent for shadow-caster (depth-only), present for forward.
360
+ if (attachments.colorFormats.length > 0) {
361
+ descriptor.fragment = {
362
+ module: modules.fragment,
363
+ entryPoint: modules.fragmentEntryPoint ?? 'fs_main',
364
+ targets: attachments.colorFormats.map((fmt) => {
365
+ const target: Record<string, unknown> = { format: fmt };
366
+ if (renderState?.blend !== undefined) {
367
+ target.blend = renderState.blend;
368
+ }
369
+ return target;
370
+ }),
371
+ };
372
+ }
373
+
374
+ // Layout: forward if provided by caller (fullscreen-post passes set it).
375
+ if (modules.layout !== undefined) {
376
+ descriptor.layout = modules.layout;
377
+ }
378
+
379
+ // Primitive state.
380
+ const primitive: Record<string, unknown> = {
381
+ topology: geometry.topology,
382
+ cullMode: renderState?.cullMode ?? 'back',
383
+ frontFace: renderState?.frontFace ?? 'ccw',
384
+ };
385
+ if (geometry.topology.endsWith('strip') && geometry.stripIndexFormat !== undefined) {
386
+ primitive.stripIndexFormat = geometry.stripIndexFormat;
387
+ }
388
+ descriptor.primitive = primitive;
389
+
390
+ // Depth-stencil state.
391
+ if (attachments.depthFormat !== undefined) {
392
+ const ds: Record<string, unknown> = {
393
+ format: attachments.depthFormat,
394
+ depthWriteEnabled: renderState?.depthWriteEnabled ?? true,
395
+ depthCompare: renderState?.depthCompare ?? 'less',
396
+ };
397
+ if (renderState?.stencilReadMask !== undefined) {
398
+ ds.stencilReadMask = renderState.stencilReadMask;
399
+ }
400
+ if (renderState?.stencilWriteMask !== undefined) {
401
+ ds.stencilWriteMask = renderState.stencilWriteMask;
402
+ }
403
+ if (renderState?.stencil !== undefined) {
404
+ ds.stencilFront = renderState.stencil;
405
+ ds.stencilBack = renderState.stencil;
406
+ }
407
+ descriptor.depthStencil = ds;
408
+ }
409
+
410
+ // Multisample: absent for sampleCount=1 (undefined). For each value > 1,
411
+ // emit { count: sampleCount } so forward-compat sample counts (2, 8, …)
412
+ // flow through to the descriptor without requiring a type change.
413
+ if (attachments.sampleCount > 1) {
414
+ descriptor.multisample = {
415
+ count: attachments.sampleCount,
416
+ ...(renderState?.alphaToCoverageEnabled === true && { alphaToCoverageEnabled: true }),
417
+ };
418
+ }
419
+
420
+ return descriptor;
421
+ }
422
+
423
+ // ══════════════════════════════════════════════════════════════════════════════
424
+ // passKindPolicyTable — closed map: passKind → attachment shape + default ops
425
+ // ══════════════════════════════════════════════════════════════════════════════
426
+
427
+ /**
428
+ * Default colour-attachment ops carried by a passKind policy.
429
+ *
430
+ * `clearValue` is `undefined` for `loadOp='load'` policies (no clear value
431
+ * is emitted into the descriptor when the prior contents are loaded).
432
+ */
433
+ export interface AttachmentColorOps {
434
+ readonly loadOp: 'clear' | 'load';
435
+ readonly storeOp: 'store' | 'discard';
436
+ readonly clearValue: GPUColor | undefined;
437
+ }
438
+
439
+ /**
440
+ * Default depth-attachment ops carried by a passKind policy.
441
+ *
442
+ * `stencilLoadOp` / `stencilStoreOp` are absent on the policy itself — the
443
+ * stencil-op gate is auto-derived from `specAttachments.depthFormat` at call
444
+ * time (`'depth24plus-stencil8'` → `'clear'+'discard'`; everything else
445
+ * elides stencil ops). This collapses the R3/R5 stencil-op duplicates that
446
+ * previously lived inline at every forward-pass beginRenderPass call site.
447
+ */
448
+ export interface AttachmentDepthOps {
449
+ readonly loadOp: 'clear' | 'load';
450
+ readonly storeOp: 'store' | 'discard';
451
+ readonly clearValue: number;
452
+ }
453
+
454
+ /**
455
+ * Attachment policy for a single passKind — declares the colour / depth shape
456
+ * the pass produces and the default load/store ops. Per-call-site overrides
457
+ * (skybox vs main forward differing on `colorLoadOp`, sprite-split forward
458
+ * differing on both `colorLoadOp` and `depthLoadOp`) flow through the
459
+ * `options` parameter of {@link buildBeginRenderPassDescriptor}.
460
+ *
461
+ * `shape` discriminator drives which attachment slots the descriptor emits:
462
+ * - `'depth-only'` → empty `colorAttachments[]`, `depthStencilAttachment` set
463
+ * - `'color-only'` → populated `colorAttachments[]`, no `depthStencilAttachment`
464
+ * - `'color-and-depth'` → both
465
+ */
466
+ export interface PassKindAttachmentPolicy {
467
+ readonly shape: 'depth-only' | 'color-only' | 'color-and-depth';
468
+ readonly defaultColorOps: AttachmentColorOps | undefined;
469
+ readonly defaultDepthOps: AttachmentDepthOps | undefined;
470
+ }
471
+
472
+ /**
473
+ * Closed map of passKind → attachment policy. Covers the 10 attachment shapes
474
+ * the runtime ships (per plan-strategy M4):
475
+ *
476
+ * 1. `'forward'` — main geometry pass: color+depth(+stencil-gated)
477
+ * 2. `'deferred'` — HDRP G-Buffer geometry pass: MRT color+depth
478
+ * 3. `'shadow-caster'` — directional shadow caster: depth-only
479
+ * 4. `'point-shadow-caster'` — HDRP point-shadow caster: depth-only
480
+ * 5. `'skybox'` — fullscreen skybox: color-only clear/store
481
+ * 6. `'tonemap'` — HDR→LDR tonemap fullscreen: color-only clear/store
482
+ * 7. `'bloom-bright'` / `'bloom-blur'` — bloom downsample/blur: color-only
483
+ * clear/store
484
+ * 8. `'bloom-composite'` — bloom add-back: color-only load/store (NOT clear)
485
+ * 9. `'fxaa'` — fullscreen FXAA: color-only clear/store
486
+ * 10. `'post-process'` — generic fullscreen primitive (SSAO, render-graph
487
+ * fullscreen-post-process-pass dispatcher, M2 tonemap pre-warm slot):
488
+ * color-only clear/store
489
+ *
490
+ * Sprite-split forward sub-pass reuses the `'forward'` policy with
491
+ * `options.colorLoadOp='load'` + `options.depthLoadOp='load'`.
492
+ *
493
+ * Stencil-op gate is NOT in this table — it is derived from
494
+ * `specAttachments.depthFormat` inside the helper (depth24plus-stencil8
495
+ * → emit `stencilLoadOp:'clear' / stencilStoreOp:'discard'`).
496
+ */
497
+ export const passKindPolicyTable: Readonly<Record<string, PassKindAttachmentPolicy>> = {
498
+ forward: {
499
+ shape: 'color-and-depth',
500
+ defaultColorOps: {
501
+ loadOp: 'clear',
502
+ storeOp: 'store',
503
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
504
+ },
505
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
506
+ },
507
+ deferred: {
508
+ shape: 'color-and-depth',
509
+ defaultColorOps: {
510
+ loadOp: 'clear',
511
+ storeOp: 'store',
512
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
513
+ },
514
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
515
+ },
516
+ 'shadow-caster': {
517
+ shape: 'depth-only',
518
+ defaultColorOps: undefined,
519
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
520
+ },
521
+ 'point-shadow-caster': {
522
+ shape: 'depth-only',
523
+ defaultColorOps: undefined,
524
+ defaultDepthOps: { loadOp: 'clear', storeOp: 'store', clearValue: 1 },
525
+ },
526
+ skybox: {
527
+ shape: 'color-only',
528
+ defaultColorOps: {
529
+ loadOp: 'clear',
530
+ storeOp: 'store',
531
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
532
+ },
533
+ defaultDepthOps: undefined,
534
+ },
535
+ tonemap: {
536
+ shape: 'color-only',
537
+ defaultColorOps: {
538
+ loadOp: 'clear',
539
+ storeOp: 'store',
540
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
541
+ },
542
+ defaultDepthOps: undefined,
543
+ },
544
+ 'bloom-bright': {
545
+ shape: 'color-only',
546
+ defaultColorOps: {
547
+ loadOp: 'clear',
548
+ storeOp: 'store',
549
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
550
+ },
551
+ defaultDepthOps: undefined,
552
+ },
553
+ 'bloom-blur': {
554
+ shape: 'color-only',
555
+ defaultColorOps: {
556
+ loadOp: 'clear',
557
+ storeOp: 'store',
558
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
559
+ },
560
+ defaultDepthOps: undefined,
561
+ },
562
+ 'bloom-composite': {
563
+ shape: 'color-only',
564
+ defaultColorOps: {
565
+ loadOp: 'load',
566
+ storeOp: 'store',
567
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
568
+ },
569
+ defaultDepthOps: undefined,
570
+ },
571
+ fxaa: {
572
+ shape: 'color-only',
573
+ defaultColorOps: {
574
+ loadOp: 'clear',
575
+ storeOp: 'store',
576
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
577
+ },
578
+ defaultDepthOps: undefined,
579
+ },
580
+ 'post-process': {
581
+ shape: 'color-only',
582
+ defaultColorOps: {
583
+ loadOp: 'clear',
584
+ storeOp: 'store',
585
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
586
+ },
587
+ defaultDepthOps: undefined,
588
+ },
589
+ };
590
+
591
+ /**
592
+ * Build a `GPURenderPassDescriptor` from spec attachments + resolved views +
593
+ * a passKind policy lookup.
594
+ *
595
+ * The helper is the single SSOT for `device.beginRenderPass(...)` descriptor
596
+ * shape — every record-stage call site routes through it (plan-strategy M4
597
+ * AC-06). It dispatches on `passKindPolicyTable[passKind]` to pick the
598
+ * attachment shape (depth-only / color-only / color-and-depth) and applies
599
+ * default color/depth load+store ops; per-call overrides (sprite-split's
600
+ * `loadOp:'load'`, main pass's dynamic `mainColorLoadOp`, skybox's specific
601
+ * clearColor) flow through `options`.
602
+ *
603
+ * Stencil-op gate is auto-derived from `specAttachments.depthFormat`:
604
+ * - `'depth24plus-stencil8'` → emits `stencilLoadOp:'clear', stencilStoreOp:'discard'`
605
+ * - every other depth format → omits stencil ops entirely
606
+ *
607
+ * This collapses the R3/R5 stencil-op duplicates that previously lived inline
608
+ * at every forward-pass beginRenderPass site.
609
+ *
610
+ * @param specAttachments - the attachments axis from a PipelineSpec
611
+ * @param viewBindings - resolved texture views: `{ colorViews, depthView?, resolveTargets? }`
612
+ * @param passKind - one of the keys in {@link passKindPolicyTable}
613
+ * @param options - per-call ops overrides (loadOp / clearValue / label)
614
+ * @returns a WebGPU render-pass descriptor
615
+ * @throws PipelineSpecError(`'unknown-pass-kind'`) when passKind is not registered
616
+ * @see plan-strategy M4 · requirements AC-06
617
+ */
618
+ export function buildBeginRenderPassDescriptor(
619
+ specAttachments: PipelineSpec['attachments'],
620
+ viewBindings: {
621
+ readonly colorViews: readonly unknown[];
622
+ readonly resolveTargets?: readonly (unknown | undefined)[];
623
+ readonly depthView?: unknown;
624
+ },
625
+ passKind: string,
626
+ options?: {
627
+ readonly colorLoadOp?: 'clear' | 'load';
628
+ readonly colorStoreOp?: 'store' | 'discard';
629
+ readonly clearColor?: GPUColor;
630
+ readonly depthLoadOp?: 'clear' | 'load';
631
+ readonly depthStoreOp?: 'store' | 'discard';
632
+ readonly label?: string;
633
+ },
634
+ ): Record<string, unknown> {
635
+ const policy = passKindPolicyTable[passKind];
636
+ if (policy === undefined) {
637
+ throw new PipelineSpecError({
638
+ code: 'unknown-pass-kind',
639
+ detail: { expected: Object.keys(passKindPolicyTable), actual: passKind },
640
+ hint: `passKind '${passKind}' is not in passKindPolicyTable; register an attachment policy or pick an existing one (e.g. 'post-process' for fullscreen-quad passes)`,
641
+ });
642
+ }
643
+
644
+ const out: Record<string, unknown> = {};
645
+ if (options?.label !== undefined) {
646
+ out.label = options.label;
647
+ }
648
+
649
+ // Colour attachments: depth-only → empty array; otherwise iterate colorViews
650
+ // and apply policy default ops + per-call overrides. resolveTargets[i] === undefined
651
+ // means "no resolve for this slot"; only present slots emit a `resolveTarget`.
652
+ if (policy.shape === 'depth-only') {
653
+ out.colorAttachments = [];
654
+ } else {
655
+ const colorOps = policy.defaultColorOps;
656
+ if (colorOps === undefined) {
657
+ throw new PipelineSpecError({
658
+ code: 'spec-inconsistent',
659
+ detail: {
660
+ reason: 'policy-shape-color-without-colorOps',
661
+ actual: passKind,
662
+ },
663
+ hint: `passKind '${passKind}' has shape='${policy.shape}' but no defaultColorOps; fix passKindPolicyTable entry`,
664
+ });
665
+ }
666
+ const loadOp = options?.colorLoadOp ?? colorOps.loadOp;
667
+ const storeOp = options?.colorStoreOp ?? colorOps.storeOp;
668
+ const clearValue = options?.clearColor ?? colorOps.clearValue;
669
+
670
+ out.colorAttachments = viewBindings.colorViews.map((view, i) => {
671
+ const slot: Record<string, unknown> = {
672
+ view,
673
+ loadOp,
674
+ storeOp,
675
+ };
676
+ const resolveTarget = viewBindings.resolveTargets?.[i];
677
+ if (resolveTarget !== undefined) {
678
+ slot.resolveTarget = resolveTarget;
679
+ }
680
+ // Emit clearValue only when load is 'clear' AND a value is available.
681
+ if (loadOp === 'clear' && clearValue !== undefined) {
682
+ slot.clearValue = clearValue;
683
+ }
684
+ return slot;
685
+ });
686
+ }
687
+
688
+ // Depth-stencil attachment: emitted iff policy declares depth ops AND
689
+ // the spec carries a depthFormat. Stencil ops auto-derived from format.
690
+ if (policy.shape !== 'color-only' && policy.defaultDepthOps !== undefined) {
691
+ const dOps = policy.defaultDepthOps;
692
+ const depthLoadOp = options?.depthLoadOp ?? dOps.loadOp;
693
+ const depthStoreOp = options?.depthStoreOp ?? dOps.storeOp;
694
+ const ds: Record<string, unknown> = {
695
+ view: viewBindings.depthView,
696
+ depthLoadOp,
697
+ depthStoreOp,
698
+ };
699
+ if (depthLoadOp === 'clear') {
700
+ ds.depthClearValue = dOps.clearValue;
701
+ }
702
+ // Stencil-op gate: only depth24plus-stencil8 carries a stencil aspect.
703
+ if (specAttachments.depthFormat === 'depth24plus-stencil8') {
704
+ ds.stencilClearValue = 0;
705
+ ds.stencilLoadOp = 'clear';
706
+ ds.stencilStoreOp = 'discard';
707
+ }
708
+ out.depthStencilAttachment = ds;
709
+ }
710
+
711
+ return out;
712
+ }
713
+
714
+ /**
715
+ * Validate a PipelineSpec before attempting to build.
716
+ *
717
+ * Fail-fast checks (charter P5) covering axis mutual-exclusion rules.
718
+ * Returns `Result<void, PipelineSpecError>` — ok for valid specs,
719
+ * err with structured code + detail for invalid ones.
720
+ *
721
+ * Checks:
722
+ * 1. `sampleCount=4` with empty `colorFormats` → `'spec-inconsistent'`
723
+ * 2. Pass kind not in `KNOWN_PASS_KINDS` → `'unknown-pass-kind'`
724
+ * 3. `depthFormat` undefined but `renderState` implies depth testing →
725
+ * `'attachment-format-incompatible'`
726
+ *
727
+ * @see plan-strategy §3.2 · requirements AC-02 · charter P5
728
+ */
729
+ export function validateSpec(
730
+ spec: PipelineSpec,
731
+ ):
732
+ | { ok: true }
733
+ | { ok: false; code: PipelineSpecErrorCode; detail: Record<string, unknown>; hint?: string } {
734
+ // Check 1: sampleCount=4 with empty colorFormats is inconsistent —
735
+ // multisample requires a colour target to resolve to.
736
+ if (spec.attachments.sampleCount === 4 && spec.attachments.colorFormats.length === 0) {
737
+ return {
738
+ ok: false,
739
+ code: 'spec-inconsistent',
740
+ detail: { reason: 'sample-count-format-incompatible' },
741
+ hint: 'sampleCount=4 requires at least one colorFormat; shadow-caster (depth-only) passes should use sampleCount=1',
742
+ };
743
+ }
744
+
745
+ // Check 2: unknown pass kind
746
+ if (!KNOWN_PASS_KINDS.includes(spec.shader.passKind)) {
747
+ return {
748
+ ok: false,
749
+ code: 'unknown-pass-kind',
750
+ detail: { expected: KNOWN_PASS_KINDS, actual: spec.shader.passKind },
751
+ hint: `passKind '${spec.shader.passKind}' is not in KNOWN_PASS_KINDS; register custom pass kinds via ShaderCatalog`,
752
+ };
753
+ }
754
+
755
+ // Check 3: depth-testing renderState without a depthFormat
756
+ const depthOnly = passKindPolicyTable[spec.shader.passKind]?.shape === 'depth-only';
757
+ const depthRequired = !!spec.renderState?.depthCompare || depthOnly;
758
+ if (!spec.attachments.depthFormat && depthRequired) {
759
+ return {
760
+ ok: false,
761
+ code: 'attachment-format-incompatible',
762
+ detail: {
763
+ reason: 'depth-requirement-without-depth-format',
764
+ expected: 'depthFormat must be set when depth testing or a depth-only pass is requested',
765
+ actual: `depthFormat=${String(spec.attachments.depthFormat)}, depthCompare=${spec.renderState?.depthCompare}`,
766
+ },
767
+ hint: 'set attachments.depthFormat (e.g. depth24plus-stencil8 or depth32float) when renderState specifies depthCompare',
768
+ };
769
+ }
770
+
771
+ return { ok: true };
772
+ }
773
+
774
+ // ══════════════════════════════════════════════════════════════════════════════
775
+ // PipelineCache — Map<string, RenderPipeline> container (D-12)
776
+ // ══════════════════════════════════════════════════════════════════════════════
777
+
778
+ /**
779
+ * Pipeline cache — Map from cacheKeyOf(spec) to opaque RenderPipeline handle.
780
+ *
781
+ * Constructed once at createRenderer boot time; shared across all call sites.
782
+ * Consumers call `getOrBuildPipeline(spec, deviceProvider, cache)` — the
783
+ * entrypoint does cache lookup internally; consumers never touch the Map
784
+ * directly.
785
+ *
786
+ * @see plan-strategy D-12 · requirements §3.2
787
+ */
788
+ export type PipelineCache = Map<string, unknown>;
789
+
790
+ // ══════════════════════════════════════════════════════════════════════════════
791
+ // getOrBuildPipeline — single entrypoint (D-12)
792
+ // ══════════════════════════════════════════════════════════════════════════════
793
+
794
+ /**
795
+ * Device factory interface consumed by {@link getOrBuildPipeline}.
796
+ *
797
+ * Slim abstraction: only `createRenderPipeline` is needed; the entrypoint
798
+ * does not depend on the full `RhiDevice` interface so it can be tested
799
+ * with a mock.
800
+ */
801
+ export interface PipelineDeviceProvider {
802
+ createRenderPipeline(
803
+ descriptor: Record<string, unknown>,
804
+ ): { ok: true; value: unknown } | { ok: false; error: unknown };
805
+ }
806
+
807
+ /**
808
+ * Single entrypoint for obtaining a render pipeline from a spec.
809
+ *
810
+ * Cache-hit path: key = cacheKeyOf(spec), returns cached handle immediately.
811
+ * Cache-miss path: validates spec → builds descriptor → calls device.createRenderPipeline
812
+ * → caches result → returns handle.
813
+ * Build failure: throws PipelineSpecError (charter P3 fail-fast, no silent fallback).
814
+ *
815
+ * Pure function: same (spec, deviceProvider, cache) always produces the same result.
816
+ * Boot-time call site: createRenderer wires the real device; record-stage call site
817
+ * uses ctx.runtime.device (same entrypoint, same signature).
818
+ *
819
+ * @param spec - immutable 4-axis pipeline specification
820
+ * @param deviceProvider - factory with createRenderPipeline method
821
+ * @param cache - the PipelineCache (shared across boot + record stage)
822
+ * @returns a RenderPipeline handle (opaque, typed as unknown for M1)
823
+ * @throws PipelineSpecError on validation failure or build failure
824
+ * @see plan-strategy D-12 · requirements AC-03 · charter F1
825
+ */
826
+ export function getOrBuildPipeline(
827
+ spec: PipelineSpec,
828
+ deviceProvider: PipelineDeviceProvider,
829
+ cache: PipelineCache,
830
+ modules?: {
831
+ vertex: unknown;
832
+ fragment: unknown;
833
+ vertexEntryPoint?: string;
834
+ fragmentEntryPoint?: string;
835
+ layout?: unknown;
836
+ },
837
+ ): unknown {
838
+ const key = cacheKeyOf(spec);
839
+
840
+ // Cache hit — return immediately.
841
+ const cached = cache.get(key);
842
+ if (cached !== undefined) return cached;
843
+
844
+ // Cache miss — validate, build, cache, return.
845
+ const validation = validateSpec(spec);
846
+ if (!validation.ok) {
847
+ throw new PipelineSpecError({
848
+ code: validation.code,
849
+ detail: validation.detail,
850
+ ...(validation.hint !== undefined ? { hint: validation.hint } : {}),
851
+ });
852
+ }
853
+
854
+ const descriptor = buildPipelineDescriptor(
855
+ spec,
856
+ modules ?? { vertex: undefined, fragment: undefined },
857
+ );
858
+ const result = deviceProvider.createRenderPipeline(descriptor);
859
+
860
+ if (!result.ok) {
861
+ throw new PipelineSpecError({
862
+ code: 'pipeline-build-failed',
863
+ detail: { cause: result.error },
864
+ hint: 'device.createRenderPipeline failed for spec; inspect gpuMessage on the error detail',
865
+ });
866
+ }
867
+
868
+ cache.set(key, result.value);
869
+ return result.value;
870
+ }
871
+
872
+ // ══════════════════════════════════════════════════════════════════════════════
873
+ // SPEC_CONST_TABLE — 12 boot-time pre-warm variants (M1-T5)
874
+ // ══════════════════════════════════════════════════════════════════════════════
875
+
876
+ const PROCEDURAL_ATTR_LAYOUT: VertexAttributeMap = {
877
+ position: new Float32Array(0),
878
+ normal: new Float32Array(0),
879
+ uv: new Float32Array(0),
880
+ tangent: new Float32Array(0),
881
+ };
882
+
883
+ const HDR_FORMAT: GPUTextureFormat = 'rgba16float';
884
+ const DEPTH_DS: GPUTextureFormat = 'depth24plus-stencil8';
885
+
886
+ /**
887
+ * Default LDR view format used when callers ask for the SPEC_CONST table
888
+ * without an explicit swap-chain format. Kept for the backward-compatible
889
+ * `SPEC_CONST_TABLE` export consumed by unit tests that exercise the
890
+ * spec/cache-keying layer in isolation. Runtime callers always pass the
891
+ * format selected by `selectSwapChainFormat` (Channel 2 BGRA / Channel 3
892
+ * RGBA / dawn-node RGBA — see bug-20260615 fix-up note in `createRenderer`).
893
+ */
894
+ const DEFAULT_LDR_FORMAT: GPUTextureFormat = 'bgra8unorm-srgb';
895
+
896
+ const TRI_GEOMETRY = {
897
+ topology: 'triangle-list' as PrimitiveTopology,
898
+ stripIndexFormat: undefined,
899
+ vertexLayout: PROCEDURAL_ATTR_LAYOUT,
900
+ };
901
+
902
+ // feat-city-glb multi-UV tiling: the built-in standard PBR shader now declares
903
+ // UV sets @location(6..12), so naga reflects uvSetCount=8 for it and the URP
904
+ // record path threads `shaderUvSetCount: 8` into every standard-pbr spec
905
+ // (createRenderer.ts buildPipelineContext / getMaterialShaderPipeline).
906
+ // The boot-time prewarm must match on both axes: the PSO vertex layout includes
907
+ // all declared UV slots, and the cacheKey carries `:uvsc8`. For single-UV
908
+ // meshes deriveVertexBufferLayout clamp-to-last aliases every missing set onto
909
+ // the last mesh set (48-byte stride unchanged), so existing geometry remains
910
+ // byte-stable.
911
+ // unlit stays on TRI_GEOMETRY (its shader declares only @location(0..3)).
912
+ const TRI_GEOMETRY_PBR = {
913
+ topology: 'triangle-list' as PrimitiveTopology,
914
+ stripIndexFormat: undefined,
915
+ vertexLayout: PROCEDURAL_ATTR_LAYOUT,
916
+ shaderUvSetCount: 8,
917
+ };
918
+
919
+ // M6 fix-up: URP-variant key string for the standard PBR shader. Mirrors the
920
+ // boot-time variantSet computed at createRenderer.ts step 1b when
921
+ // `isHdrpActive=false` and `storageBufferCapable=true` (the URP default
922
+ // surface). The URP record path requests this exact string at every
923
+ // `getMaterialShaderPipeline` call site, so seeding the table with these
924
+ // variants keeps the URP cache lookup hot from frame 1 instead of
925
+ // skip-drawing the first ~1 frames while the async compile resolves.
926
+ const URP_PBR_VARIANT_SET = 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true';
927
+
928
+ /**
929
+ * Build the boot-time pre-warm table: 15 standard PipelineSpec variants.
930
+ *
931
+ * feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12): the
932
+ * four `forgeax::default-sprite` entries (LDR S1 + LDR S4 + HDR S1 + HDR S4)
933
+ * are gone — sprite PSO lands lazily through the generic
934
+ * per-MaterialShader pipeline cache. Pre-feat count was 19; post-feat 15.
935
+ *
936
+ * Matrix:
937
+ * - 8 base material variants — {unlit, standard-pbr} x {LDR, HDR} x {S1, S4}
938
+ * - 4 URP-variant standard-pbr — standard-pbr (variantSet=URP_PBR_VARIANT_SET)
939
+ * x {LDR, HDR} x {S1, S4}; URP record path requests these specs by
940
+ * `getMaterialShaderPipeline` keying off `cacheKeyOf` so the boot-time
941
+ * prewarm seeds `materialShaderPipelineCache` and avoids a 1-frame
942
+ * async-compile skip-draw (M6 fix-up; see render-system-record.ts §URP)
943
+ * - 3 fullscreen-post — tonemap (LDR S1) + skybox (HDR S1, HDR S4)
944
+ *
945
+ * Total: 15. The URP variant is PBR-only because:
946
+ * - unlit URP record path passes `variantSet=undefined` (the no-variant
947
+ * boot-default entries already cover it; createRenderer.ts §unlitRsp)
948
+ * - sprite goes through `getMaterialShaderPipeline('forgeax::sprite', ...)`
949
+ * lazily at first transparent-LDR-split draw — no boot-time pre-warm.
950
+ * - HDRP variant (`variantSet=''` or compound `=true` form) is registered
951
+ * lazily when the clustered Standard profile activates, not at boot — adding clustered
952
+ * prewarm here would build PSOs against the URP layout (the boot-time
953
+ * `pbrModule` is the URP variant when `isHdrpActive=false`)
954
+ *
955
+ * `ldrViewFormat` parameterises the LDR color attachment format. Callers
956
+ * pass the runtime-resolved swap-chain view format (Channel 2 typically
957
+ * `bgra8unorm-srgb`; Channel 3 wgpu-wasm and dawn-node typically
958
+ * `rgba8unorm-srgb`). Hard-coding `bgra8unorm-srgb` at module load made
959
+ * the pre-warmed PSOs incompatible with the actual RenderPass color
960
+ * attachment on Channel 3 / dawn-node, producing whole-commandBuffer
961
+ * invalid errors on every frame (bug-20260615 fix-up — see
962
+ * `createRenderer` boot-time pre-warm site).
963
+ *
964
+ * Fullscreen passes (fxaa / bloom x 3 / SSAO x 2) are lazy-build — they
965
+ * use the same getOrBuildPipeline entrypoint but are not in this table.
966
+ *
967
+ * @see plan-strategy D-4 · research R-D4 · requirements AC-16
968
+ * @see bug-20260612-webgpu-canvas-format-prefer-bgra-shipped (same trap shape)
969
+ */
970
+ export function buildSpecConstTable(
971
+ ldrViewFormat: GPUTextureFormat,
972
+ ): readonly Readonly<PipelineSpec>[] {
973
+ const TRI_ATTACHMENTS_LDR_S1 = {
974
+ colorFormats: [ldrViewFormat],
975
+ depthFormat: DEPTH_DS,
976
+ sampleCount: 1 as const,
977
+ };
978
+
979
+ const TRI_ATTACHMENTS_LDR_S4 = {
980
+ colorFormats: [ldrViewFormat],
981
+ depthFormat: DEPTH_DS,
982
+ sampleCount: 4 as const,
983
+ };
984
+
985
+ // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12 / D-7):
986
+ // SPRITE_ATTACHMENTS_LDR_S1 / S4 (the dedicated non-srgb storage-format
987
+ // attachments the sprite spec entries consumed) were deleted alongside the
988
+ // four `forgeax::default-sprite` SPEC_CONST entries. The bgra8unorm storage
989
+ // format itself is still enforced at the LDR sprite sub-pass attachment
990
+ // level (the WebGPU pipeline `colorFormats` derive from the actual render
991
+ // pass attachment view, which is built off `pipelineState.format` =
992
+ // swap-chain storage format — see `render-system-record.ts` LDR split
993
+ // beginRenderPass call). The triggering source migrated from the
994
+ // spec-table id to `material.transparent` (derived by the extract stage
995
+ // from `passes[0].renderState.blend !== undefined`, the
996
+ // post-feat-20260626-collapse SSOT; w7 onwards).
997
+
998
+ const TRI_ATTACHMENTS_HDR_S1 = {
999
+ colorFormats: [HDR_FORMAT],
1000
+ depthFormat: DEPTH_DS,
1001
+ sampleCount: 1 as const,
1002
+ };
1003
+
1004
+ const TRI_ATTACHMENTS_HDR_S4 = {
1005
+ colorFormats: [HDR_FORMAT],
1006
+ depthFormat: DEPTH_DS,
1007
+ sampleCount: 4 as const,
1008
+ };
1009
+
1010
+ return [
1011
+ // unlit LDR S1
1012
+ {
1013
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1014
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1015
+ geometry: TRI_GEOMETRY,
1016
+ renderState: undefined,
1017
+ },
1018
+ // unlit LDR S4
1019
+ {
1020
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1021
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1022
+ geometry: TRI_GEOMETRY,
1023
+ renderState: undefined,
1024
+ },
1025
+ // unlit HDR S1
1026
+ {
1027
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1028
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1029
+ geometry: TRI_GEOMETRY,
1030
+ renderState: undefined,
1031
+ },
1032
+ // unlit HDR S4
1033
+ {
1034
+ shader: { id: 'forgeax::default-unlit', passKind: 'forward', variantSet: undefined },
1035
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1036
+ geometry: TRI_GEOMETRY,
1037
+ renderState: undefined,
1038
+ },
1039
+ // standard LDR S1
1040
+ {
1041
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1042
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1043
+ geometry: TRI_GEOMETRY_PBR,
1044
+ renderState: undefined,
1045
+ },
1046
+ // standard LDR S4
1047
+ {
1048
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1049
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1050
+ geometry: TRI_GEOMETRY_PBR,
1051
+ renderState: undefined,
1052
+ },
1053
+ // standard HDR S1
1054
+ {
1055
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1056
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1057
+ geometry: TRI_GEOMETRY_PBR,
1058
+ renderState: undefined,
1059
+ },
1060
+ // standard HDR S4
1061
+ {
1062
+ shader: { id: 'forgeax::default-standard-pbr', passKind: 'forward', variantSet: undefined },
1063
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1064
+ geometry: TRI_GEOMETRY_PBR,
1065
+ renderState: undefined,
1066
+ },
1067
+
1068
+ // ── M6 fix-up: URP-variant standard-pbr prewarm ─────────────────────────
1069
+ // URP record path (`getMaterialShaderPipeline`) requests
1070
+ // `variantSet=URP_PBR_VARIANT_SET` for standard-shading entities; pre-M6
1071
+ // the silent `selectStandardFallbackPipeline` shim served the no-variant
1072
+ // boot prewarm during the 1-frame async-compile warmup. With M6's
1073
+ // explicit-failure surface, those URP requests must hit the boot prewarm
1074
+ // by their own variantSet — these 4 entries close that gap.
1075
+
1076
+ // standard PBR URP LDR S1
1077
+ {
1078
+ shader: {
1079
+ id: 'forgeax::default-standard-pbr',
1080
+ passKind: 'forward',
1081
+ variantSet: URP_PBR_VARIANT_SET,
1082
+ },
1083
+ attachments: TRI_ATTACHMENTS_LDR_S1,
1084
+ geometry: TRI_GEOMETRY_PBR,
1085
+ renderState: undefined,
1086
+ },
1087
+ // standard PBR URP LDR S4
1088
+ {
1089
+ shader: {
1090
+ id: 'forgeax::default-standard-pbr',
1091
+ passKind: 'forward',
1092
+ variantSet: URP_PBR_VARIANT_SET,
1093
+ },
1094
+ attachments: TRI_ATTACHMENTS_LDR_S4,
1095
+ geometry: TRI_GEOMETRY_PBR,
1096
+ renderState: undefined,
1097
+ },
1098
+ // standard PBR URP HDR S1
1099
+ {
1100
+ shader: {
1101
+ id: 'forgeax::default-standard-pbr',
1102
+ passKind: 'forward',
1103
+ variantSet: URP_PBR_VARIANT_SET,
1104
+ },
1105
+ attachments: TRI_ATTACHMENTS_HDR_S1,
1106
+ geometry: TRI_GEOMETRY_PBR,
1107
+ renderState: undefined,
1108
+ },
1109
+ // standard PBR URP HDR S4
1110
+ {
1111
+ shader: {
1112
+ id: 'forgeax::default-standard-pbr',
1113
+ passKind: 'forward',
1114
+ variantSet: URP_PBR_VARIANT_SET,
1115
+ },
1116
+ attachments: TRI_ATTACHMENTS_HDR_S4,
1117
+ geometry: TRI_GEOMETRY_PBR,
1118
+ renderState: undefined,
1119
+ },
1120
+
1121
+ // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (AC-12 / D-7):
1122
+ // the four `forgeax::default-sprite` boot-time pre-warm entries (LDR S1
1123
+ // + LDR S4 + HDR S1 + HDR S4) are gone. Sprite PSO lands lazily through
1124
+ // the generic per-MaterialShader pipeline cache keyed on
1125
+ // `forgeax::sprite` + premultiplied-alpha renderState; SPEC_CONST_TABLE
1126
+ // shrinks from 19 to 15 entries (-4 boot-time PSOs).
1127
+
1128
+ // ── M2-T4: fullscreen-post boot-time pre-warm (tonemap + skybox) ──────────
1129
+ //
1130
+ // Tonemap (LDR S1): fullscreen triangle writes to swap-chain LDR view format
1131
+ // (parameterised — `ldrViewFormat`; see buildSpecConstTable jsdoc + bug-20260615).
1132
+ // Skybox (HDR S1 + S4): fullscreen triangle writes to rgba16float; MSAA variant
1133
+ // has sampleCount=4. Both use empty vertexLayout (fullscreen triangle, no
1134
+ // attributes) and cullMode='none' (forward cull for fullscreen-quad passthrough).
1135
+ //
1136
+ // Shadow-probe / fxaa / bloom 4-stage / SSAO 2-stage are lazy-build — not in
1137
+ // SPEC_CONST_TABLE (R-D4 decision: only entries that are always-present on
1138
+ // every boot).
1139
+
1140
+ // tonemap LDR S1 (writes to runtime-resolved swap-chain LDR view format)
1141
+ {
1142
+ shader: { id: 'forgeax::post::tonemap', passKind: 'post-process', variantSet: undefined },
1143
+ attachments: {
1144
+ colorFormats: [ldrViewFormat],
1145
+ depthFormat: undefined,
1146
+ sampleCount: 1 as const,
1147
+ },
1148
+ geometry: {
1149
+ topology: 'triangle-list' as PrimitiveTopology,
1150
+ stripIndexFormat: undefined,
1151
+ vertexLayout: {},
1152
+ },
1153
+ renderState: {
1154
+ cullMode: 'none',
1155
+ },
1156
+ },
1157
+
1158
+ // skybox HDR S1 (writes to rgba16float, no depth)
1159
+ {
1160
+ shader: { id: 'forgeax::skybox::cube', passKind: 'skybox', variantSet: undefined },
1161
+ attachments: {
1162
+ colorFormats: [HDR_FORMAT],
1163
+ depthFormat: undefined,
1164
+ sampleCount: 1 as const,
1165
+ },
1166
+ geometry: {
1167
+ topology: 'triangle-list' as PrimitiveTopology,
1168
+ stripIndexFormat: undefined,
1169
+ vertexLayout: {},
1170
+ },
1171
+ renderState: {
1172
+ cullMode: 'none',
1173
+ },
1174
+ },
1175
+
1176
+ // skybox HDR S4 (MSAA variant)
1177
+ {
1178
+ shader: { id: 'forgeax::skybox::cube', passKind: 'skybox', variantSet: undefined },
1179
+ attachments: {
1180
+ colorFormats: [HDR_FORMAT],
1181
+ depthFormat: undefined,
1182
+ sampleCount: 4 as const,
1183
+ },
1184
+ geometry: {
1185
+ topology: 'triangle-list' as PrimitiveTopology,
1186
+ stripIndexFormat: undefined,
1187
+ vertexLayout: {},
1188
+ },
1189
+ renderState: {
1190
+ cullMode: 'none',
1191
+ },
1192
+ },
1193
+ ];
1194
+ }
1195
+
1196
+ /**
1197
+ * Derive the material-only pre-warm table for a native linear-LDR target.
1198
+ *
1199
+ * The regular SPEC_CONST table targets the swap-chain view, while the
1200
+ * tonemap=none path records geometry directly into the graph-owned
1201
+ * `rgba16float` target. Keep that second attachment matrix derived from the
1202
+ * same material specs so the first frame does not depend on an asynchronous
1203
+ * lazy PSO build.
1204
+ */
1205
+ export function buildLinearLdrMaterialSpecTable(
1206
+ ldrViewFormat: GPUTextureFormat,
1207
+ ): readonly Readonly<PipelineSpec>[] {
1208
+ return buildSpecConstTable(ldrViewFormat)
1209
+ .filter(
1210
+ (spec) =>
1211
+ spec.shader.passKind === 'forward' && spec.attachments.colorFormats[0] === ldrViewFormat,
1212
+ )
1213
+ .map((spec) => ({
1214
+ ...spec,
1215
+ attachments: {
1216
+ ...spec.attachments,
1217
+ colorFormats: [HDR_FORMAT],
1218
+ },
1219
+ }));
1220
+ }
1221
+
1222
+ /**
1223
+ * Backward-compatible SPEC_CONST_TABLE — the table built with the default
1224
+ * LDR view format (`bgra8unorm-srgb`). Unit tests that exercise the
1225
+ * spec/cache-keying layer in isolation import this directly. Runtime
1226
+ * callers MUST call `buildSpecConstTable(swapChainFormats.view)` instead
1227
+ * so the pre-warmed PSO color format matches the actual RenderPass color
1228
+ * attachment on every backend (bug-20260615 fix-up).
1229
+ */
1230
+ export const SPEC_CONST_TABLE: readonly Readonly<PipelineSpec>[] =
1231
+ buildSpecConstTable(DEFAULT_LDR_FORMAT);