@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,885 @@
1
+ import { mat3 } from '@forgeax/engine-math';
2
+ import { type BindGroup, type Buffer, RhiError, type RhiQueue } from '@forgeax/engine-rhi';
3
+ import type { DispatchEntry } from '../render-system-extract';
4
+ import {
5
+ TRANSPARENT_SORT_MODE_LAYER_Y,
6
+ TRANSPARENT_SORT_MODE_LAYER_Z,
7
+ type TransparentSortConfig,
8
+ } from '../systems/transparent-sort-config';
9
+ import type { ValidatedRenderable } from './frame-snapshot';
10
+
11
+ /**
12
+ * Stride between per-renderable `entity_world` mat4 slots inside the
13
+ * shared `pipelineState.meshStorageBuffer`. The 256-byte alignment is
14
+ * required because the storage buffer is bound with
15
+ * `hasDynamicOffset: true` and WebGPU spec
16
+ * `minStorageBufferOffsetAlignment` defaults to 256.
17
+ */
18
+ export const MESH_PER_ENTITY_STRIDE = 256;
19
+
20
+ // The storage-buffer Mesh struct also carries the temporal previous transform
21
+ // and reactive metadata when STORAGE_BUFFER_AVAILABLE is true:
22
+ // mat4 (64 B) + mat3 (48 B) + previous mat4 (64 B) + vec4 (16 B) = 192 B.
23
+ // The BindGroup entry's `size` must cover the complete reflected struct, not
24
+ // only the first world transform and normal matrix.
25
+ export const MESH_SSBO_BYTES = 192;
26
+
27
+ // bug-20260610: WebGL2 fallback shader declares `array<Mesh, 128>` as a
28
+ // uniform buffer; binding must cover the full array size. The storage
29
+ // variant binds a single 112-B slot via dynamic offset, but the uniform
30
+ // variant requires the whole 14336-B range visible to the shader.
31
+ export const MESH_UBO_FULL_ARRAY_BYTES = 112 * 128;
32
+
33
+ // bug-20260723-webgl2-instancing-uniform-range: the WebGL2 fallback shader
34
+ // declares `array<InstanceData, 128>` in the instances bind group. Even when
35
+ // a draw carries fewer transforms, the buffer binding must expose the full
36
+ // array range or wgpu rejects the draw at submit time with a late
37
+ // min-binding-size mismatch.
38
+ export const INSTANCE_UBO_FULL_ARRAY_BYTES = 80 * 128;
39
+
40
+ export const MAX_UNIFORM_INSTANCES = 128;
41
+
42
+ /** The storage-backed InstanceData layout is current + previous mat4. */
43
+ export const INSTANCE_STORAGE_STRIDE_FLOATS = 32;
44
+
45
+ /**
46
+ * Project the ECS transform snapshot into the storage-backed InstanceData
47
+ * layout. The extract contract carries one current mat4 per instance; until
48
+ * the ECS snapshot owns a previous-instance column, current is the honest
49
+ * previous value as well. Uniform-backed variants keep the compact 16-float
50
+ * payload and do not use this projection.
51
+ */
52
+ export function packInstanceStorageBuffer(transforms: Float32Array): Float32Array {
53
+ const count = Math.floor(transforms.length / 16);
54
+ const out = new Float32Array(count * INSTANCE_STORAGE_STRIDE_FLOATS);
55
+ for (let i = 0; i < count; i++) {
56
+ const sourceBase = i * 16;
57
+ const targetBase = i * INSTANCE_STORAGE_STRIDE_FLOATS;
58
+ for (let k = 0; k < 16; k++) {
59
+ const value = transforms[sourceBase + k] ?? 0;
60
+ out[targetBase + k] = value;
61
+ out[targetBase + 16 + k] = value;
62
+ }
63
+ }
64
+ return out;
65
+ }
66
+
67
+ /**
68
+ * M3 / w12: extracts the underlying GPU resource object from a bind
69
+ * group entry descriptor. Returns the raw object reference (Buffer,
70
+ * TextureView, or Sampler) usable as a WeakMap chain key.
71
+ */
72
+ export function extractEntryResourceHandle(entry: {
73
+ resource: { kind: string; value: unknown };
74
+ }): object {
75
+ const v = entry.resource.value;
76
+ if (typeof v === 'object' && v !== null && 'buffer' in (v as Record<string, unknown>)) {
77
+ return (v as { buffer: object }).buffer;
78
+ }
79
+ return v as object;
80
+ }
81
+
82
+ /**
83
+ * feat-20260622-handle-to-id-allocator-elimination M2 / w7: walks a nested
84
+ * WeakMap chain to find or create a BindGroup leaf. Each handle in the
85
+ * `handles` array is a chain node; the final leaf is a Map<string, BindGroup>
86
+ * keyed by `variant` (D-2). Chain keys are always object references, never
87
+ * numeric ids — GC reclaims entries for dead handles automatically.
88
+ *
89
+ * On cache hit returns the cached BindGroup. On miss calls `factory`,
90
+ * bumps `bindGroupCounts.createBindGroup`, stores the result at the leaf,
91
+ * and returns it. Hit/miss accounting is observable via `bindGroupCounts`
92
+ * (D-8: the skin probe reads `counts.createBindGroup` delta).
93
+ */
94
+ export function getOrCreateFromChain(
95
+ root: WeakMap<object, unknown>,
96
+ handles: readonly object[],
97
+ variant: string,
98
+ factory: () => BindGroup,
99
+ counts: { createBindGroup: number; keys: string[] },
100
+ ): BindGroup {
101
+ let node = root;
102
+ for (let i = 0; i < handles.length - 1; i++) {
103
+ // biome-ignore lint/style/noNonNullAssertion: handles length guards the index
104
+ const h = handles[i]!;
105
+ let next = node.get(h) as WeakMap<object, unknown> | undefined;
106
+ if (next === undefined) {
107
+ next = new WeakMap();
108
+ node.set(h, next);
109
+ }
110
+ node = next;
111
+ }
112
+ // biome-ignore lint/style/noNonNullAssertion: known non-empty at call sites
113
+ const last = handles[handles.length - 1]!;
114
+ let leaf = node.get(last) as Map<string, BindGroup> | undefined;
115
+ if (leaf === undefined) {
116
+ leaf = new Map();
117
+ node.set(last, leaf);
118
+ }
119
+ const hit = leaf.get(variant);
120
+ if (hit !== undefined) return hit;
121
+ const bg = factory();
122
+ counts.createBindGroup += 1;
123
+ counts.keys.push(variant);
124
+ leaf.set(variant, bg);
125
+ return bg;
126
+ }
127
+
128
+ /**
129
+ * feat-20260622-handle-to-id-allocator-elimination M2 / w8: per-entity bind
130
+ * group lookup-or-create helper (D-2). Two-step lookup: outer Map.get(outerKey)
131
+ * finds or lazily creates an inner WeakMap chain, then delegates to
132
+ * `getOrCreateFromChain` for the chain walk. outerKey is `string | number`
133
+ * to cover both per-entity (number entityKey) and material-shared
134
+ * (string shaderId) caches (D-1 / OQ-1).
135
+ */
136
+ export function getOrCreatePerEntity(
137
+ outerMap: Map<string | number, WeakMap<object, unknown>>,
138
+ outerKey: string | number,
139
+ handles: readonly object[],
140
+ variant: string,
141
+ factory: () => BindGroup,
142
+ counts: { createBindGroup: number; keys: string[] },
143
+ ): BindGroup {
144
+ let inner = outerMap.get(outerKey) as WeakMap<object, unknown> | undefined;
145
+ if (inner === undefined) {
146
+ inner = new WeakMap();
147
+ outerMap.set(outerKey, inner);
148
+ }
149
+ return getOrCreateFromChain(inner, handles, variant, factory, counts);
150
+ }
151
+
152
+ /**
153
+ * feat-20260622-handle-to-id-allocator-elimination M2 / w8: evicts per-entity
154
+ * cache entries whose entityKey is not in the validated set. Works on
155
+ * Map<entityKey, WeakMap<handle, BindGroup>> by iterating the outer Map keys
156
+ * and deleting entries for which validatedEntityKeys.has(ek) is false.
157
+ * No string parsing, no Number / Number.isNaN — the entityKey is already a
158
+ * number (D-1 / RD4).
159
+ *
160
+ * @internal — exported for unit test access (AC-08)
161
+ */
162
+ export function cleanPerEntityCache(
163
+ cache: Map<number, WeakMap<object, unknown>>,
164
+ validatedEntityKeys: Set<number>,
165
+ ): void {
166
+ for (const ek of cache.keys()) {
167
+ if (!validatedEntityKeys.has(ek)) {
168
+ cache.delete(ek);
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * feat-20260608-mesh-ssbo-dynamic-grow-l1-lift-1024-entity-cap M3 / T-M3-04:
175
+ * record-stage entry-point hook to the closure-scoped mesh-SSBO grow
176
+ * controller (createRenderer.ts). Called once per frame, after
177
+ * `validatedOrdered` has been finalised and BEFORE the first per-entity
178
+ * `queue.writeBuffer`. Returns Result-like (never throws — D-5):
179
+ *
180
+ * - `{ ok: true }` — slotCount already covers `neededSlots` (idempotent
181
+ * short-circuit), or the controller successfully grew
182
+ * in this call. Caller proceeds with the frame.
183
+ * - `{ ok: false, code, degradedToSlotCount }` — controller hit ceiling /
184
+ * capacity and ALREADY fired the structured error
185
+ * via errorRegistry. Caller truncates the draw
186
+ * list to the largest complete entity prefix that
187
+ * fits within `degradedToSlotCount` slots (graceful
188
+ * degradation per plan-strategy D-2): renders the
189
+ * subset that fits, discards overflow, no black
190
+ * frame.
191
+ *
192
+ * This helper does NOT re-fire on `ok:false` — the controller is the single
193
+ * fire site (createRenderer.ts grow factory), so callers see exactly one
194
+ * structured error per ceiling event (charter P3 explicit failure: no
195
+ * double-fire).
196
+ *
197
+ * Dev-mode visibility: when grow actually grew (slotCount transition) AND
198
+ * `import.meta.env?.DEV` is truthy, a single `console.info('[mesh-ssbo] ...')`
199
+ * line reports the before / after / requested counts. The optional-chain
200
+ * keeps non-vite envs (dawn-node smoke, plain tsup tests) silent —
201
+ * `import.meta.env` is undefined there, the chain short-circuits to
202
+ * undefined, the if-guard is falsy (AC-11 + plan-strategy §2.D-3).
203
+ *
204
+ * Bind-group cache invalidation is automatic: on grow, the controller
205
+ * mutates `meshSsboState.mesh.buffer` / `.material.buffer` in place
206
+ * (wrapper-object identity preserved, inner buffer replaced — research §F8).
207
+ * Downstream the fresh inner buffer object is a new WeakMap chain key, so
208
+ * `getOrCreateFromChain` misses and rebuilds the BindGroup on the next frame
209
+ * (AC-07; T-M3-03 (a) test).
210
+ *
211
+ * @internal — exported for unit-test access (`mesh-ssbo-grow.test.ts`
212
+ * T-M3-01 / T-M3-02 / T-M3-03 cover idempotency, ceiling, dev info).
213
+ */
214
+ export function ensureMeshSsboCapacity(
215
+ internals: {
216
+ readonly growMeshSsbo?:
217
+ | ((neededSlots: number) =>
218
+ | { readonly ok: true }
219
+ | {
220
+ readonly ok: false;
221
+ readonly code: 'mesh-ssbo-ceiling-reached' | 'mesh-ssbo-capacity-exceeded';
222
+ readonly degradedToSlotCount: number;
223
+ })
224
+ | undefined;
225
+ readonly meshSsboState?: { readonly slotCount: number } | undefined;
226
+ },
227
+ neededSlots: number,
228
+ ):
229
+ | { readonly ok: true }
230
+ | {
231
+ readonly ok: false;
232
+ readonly code: 'mesh-ssbo-ceiling-reached' | 'mesh-ssbo-capacity-exceeded';
233
+ readonly degradedToSlotCount: number;
234
+ } {
235
+ // Empty scene / no controller wired (legacy / test fixture path).
236
+ if (neededSlots <= 0) return { ok: true };
237
+ const grow = internals.growMeshSsbo;
238
+ if (grow === undefined) return { ok: true };
239
+ // Idempotent guard — current slotCount already covers neededSlots.
240
+ // The controller's own internal guard catches this too, but bailing here
241
+ // skips the spy / tracing overhead and matches the AC-09 contract that
242
+ // grow runs at most once per frame transition.
243
+ const before = internals.meshSsboState?.slotCount ?? 0;
244
+ if (before > 0 && before >= neededSlots) return { ok: true };
245
+ const result = grow(neededSlots);
246
+ // Note: ok:false has already fired the structured error inside the
247
+ // controller (createRenderer.ts grow factory). Do NOT double-fire here.
248
+ if (!result.ok) return result;
249
+ // Dev-mode visibility — only on a real slotCount transition (skip
250
+ // no-op idempotent paths above; ceiling path returned early on ok:false).
251
+ const after = internals.meshSsboState?.slotCount ?? before;
252
+ if (after !== before) {
253
+ // Module-local binding read (NOT `recordModule.devModeProbe`) so vitest
254
+ // ESM-readonly export forced us to expose the probe as a settable holder
255
+ // (`setMeshSsboDevModeProbeForTests`) instead of a `vi.spyOn` target.
256
+ if (meshSsboDevModeProbe()) {
257
+ // biome-ignore lint/suspicious/noConsole: AC-11 mandates a `[mesh-ssbo]` info line in dev mode (vite build dead-strips this branch via the `import.meta.env.DEV` constant fold; tsup / esbuild prod sets NODE_ENV=production).
258
+ console.info(
259
+ '[mesh-ssbo] grew slotCount: %d -> %d (requested=%d)',
260
+ before,
261
+ after,
262
+ neededSlots,
263
+ );
264
+ }
265
+ }
266
+ return result;
267
+ }
268
+
269
+ /**
270
+ * Test seam: a closure-local function pointer ensureMeshSsboCapacity reads
271
+ * for the dev-mode gate. Defaults to `isMeshSsboDevMode`; tests swap it out
272
+ * via `setMeshSsboDevModeProbeForTests` because vitest 4.x export bindings
273
+ * are non-writable (ESM spec) and `import.meta.env.DEV` is build-time-frozen
274
+ * by the vite transform — neither `vi.spyOn(recordModule, 'isMeshSsboDevMode')`
275
+ * nor `vi.stubEnv('DEV', false)` toggles it at runtime.
276
+ */
277
+ let meshSsboDevModeProbe: () => boolean = isMeshSsboDevMode;
278
+
279
+ /**
280
+ * @internal — test-only injection seam for `ensureMeshSsboCapacity`'s
281
+ * dev-mode gate. Pass `undefined` to restore the production probe
282
+ * (`isMeshSsboDevMode`). Production code paths NEVER call this.
283
+ */
284
+ export function setMeshSsboDevModeProbeForTests(probe: (() => boolean) | undefined): void {
285
+ meshSsboDevModeProbe = probe ?? isMeshSsboDevMode;
286
+ }
287
+
288
+ /**
289
+ * Dev-mode probe for `ensureMeshSsboCapacity`'s console.info gate
290
+ * (plan-strategy §2.D-3 + AC-11). True when the build is in dev mode:
291
+ * - `import.meta.env?.DEV` is truthy (vite dev / vitest), OR
292
+ * - `process.env.NODE_ENV !== 'production'` (esbuild / tsup / dawn-node).
293
+ * Optional-chain keeps it safe in non-vite ESM envs that never inject
294
+ * `import.meta.env` (the chain short-circuits to undefined → falsy).
295
+ *
296
+ * Vite's `import.meta.env.DEV` is constant-folded at build time, so the
297
+ * production bundle dead-code-strips the entire branch even though the
298
+ * test fall-through reads `process.env.NODE_ENV`.
299
+ *
300
+ * @internal — exported as a function (not a const) so unit tests can
301
+ * `vi.spyOn(...).mockReturnValue(false)` to exercise the dev=false path
302
+ * (vitest 4.x cannot toggle `import.meta.env.DEV` at runtime — it is
303
+ * compile-time-frozen by the vite transform).
304
+ */
305
+ export function isMeshSsboDevMode(): boolean {
306
+ const importMetaDev = (import.meta as { env?: { DEV?: unknown } }).env?.DEV;
307
+ if (importMetaDev) return true;
308
+ // Fallback for tsup / esbuild / dawn-node where import.meta.env is absent:
309
+ // NODE_ENV !== 'production' counts as dev. NODE_ENV unset (undefined)
310
+ // also counts as dev so test envs without explicit NODE_ENV log too —
311
+ // production builds always set NODE_ENV='production'. We read process via
312
+ // globalThis to keep this file @types/node-free (rest of the package is
313
+ // browser-typed; engine-runtime ships ESM into both browser + dawn-node).
314
+ const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;
315
+ if (proc !== undefined && proc.env?.NODE_ENV === 'production') return false;
316
+ if (proc === undefined) return false;
317
+ return true;
318
+ }
319
+
320
+ /**
321
+ * Module-scoped reusable scratch for batched mesh-SSBO uploads (O2).
322
+ * Grows monotonically; never shrinks. One allocation per render session
323
+ * instead of one per entity per frame.
324
+ *
325
+ * @internal
326
+ */
327
+ let _meshSsboScratch = new Uint8Array(0);
328
+
329
+ /**
330
+ * feat-20260704 M3/w21: per-renderable `entity_world` upload (batched). All N
331
+ * mat4+normalMatrix slots are assembled into a single contiguous scratch
332
+ * buffer, then flushed as one `writeBuffer` call instead of N individual
333
+ * calls. Extracted verbatim from `recordFrame` (frame.ts) — the module-scoped
334
+ * `_meshSsboScratch` let and its only reassignment site now co-locate in this
335
+ * file so the two mesh-SSBO module lets live together (AC-06).
336
+ *
337
+ * feat-20260518 M3 / w14 (AC-08): each 256-byte slot carries a 16-float mat4
338
+ * at [0..64B) and a 48-byte mat3 normalMatrix at [64..112B) (3 vec4 columns;
339
+ * padding at indices 19/23/27 stays 0). The mat3 =
340
+ * transpose(invert(mat3(worldFromLocal))) for correct normal transform under
341
+ * non-uniform scale.
342
+ *
343
+ * feat-20260622-chunk-gpu-instancing-sprite-tilemap M1 / w4-record-swap (D-1):
344
+ * fold-bucket heads write identity into their slot; the fold path assembles
345
+ * per-instance world matrices into the @group(3) instances buffer instead
346
+ * (sprite/unlit shaders ignore normals; AC-01/AC-02).
347
+ *
348
+ * @internal
349
+ */
350
+ export function uploadMeshSsboBatch(
351
+ queue: RhiQueue,
352
+ meshStorageBuffer: { readonly buffer: Buffer },
353
+ validatedOrdered: readonly ValidatedRenderable[],
354
+ foldDispatchPlan: FoldDispatchPlan | null,
355
+ ): void {
356
+ const slotCount = validatedOrdered.length;
357
+ const neededBytes = slotCount * MESH_PER_ENTITY_STRIDE;
358
+ // Grow the module-scoped scratch monotonically; zero the used range.
359
+ if (_meshSsboScratch.length < neededBytes) {
360
+ _meshSsboScratch = new Uint8Array(neededBytes);
361
+ } else {
362
+ _meshSsboScratch.fill(0, 0, neededBytes);
363
+ }
364
+ const normalMatrixScratch = mat3.create();
365
+ for (let i = 0; i < slotCount; i++) {
366
+ const entry = validatedOrdered[i];
367
+ if (entry === undefined) continue;
368
+ // Float32Array view into this entity's 256-byte slot (28 floats used,
369
+ // rest remains 0 from the fill above). Byte offset i*256 is always
370
+ // 4-byte aligned since MESH_PER_ENTITY_STRIDE=256 is divisible by 4.
371
+ const slot = new Float32Array(_meshSsboScratch.buffer, i * MESH_PER_ENTITY_STRIDE, 28);
372
+ const isFoldHead = foldDispatchPlan?.headBuckets.has(i) === true;
373
+ if (isFoldHead) {
374
+ // identity mat4
375
+ slot[0] = 1;
376
+ slot[5] = 1;
377
+ slot[10] = 1;
378
+ slot[15] = 1;
379
+ // identity mat3 normal (cols at slot offsets 16/20/24)
380
+ slot[16] = 1;
381
+ slot[20] = 1;
382
+ slot[24] = 1;
383
+ } else {
384
+ const worldFromLocal = entry.source.transform.world;
385
+ for (let k = 0; k < 16; k++) slot[k] = worldFromLocal[k] ?? 0;
386
+ const normal = mat3.normalMatrix(normalMatrixScratch, worldFromLocal);
387
+ slot[16] = normal[0] ?? 0;
388
+ slot[17] = normal[1] ?? 0;
389
+ slot[18] = normal[2] ?? 0;
390
+ slot[20] = normal[3] ?? 0;
391
+ slot[21] = normal[4] ?? 0;
392
+ slot[22] = normal[5] ?? 0;
393
+ slot[24] = normal[6] ?? 0;
394
+ slot[25] = normal[7] ?? 0;
395
+ slot[26] = normal[8] ?? 0;
396
+ }
397
+ }
398
+ if (neededBytes > 0) {
399
+ const meshUpload = queue.writeBuffer(
400
+ meshStorageBuffer.buffer,
401
+ 0,
402
+ _meshSsboScratch,
403
+ 0,
404
+ neededBytes,
405
+ );
406
+ if (!meshUpload.ok) throw meshUpload.error;
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Per-bucket descriptor produced by {@link foldDispatchBuckets}.
412
+ *
413
+ * One bucket = one fold-eligible run of consecutive DispatchEntry whose
414
+ * `(layer, sortKey, materialHandle)` triple is equal. Singleton buckets
415
+ * (bucketSize=1) appear when the mode bypasses fold (D-5 mode 2/3) or
416
+ * when consecutive entries differ in one of the three keys.
417
+ *
418
+ * Fields:
419
+ * - `entries` — original DispatchEntry slice for this bucket (preserves
420
+ * the input ordering); the consumer uses these to look up per-entity
421
+ * material BG handles, mesh handles (which are bucket-uniform by
422
+ * construction since materialHandle key is included), etc.
423
+ * - `bucketSize` — `entries.length`. Surfaced as a top-level field so
424
+ * the consumer can pass it directly as `instanceCount` to
425
+ * `drawIndexed`.
426
+ * - `transforms` — assembled Float32Array of bucketSize world mat4s,
427
+ * stride=16 floats per instance, column-major. Suitable for direct
428
+ * `device.queue.writeBuffer` into an instance buffer used at @group(3).
429
+ * - `materialHandle` / `layer` / `sortKey` — the three-tuple key for this
430
+ * bucket. `sortKey` is mode-dependent: posZ (world[14]) for mode 0
431
+ * (LAYER_Z), posY (world[13]) for mode 1 (LAYER_Y). Consumed by the
432
+ * dispatch loop for bind-group selection / sort-stability invariants.
433
+ */
434
+ export interface FoldBucket {
435
+ readonly entries: readonly DispatchEntry[];
436
+ readonly bucketSize: number;
437
+ readonly transforms: Float32Array;
438
+ readonly materialHandle: number;
439
+ readonly layer: number;
440
+ readonly sortKey: number;
441
+ }
442
+
443
+ /**
444
+ * Minimal renderable shape consumed by the helper. The real
445
+ * `RenderableSnapshot` carries many more fields; the helper only reads
446
+ * `transform.world` (a Float32Array of 16 column-major floats) and
447
+ * `material.transparent` (the LDR-split-sub-pass fold gate, see PR #502
448
+ * fix + feat-20260625 R2 fix-up: geometry-pass entities — non-transparent
449
+ * materials — MUST stay singleton because the sprite-pass dispatch path
450
+ * that consumes `headBuckets` does not run for them; folding them would
451
+ * overwrite their mesh-SSBO slot with identity and collapse 3D geometry
452
+ * to origin).
453
+ *
454
+ * Production callers pass `RenderableSnapshot[]` straight through —
455
+ * `RenderableSnapshot.material.transparent` is `boolean | undefined`
456
+ * (derived by the extract stage from `passes[0].renderState.blend !==
457
+ * undefined`, the post-feat-20260626-collapse SSOT; see
458
+ * `MaterialSnapshot.transparent`), structurally compatible with this
459
+ * minimal shape. The gate read inside the helper uses `=== true` /
460
+ * `!== true` so both `false` and `undefined` enter the singleton branch.
461
+ *
462
+ * feat-20260625-refactor-sprite-as-transparent-mesh R2 fix-up: gate
463
+ * migrated from `shadingModel === 'sprite'` (the union member was
464
+ * removed in M3 / w15) to `transparent === true` (the new SSOT for
465
+ * "routes through the LDR split sub-pass" — same predicate the
466
+ * `splitLdrSprite` filter at render-system-record.ts:4826/5612 uses).
467
+ */
468
+ export interface FoldRenderableLike {
469
+ readonly transform: { readonly world: Float32Array };
470
+ readonly material: { readonly transparent?: boolean | undefined };
471
+ }
472
+
473
+ /**
474
+ * Linear-scan fold operator (plan-strategy D-1).
475
+ *
476
+ * Walks `orderedEntries` (must be transparent-sort-ordered when mode=0;
477
+ * the helper trusts the input ordering and only checks adjacent equality
478
+ * — non-consecutive entries with equal keys are NOT merged, preserving
479
+ * stable-sort semantics).
480
+ *
481
+ * @param orderedEntries — DispatchEntry[] in transparent-sort order. Empty
482
+ * array yields zero buckets (defensive empty-bucket suppression).
483
+ * @param mode — current `TransparentSortConfig.mode`. Modes 0 (LAYER_Z)
484
+ * and 1 (LAYER_Y) enable fold using the appropriate sort-axis coordinate
485
+ * (posZ / posY respectively). Modes 2 and 3 produce singleton buckets
486
+ * per entry (D-5 bypass).
487
+ * @param renderables — parallel snapshot array indexed by
488
+ * `DispatchEntry.renderableIndex`. The helper reads `transform.world`
489
+ * to (a) extract the sort-axis coordinate for the bucket key (posZ
490
+ * world[14] for mode 0, posY world[13] for mode 1), and (b) copy 16
491
+ * floats per entry into the assembled transforms buffer. Out-of-range /
492
+ * missing renderables defensively contribute a zero mat4 slot.
493
+ * @returns Array of FoldBucket descriptors in input order.
494
+ */
495
+ export function foldDispatchBuckets(
496
+ orderedEntries: readonly DispatchEntry[],
497
+ mode: TransparentSortConfig['mode'],
498
+ renderables: readonly FoldRenderableLike[],
499
+ ): readonly FoldBucket[] {
500
+ if (orderedEntries.length === 0) return [];
501
+
502
+ // Bypass branch (D-5): modes 2 (LAYER_YZ) and 3 (DISTANCE) cannot fold
503
+ // — their sort keys are composite foot-Y formulas or per-entity camera
504
+ // distances, not reducible to a single world-mat4 coordinate read.
505
+ // Each entry produces its own singleton bucket; the dispatch consumer
506
+ // treats bucketSize=1 identically to per-entity drawIndexed (charter P3
507
+ // silent fallback — no error fired).
508
+ //
509
+ // Mode 1 (LAYER_Y) falls through to the fold branch below and uses posY
510
+ // (world[13]) as the sort-axis bucket key.
511
+ if (mode !== TRANSPARENT_SORT_MODE_LAYER_Z && mode !== TRANSPARENT_SORT_MODE_LAYER_Y) {
512
+ const out: FoldBucket[] = [];
513
+ for (let i = 0; i < orderedEntries.length; i++) {
514
+ const e = orderedEntries[i];
515
+ if (e === undefined) continue;
516
+ out.push(makeSingletonBucket(e, renderables, mode));
517
+ }
518
+ return out;
519
+ }
520
+
521
+ // Fold branch (mode 0 = LAYER_Z, mode 1 = LAYER_Y): linear scan, collect
522
+ // runs with equal (layer, sortKey, materialHandle). sortKey is posZ for
523
+ // mode 0, posY for mode 1 — see readSortKey().
524
+ //
525
+ // Transparent-pass-only gate (PR #502 fix + feat-20260625 R2 fix-up):
526
+ // the only dispatch site that consumes `headBuckets` to emit one
527
+ // instanced drawIndexed per bucket is the transparent-pass loop in
528
+ // `render-system-record.ts` (~line 5500; routed via `splitLdrSprite`
529
+ // filter on `material.transparent === true`). The geometry-pass loop
530
+ // (~line 4660) iterates `validatedOrdered` and emits per-entity
531
+ // drawIndexed unchanged; it does NOT branch on `headBuckets`. So when
532
+ // a non-transparent entry (geometry-pass: unlit / standard-PBR / skin)
533
+ // is folded into a multi-entry bucket, the mesh-SSBO upload loop
534
+ // (~line 2710) still overwrites its mesh slot with identity (because
535
+ // `headBuckets.has(i)` is true), but the geometry-pass then reads
536
+ // identity and renders the 3D geometry at the origin — collapsing the
537
+ // frame to black (hello-room CI regression).
538
+ //
539
+ // Concept-count fix: encode "fold is transparent-sub-pass-only" at the
540
+ // head selection point — the gate is the single bucket-key invariant
541
+ // that makes both dispatch sites correct without coupling identity-
542
+ // overwrite logic to a separate check (avoiding the D-9 shared-exit
543
+ // violation that selecting fix-location B would produce).
544
+ //
545
+ // Non-transparent entries (`transparent !== true`) always produce
546
+ // singleton buckets (bucketSize=1), which `buildFoldDispatchPlan`
547
+ // filters out (`if (bucket.bucketSize <= 1) continue`), so they never
548
+ // enter `headBuckets` / `skipIndices` — the mesh-SSBO upload,
549
+ // transparent-pass, and geometry-pass loops all see them as byte-
550
+ // identical to the pre-fold per-entity path.
551
+ //
552
+ // feat-20260625 R2 fix-up: pre-feat the gate was `shadingModel ===
553
+ // 'sprite'`; M3 / w15 narrowed the shadingModel union to
554
+ // `'unlit' | undefined` (the `'sprite'` discriminator was the design
555
+ // ablation target), so the gate now reads `material.transparent` —
556
+ // the new SSOT for "routes through the LDR split sub-pass" mirrored
557
+ // on `computeSplitLdrSprite` + the `splitLdrSprite` skip filter.
558
+ const buckets: FoldBucket[] = [];
559
+ let runStart = 0;
560
+ while (runStart < orderedEntries.length) {
561
+ const head = orderedEntries[runStart];
562
+ if (head === undefined) {
563
+ runStart += 1;
564
+ continue;
565
+ }
566
+ // Transparent-pass-only gate (feat-20260625 R2 fix-up): non-transparent
567
+ // heads emit a singleton bucket and advance the cursor by 1 — no run
568
+ // extension. `RenderableSnapshot.material.transparent` is the SSOT
569
+ // carrier (extract stage derives it from the first pass's
570
+ // `renderState.blend !== undefined`, post-feat-20260626-collapse;
571
+ // see `MaterialSnapshot.transparent`).
572
+ const headTransparent = renderables[head.renderableIndex]?.material.transparent;
573
+ if (headTransparent !== true) {
574
+ buckets.push(makeSingletonBucket(head, renderables, mode));
575
+ runStart += 1;
576
+ continue;
577
+ }
578
+ const headSortKey = readSortKey(mode, head.renderableIndex, renderables);
579
+ let runEnd = runStart + 1;
580
+ while (runEnd < orderedEntries.length) {
581
+ const cand = orderedEntries[runEnd];
582
+ if (cand === undefined) break;
583
+ if (cand.layer !== head.layer) break;
584
+ if (cand.materialHandle !== head.materialHandle) break;
585
+ // Defensive: cand transparent must also be true to join the run.
586
+ // Same materialHandle implies same transparent flag in production
587
+ // (material asset identity), but the check costs O(1) per cand and
588
+ // makes the bucket invariant locally readable.
589
+ const candTransparent = renderables[cand.renderableIndex]?.material.transparent;
590
+ if (candTransparent !== true) break;
591
+ const candSortKey = readSortKey(mode, cand.renderableIndex, renderables);
592
+ if (candSortKey !== headSortKey) break;
593
+ runEnd += 1;
594
+ }
595
+
596
+ const run = orderedEntries.slice(runStart, runEnd);
597
+ const transforms = assembleTransforms(run, renderables);
598
+ buckets.push({
599
+ entries: run,
600
+ bucketSize: run.length,
601
+ transforms,
602
+ materialHandle: head.materialHandle,
603
+ layer: head.layer,
604
+ sortKey: headSortKey,
605
+ });
606
+ runStart = runEnd;
607
+ }
608
+ return buckets;
609
+ }
610
+
611
+ function makeSingletonBucket(
612
+ entry: DispatchEntry,
613
+ renderables: readonly FoldRenderableLike[],
614
+ mode: TransparentSortConfig['mode'],
615
+ ): FoldBucket {
616
+ const transforms = new Float32Array(16);
617
+ const w = renderables[entry.renderableIndex]?.transform.world;
618
+ if (w !== undefined) transforms.set(w);
619
+ const sortKey = readSortKey(mode, entry.renderableIndex, renderables);
620
+ return {
621
+ entries: [entry],
622
+ bucketSize: 1,
623
+ transforms,
624
+ materialHandle: entry.materialHandle,
625
+ layer: entry.layer,
626
+ sortKey,
627
+ };
628
+ }
629
+
630
+ function assembleTransforms(
631
+ run: readonly DispatchEntry[],
632
+ renderables: readonly FoldRenderableLike[],
633
+ ): Float32Array {
634
+ const out = new Float32Array(run.length * 16);
635
+ for (let i = 0; i < run.length; i++) {
636
+ const e = run[i];
637
+ if (e === undefined) continue;
638
+ const w = renderables[e.renderableIndex]?.transform.world;
639
+ if (w !== undefined) out.set(w, i * 16);
640
+ }
641
+ return out;
642
+ }
643
+
644
+ function readSortKey(
645
+ mode: TransparentSortConfig['mode'],
646
+ renderableIndex: number,
647
+ renderables: readonly FoldRenderableLike[],
648
+ ): number {
649
+ const w = renderables[renderableIndex]?.transform.world;
650
+ if (w === undefined) return 0;
651
+ // mode 0 (LAYER_Z): sort-axis is Z, column 3 row 2 = world[14].
652
+ // mode 1 (LAYER_Y): sort-axis is Y, column 3 row 1 = world[13].
653
+ return ((mode === TRANSPARENT_SORT_MODE_LAYER_Z ? w[14] : w[13]) ?? 0) as number;
654
+ }
655
+
656
+ /**
657
+ * Per-validatedOrdered-index fold metadata consumed by the record-stage
658
+ * dispatch loops. Built from {@link foldDispatchBuckets} output by
659
+ * {@link buildFoldDispatchPlan}; see plan-strategy §3.2 sequence diagram.
660
+ *
661
+ * Field semantics (consumer contract, w4-record-swap):
662
+ * - `headBuckets[i]` is non-null when validatedOrdered index `i` is the
663
+ * **bucket head** of a non-singleton (bucketSize > 1) fold bucket. The
664
+ * dispatch loop overrides @group(3) instances BG to a transient buffer
665
+ * holding `bucket.transforms` and emits `drawIndexed(idxCount,
666
+ * bucket.bucketSize)` instead of per-entity drawIndexed.
667
+ * - `skipIndices.has(i)` is true when index `i` is a non-head member of
668
+ * a non-singleton fold bucket; the dispatch loop emits `continue`.
669
+ * - Singleton buckets (bucketSize === 1) leave both arrays empty for
670
+ * that index — dispatch falls through to the existing per-entity path
671
+ * byte-identically (mode-bypass / non-foldable head / fold-disabled).
672
+ *
673
+ * Note: the maps are keyed on `validatedOrderedIndex`, NOT
674
+ * `renderableIndex`. The dispatch loops iterate `validatedOrdered` by
675
+ * positional index `i`, and that index drives mesh SSBO slot offset
676
+ * (`i * MESH_PER_ENTITY_STRIDE`), material UBO slot, and per-entity bind
677
+ * group cache keys, all of which the swap must coordinate with.
678
+ */
679
+ export interface FoldDispatchPlan {
680
+ readonly headBuckets: ReadonlyMap<number, FoldBucket>;
681
+ readonly skipIndices: ReadonlySet<number>;
682
+ readonly foldedBucketCount: number;
683
+ }
684
+
685
+ /**
686
+ * Build the per-validatedOrdered-index fold metadata from a
687
+ * {@link foldDispatchBuckets} output.
688
+ *
689
+ * @param buckets — output of {@link foldDispatchBuckets}; ordered by
690
+ * transparent-sort scan order.
691
+ * @param renderableIndexToValidatedIndex — map from `DispatchEntry.renderableIndex`
692
+ * to the validated-ordered index `i` (the loop counter the dispatch
693
+ * loops use). Caller builds this once per frame from `validatedOrdered`.
694
+ * @returns FoldDispatchPlan keyed by validated-ordered index.
695
+ *
696
+ * Empty / all-singleton input yields empty maps + `foldedBucketCount=0`,
697
+ * which the dispatch loops treat as "no fold this frame" — byte-identical
698
+ * to pre-feat behavior.
699
+ */
700
+ export function buildFoldDispatchPlan(
701
+ buckets: readonly FoldBucket[],
702
+ renderableIndexToValidatedIndex: ReadonlyMap<number, number>,
703
+ ): FoldDispatchPlan {
704
+ const headBuckets = new Map<number, FoldBucket>();
705
+ const skipIndices = new Set<number>();
706
+ let foldedBucketCount = 0;
707
+ for (const bucket of buckets) {
708
+ if (bucket.bucketSize <= 1) continue;
709
+ const headEntry = bucket.entries[0];
710
+ if (headEntry === undefined) continue;
711
+ const headValidatedIdx = renderableIndexToValidatedIndex.get(headEntry.renderableIndex);
712
+ if (headValidatedIdx === undefined) continue;
713
+ headBuckets.set(headValidatedIdx, bucket);
714
+ foldedBucketCount += 1;
715
+ for (let i = 1; i < bucket.entries.length; i++) {
716
+ const memberEntry = bucket.entries[i];
717
+ if (memberEntry === undefined) continue;
718
+ const memberValidatedIdx = renderableIndexToValidatedIndex.get(memberEntry.renderableIndex);
719
+ if (memberValidatedIdx === undefined) continue;
720
+ skipIndices.add(memberValidatedIdx);
721
+ }
722
+ }
723
+ return { headBuckets, skipIndices, foldedBucketCount };
724
+ }
725
+
726
+ /**
727
+ * WebGL2 uniform-fallback per-bucket instance-count ceiling
728
+ * (feat-20260622-chunk-gpu-instancing-sprite-tilemap M2 / D-2 +
729
+ * research N-1).
730
+ *
731
+ * 128 instances * 64 B/mat4 stride = 8192 B, comfortably below the WebGL2
732
+ * minimum 16384 B UBO size, leaving headroom for the per-frame material
733
+ * UBO slice. Locked at the type level via `RhiInstancingExceedsUniformCapDetail.limit`
734
+ * (literal 128) — a future cap change would be a major evolution, not a
735
+ * runtime knob.
736
+ */
737
+ export const FOLD_UNIFORM_INSTANCE_CAP = 128;
738
+
739
+ /**
740
+ * Minimal `RhiCapabilities` shape consumed by the cap-fallback helper.
741
+ *
742
+ * The real `RhiDevice.caps` carries many feature flags; the helper only
743
+ * reads `storageBuffer` (the WebGL2 / WebGPU split signal — true on
744
+ * WebGPU + dawn / wgpu native paths, false on the WebGL2 uniform-only
745
+ * fallback path). Mirrors the field name on the production `RhiCaps`
746
+ * type so the dispatch site can pass `runtime.device.caps` straight in.
747
+ */
748
+ export interface FoldCapsLike {
749
+ readonly storageBuffer: boolean;
750
+ }
751
+
752
+ /**
753
+ * Decision POD returned by {@link evaluateFoldBucketUniformCap}.
754
+ *
755
+ * Fields:
756
+ * - `fallback` — `true` when the bucket must NOT fold and the dispatch
757
+ * site must route it through the per-entity drawIndexed exit (the
758
+ * same exit the mode-gate bypass uses, plan-strategy D-9 "shared
759
+ * fallback exit"). `false` when the bucket can fold normally.
760
+ * - `error` — the structured RhiError to fire alongside the fallback.
761
+ * Always populated when `fallback === true`; always `undefined` when
762
+ * `fallback === false` (charter proposition 4: explicit failure on
763
+ * the failure path; silent success on the success path).
764
+ *
765
+ * Caller contract: when `fallback === true`, fire the error via the
766
+ * runtime error registry AND draw the bucket's entries individually
767
+ * (each as a 1-instance drawIndexed). Skipping the fallback while still
768
+ * firing the error would leave the frame visually wrong (uniform buffer
769
+ * write would clip at 128 entries).
770
+ */
771
+ export interface FoldBucketCapDecision {
772
+ readonly fallback: boolean;
773
+ readonly error: RhiError | undefined;
774
+ }
775
+
776
+ /**
777
+ * Decide whether a fold bucket fits the WebGL2 uniform-fallback per-bucket
778
+ * instance-count ceiling, returning the structured RhiError + fallback
779
+ * intent the dispatch site needs to act on
780
+ * (feat-20260622-chunk-gpu-instancing-sprite-tilemap M2 / w11 +
781
+ * plan-strategy D-2 + D-9 + AC-05).
782
+ *
783
+ * Decision matrix:
784
+ *
785
+ * | caps.storageBuffer | bucketSize | fallback | error |
786
+ * |:--|:--|:--|:--|
787
+ * | `true` | every | `false` | `undefined` (WebGPU has no per-binding instance cap inside the storage buffer's `maxStorageBufferBindingSize`; the byte-cap path emits `'limit-exceeded'` separately) |
788
+ * | `false` | `<= 128` | `false` | `undefined` (fits inside the WebGL2 minimum 16384 B UBO with headroom) |
789
+ * | `false` | `> 128` | `true` | `RhiError({ code: 'instancing-exceeds-uniform-cap', detail: { requested, limit: 128, scope } })` |
790
+ *
791
+ * Singleton buckets (`bucketSize === 1`) always pass — they are the
792
+ * mode-gate bypass output and never need the cap check (the cap is
793
+ * about *folded* bucket arity, not about per-entity per-frame work).
794
+ *
795
+ * @param bucket — the FoldBucket whose `bucketSize` is the sole input
796
+ * (instance count = bucketSize); other fields are not consulted.
797
+ * @param caps — the runtime's RHI capability flags
798
+ * (`runtime.device.caps`); only `storageBuffer` is read.
799
+ * @param scope — closed `'sprite' | 'tilemap-chunk'` discriminator the
800
+ * dispatch site picks based on the call site (sprite-pass primary
801
+ * sprite entry vs tilemap-chunk-derived entry). Surfaced verbatim on
802
+ * the error's `.detail.scope` so AI users can branch their recovery
803
+ * on which dispatch site overflowed.
804
+ * @returns a {@link FoldBucketCapDecision} POD; never throws.
805
+ */
806
+ export function evaluateFoldBucketUniformCap(
807
+ bucket: FoldBucket,
808
+ caps: FoldCapsLike,
809
+ scope: 'sprite' | 'tilemap-chunk',
810
+ ): FoldBucketCapDecision {
811
+ if (caps.storageBuffer) return { fallback: false, error: undefined };
812
+ if (bucket.bucketSize <= FOLD_UNIFORM_INSTANCE_CAP) {
813
+ return { fallback: false, error: undefined };
814
+ }
815
+ const error = new RhiError({
816
+ code: 'instancing-exceeds-uniform-cap',
817
+ expected: `bucket instance count <= ${FOLD_UNIFORM_INSTANCE_CAP} (uniform fallback cap)`,
818
+ hint: `reduce the bucket size (smaller layer/material groupings), switch to a WebGPU-capable backend (storage buffers lift the cap), or accept the per-cell drawIndexed fallback for ${scope}`,
819
+ detail: {
820
+ requested: bucket.bucketSize,
821
+ limit: FOLD_UNIFORM_INSTANCE_CAP,
822
+ scope,
823
+ },
824
+ });
825
+ return { fallback: true, error };
826
+ }
827
+
828
+ /**
829
+ * Closed metric key for the AC-06 fold counter
830
+ * (feat-20260622-chunk-gpu-instancing-sprite-tilemap M3 / D-3).
831
+ *
832
+ * Semantics — count of instanced `drawIndexed` calls the fold operator
833
+ * emits this frame; one increment per non-singleton head bucket retained
834
+ * after the M2 / w11 cap-fallback filter. NOT entity count, NOT pre-
835
+ * filter bucket count — cap-overrun buckets that the dispatch site
836
+ * routed through the per-entity fallback exit do not count.
837
+ *
838
+ * Naming follows the EngineMetrics dot-namespace convention
839
+ * (`<feature>.<event>`); `render.instancing.*` covers both sprite and
840
+ * tilemap-chunk dispatch sites without scope ambiguity (research F-5,
841
+ * plan-strategy §8.2). The owning host evidence reads
842
+ * `ownerMetrics.snapshot()['render.instancing.foldedDraws']`.
843
+ */
844
+ export const FOLDED_DRAWS_METRIC_KEY = 'render.instancing.foldedDraws';
845
+
846
+ /**
847
+ * Minimal `EngineMetrics` shape consumed by {@link incrementFoldedDrawsMetric}.
848
+ *
849
+ * The real `EngineMetrics` carries `snapshot()` + `reset()` too; the
850
+ * helper only writes, so the consumed surface narrows to a single
851
+ * method. Lets the unit test inject a `vi.fn()` mock without faking the
852
+ * read APIs.
853
+ */
854
+ export interface FoldMetricsLike {
855
+ increment(name: string): void;
856
+ }
857
+
858
+ /**
859
+ * Bump the AC-06 `render.instancing.foldedDraws` counter once per fold-
860
+ * eligible head bucket in `plan` (M3 / w13, plan-strategy D-3).
861
+ *
862
+ * Single counter-write site for the metric — the record-stage consumer
863
+ * calls this once per `recordFrame` after the cap-fallback filter
864
+ * (M2 / w11) so cap-overrun buckets do not contribute (their members
865
+ * fall through to per-entity drawIndexed, which is not an instanced
866
+ * draw). `plan.foldedBucketCount` is the SSOT for "how many instanced
867
+ * drawIndexed will this frame emit"; passing the same plan to this
868
+ * helper keeps the metric and the actual dispatch in lockstep.
869
+ *
870
+ * Mode-bypass plans (D-5: mode != 0 yields singleton-only buckets which
871
+ * `buildFoldDispatchPlan` filters out) carry `foldedBucketCount === 0`
872
+ * and produce no increments — per-entity drawIndexed is not folded so
873
+ * the metric correctly stays at 0.
874
+ *
875
+ * @param plan — output of {@link buildFoldDispatchPlan} after possible
876
+ * cap-fallback filtering by the record-stage consumer.
877
+ * @param metrics — the owner-provided EngineMetrics counter; only
878
+ * `increment(name)` is called. Empty `plan.foldedBucketCount === 0`
879
+ * produces zero calls (no metric churn for fold-disabled frames).
880
+ */
881
+ export function incrementFoldedDrawsMetric(plan: FoldDispatchPlan, metrics: FoldMetricsLike): void {
882
+ for (let i = 0; i < plan.foldedBucketCount; i++) {
883
+ metrics.increment(FOLDED_DRAWS_METRIC_KEY);
884
+ }
885
+ }