@forgeax/engine-render 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1172) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1019 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/analytic-sky-contract.test.d.ts +2 -0
  5. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +1 -0
  6. package/dist/__tests__/analytic-sky-falsify.test.d.ts +2 -0
  7. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +1 -0
  8. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +2 -0
  9. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +1 -0
  10. package/dist/__tests__/authoring-path.unit.test.d.ts +2 -0
  11. package/dist/__tests__/authoring-path.unit.test.d.ts.map +1 -0
  12. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts +2 -0
  13. package/dist/__tests__/backend-selection-rhi-capture.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
  15. package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
  16. package/dist/__tests__/callback-inference.test-d.d.ts +2 -0
  17. package/dist/__tests__/callback-inference.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/camera-temporal.test-d.d.ts +2 -0
  19. package/dist/__tests__/camera-temporal.test-d.d.ts.map +1 -0
  20. package/dist/__tests__/camera-temporal.test.d.ts +2 -0
  21. package/dist/__tests__/camera-temporal.test.d.ts.map +1 -0
  22. package/dist/__tests__/cluster-binner.test.d.ts +2 -0
  23. package/dist/__tests__/cluster-binner.test.d.ts.map +1 -0
  24. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts +2 -0
  25. package/dist/__tests__/cluster-grid-default-surface.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts +2 -0
  27. package/dist/__tests__/construct-renderer-identity.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts +2 -0
  29. package/dist/__tests__/direct-extract-consumer-contract.test-d.d.ts.map +1 -0
  30. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts +2 -0
  31. package/dist/__tests__/direct-light-snapshot.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +2 -0
  33. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/environment-inspection.test.d.ts +2 -0
  35. package/dist/__tests__/environment-inspection.test.d.ts.map +1 -0
  36. package/dist/__tests__/factory-contract.integration.test.d.ts +2 -0
  37. package/dist/__tests__/factory-contract.integration.test.d.ts.map +1 -0
  38. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts +2 -0
  39. package/dist/__tests__/fallback-row-stride-surface.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/fog-ai-user.fixture.d.ts +2 -0
  41. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +1 -0
  42. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +16 -0
  43. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +1 -0
  44. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +2 -0
  45. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +1 -0
  46. package/dist/__tests__/fog-inspection.integration.test.d.ts +2 -0
  47. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +1 -0
  48. package/dist/__tests__/fog-owner-state.integration.test.d.ts +2 -0
  49. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +1 -0
  50. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +2 -0
  51. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +1 -0
  52. package/dist/__tests__/fog-public-surface.integration.test.d.ts +2 -0
  53. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +1 -0
  54. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +2 -0
  55. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +1 -0
  56. package/dist/__tests__/fog-source-absence.integration.test.d.ts +2 -0
  57. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +1 -0
  58. package/dist/__tests__/fog-temporal.integration.test.d.ts +2 -0
  59. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +1 -0
  60. package/dist/__tests__/frame-chain.unit.test.d.ts +2 -0
  61. package/dist/__tests__/frame-chain.unit.test.d.ts.map +1 -0
  62. package/dist/__tests__/frame-observation.contract.test.d.ts +2 -0
  63. package/dist/__tests__/frame-observation.contract.test.d.ts.map +1 -0
  64. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts +2 -0
  65. package/dist/__tests__/glyph-text-layout-recovery.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts +6 -0
  67. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -0
  68. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts +2 -0
  69. package/dist/__tests__/gpu-driven-indirect-raster.browser.test.d.ts.map +1 -0
  70. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts +2 -0
  71. package/dist/__tests__/gpu-driven-indirect-raster.dawn.test.d.ts.map +1 -0
  72. package/dist/__tests__/gpu-driven-production.integration.test.d.ts +2 -0
  73. package/dist/__tests__/gpu-driven-production.integration.test.d.ts.map +1 -0
  74. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts +2 -0
  75. package/dist/__tests__/gpu-driven-scaling.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +12 -0
  77. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -0
  78. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts +2 -0
  79. package/dist/__tests__/gpu-driven-view-graph.integration.test.d.ts.map +1 -0
  80. package/dist/__tests__/gpu-driven-view.browser.test.d.ts +2 -0
  81. package/dist/__tests__/gpu-driven-view.browser.test.d.ts.map +1 -0
  82. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts +2 -0
  83. package/dist/__tests__/gpu-driven-view.dawn.test.d.ts.map +1 -0
  84. package/dist/__tests__/gpu-driven-view.unit.test.d.ts +2 -0
  85. package/dist/__tests__/gpu-driven-view.unit.test.d.ts.map +1 -0
  86. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts +2 -0
  87. package/dist/__tests__/gpu-resource-store-stride.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +2 -0
  89. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +1 -0
  90. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts +7 -0
  91. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -0
  92. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts +2 -0
  93. package/dist/__tests__/gpu-scene-render-graph.browser.test.d.ts.map +1 -0
  94. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts +2 -0
  95. package/dist/__tests__/gpu-scene-render-graph.dawn.test.d.ts.map +1 -0
  96. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts +2 -0
  97. package/dist/__tests__/gpu-scene-schema.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/gpu-scene.dawn.test.d.ts +2 -0
  99. package/dist/__tests__/gpu-scene.dawn.test.d.ts.map +1 -0
  100. package/dist/__tests__/gpu-scene.unit.test.d.ts +2 -0
  101. package/dist/__tests__/gpu-scene.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +2 -0
  103. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +1 -0
  104. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +2 -0
  105. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts +2 -0
  107. package/dist/__tests__/infinite-grid-no-vertex-probe.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/injection-kind-owner.test-d.d.ts +2 -0
  109. package/dist/__tests__/injection-kind-owner.test-d.d.ts.map +1 -0
  110. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts +2 -0
  111. package/dist/__tests__/ktx2-basis-gpu-consumer.dawn.test.d.ts.map +1 -0
  112. package/dist/__tests__/light-buffer-layout.unit.test.d.ts +2 -0
  113. package/dist/__tests__/light-buffer-layout.unit.test.d.ts.map +1 -0
  114. package/dist/__tests__/material-contract-inventory.unit.test.d.ts +2 -0
  115. package/dist/__tests__/material-contract-inventory.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/material-cooked-projection.unit.test.d.ts +2 -0
  117. package/dist/__tests__/material-cooked-projection.unit.test.d.ts.map +1 -0
  118. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +2 -0
  119. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +1 -0
  120. package/dist/__tests__/material-derived-payload.integration.test.d.ts +2 -0
  121. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +1 -0
  122. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts +2 -0
  123. package/dist/__tests__/material-snapshot-mutation.integration.test.d.ts.map +1 -0
  124. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts +2 -0
  125. package/dist/__tests__/material-static-dynamic-route.unit.test.d.ts.map +1 -0
  126. package/dist/__tests__/material-stride-surface.unit.test.d.ts +2 -0
  127. package/dist/__tests__/material-stride-surface.unit.test.d.ts.map +1 -0
  128. package/dist/__tests__/materials.unit.test.d.ts +2 -0
  129. package/dist/__tests__/materials.unit.test.d.ts.map +1 -0
  130. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts +2 -0
  131. package/dist/__tests__/mesh-buffer-usage-surface.unit.test.d.ts.map +1 -0
  132. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts +2 -0
  133. package/dist/__tests__/mesh-material-bindings.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts +2 -0
  135. package/dist/__tests__/mesh-stride-surface.unit.test.d.ts.map +1 -0
  136. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts +2 -0
  137. package/dist/__tests__/morph-culling-reentry.dawn.test.d.ts.map +1 -0
  138. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts +2 -0
  139. package/dist/__tests__/morph-feature-gpu-work.integration.test.d.ts.map +1 -0
  140. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts +2 -0
  141. package/dist/__tests__/morph-visual-evidence.integration.test.d.ts.map +1 -0
  142. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts +2 -0
  143. package/dist/__tests__/nineslice-handle-surface.unit.test.d.ts.map +1 -0
  144. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +2 -0
  145. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +1 -0
  146. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +2 -0
  147. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +1 -0
  148. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +2 -0
  149. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +1 -0
  150. package/dist/__tests__/pipeline-pass-trace.test.d.ts +2 -0
  151. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +1 -0
  152. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +2 -0
  153. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +1 -0
  154. package/dist/__tests__/plugin.test.d.ts +2 -0
  155. package/dist/__tests__/plugin.test.d.ts.map +1 -0
  156. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts +2 -0
  157. package/dist/__tests__/post-process-error-policy-owner.unit.test.d.ts.map +1 -0
  158. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts +2 -0
  159. package/dist/__tests__/prepared-buffer-kind-owner.test-d.d.ts.map +1 -0
  160. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +2 -0
  161. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts +2 -0
  163. package/dist/__tests__/prepared-graphics-capability.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts +2 -0
  165. package/dist/__tests__/prepared-graphics-generation.unit.test.d.ts.map +1 -0
  166. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts +2 -0
  167. package/dist/__tests__/prepared-graphics-lifecycle.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts +2 -0
  169. package/dist/__tests__/prepared-graphics-pipeline-warmup.unit.test.d.ts.map +1 -0
  170. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +2 -0
  171. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +1 -0
  172. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts +2 -0
  173. package/dist/__tests__/prepared-graphics-resolver.unit.test.d.ts.map +1 -0
  174. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts +2 -0
  175. package/dist/__tests__/prepared-graphics-snapshot.unit.test.d.ts.map +1 -0
  176. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts +2 -0
  177. package/dist/__tests__/prepared-graphics-store.unit.test.d.ts.map +1 -0
  178. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts +2 -0
  179. package/dist/__tests__/prepared-graphics-validation.unit.test.d.ts.map +1 -0
  180. package/dist/__tests__/profiler-default-off.test.d.ts +2 -0
  181. package/dist/__tests__/profiler-default-off.test.d.ts.map +1 -0
  182. package/dist/__tests__/profiler-phase-catalog.test.d.ts +2 -0
  183. package/dist/__tests__/profiler-phase-catalog.test.d.ts.map +1 -0
  184. package/dist/__tests__/profiler-phase-integration.test.d.ts +2 -0
  185. package/dist/__tests__/profiler-phase-integration.test.d.ts.map +1 -0
  186. package/dist/__tests__/profiler-phase-token.test.d.ts +2 -0
  187. package/dist/__tests__/profiler-phase-token.test.d.ts.map +1 -0
  188. package/dist/__tests__/public-pipeline-id.test-d.d.ts +2 -0
  189. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +1 -0
  190. package/dist/__tests__/public-surface.test-d.d.ts +2 -0
  191. package/dist/__tests__/public-surface.test-d.d.ts.map +1 -0
  192. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts +2 -0
  193. package/dist/__tests__/recover-error-policy-owner.unit.test.d.ts.map +1 -0
  194. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +2 -0
  195. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +1 -0
  196. package/dist/__tests__/render-error-code-owner.test-d.d.ts +2 -0
  197. package/dist/__tests__/render-error-code-owner.test-d.d.ts.map +1 -0
  198. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts +2 -0
  199. package/dist/__tests__/render-error-detail-ssot.test-d.d.ts.map +1 -0
  200. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +2 -0
  201. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  202. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  203. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  204. package/dist/__tests__/render-feature-construction.unit.test.d.ts +2 -0
  205. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +1 -0
  206. package/dist/__tests__/render-feature-context.test-d.d.ts +2 -0
  207. package/dist/__tests__/render-feature-context.test-d.d.ts.map +1 -0
  208. package/dist/__tests__/render-feature-contract.test-d.d.ts +2 -0
  209. package/dist/__tests__/render-feature-contract.test-d.d.ts.map +1 -0
  210. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts +2 -0
  211. package/dist/__tests__/render-feature-diagnostics.unit.test.d.ts.map +1 -0
  212. package/dist/__tests__/render-feature-docs.unit.test.d.ts +2 -0
  213. package/dist/__tests__/render-feature-docs.unit.test.d.ts.map +1 -0
  214. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +2 -0
  215. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +1 -0
  216. package/dist/__tests__/render-feature-errors.unit.test.d.ts +2 -0
  217. package/dist/__tests__/render-feature-errors.unit.test.d.ts.map +1 -0
  218. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +2 -0
  219. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +1 -0
  220. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts +2 -0
  221. package/dist/__tests__/render-feature-gpu-work.integration.test.d.ts.map +1 -0
  222. package/dist/__tests__/render-feature-graph.integration.test.d.ts +2 -0
  223. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +1 -0
  224. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +2 -0
  225. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +1 -0
  226. package/dist/__tests__/render-feature-order.unit.test.d.ts +2 -0
  227. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +1 -0
  228. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts +2 -0
  229. package/dist/__tests__/render-feature-prepared-diagnostics.unit.test.d.ts.map +1 -0
  230. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts +2 -0
  231. package/dist/__tests__/render-feature-prepared-errors.test-d.d.ts.map +1 -0
  232. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  233. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  234. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts +2 -0
  235. package/dist/__tests__/render-feature-prepared-graphics-isolation.unit.test.d.ts.map +1 -0
  236. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts +2 -0
  237. package/dist/__tests__/render-feature-prepared-graphics-negative.test-d.d.ts.map +1 -0
  238. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +2 -0
  239. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +1 -0
  240. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts +2 -0
  241. package/dist/__tests__/render-feature-prepared-graphics.test-d.d.ts.map +1 -0
  242. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts +2 -0
  243. package/dist/__tests__/render-feature-prepared-graphics.unit.test.d.ts.map +1 -0
  244. package/dist/__tests__/render-feature-public-surface.test-d.d.ts +2 -0
  245. package/dist/__tests__/render-feature-public-surface.test-d.d.ts.map +1 -0
  246. package/dist/__tests__/render-feature-retry.unit.test.d.ts +2 -0
  247. package/dist/__tests__/render-feature-retry.unit.test.d.ts.map +1 -0
  248. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts +2 -0
  249. package/dist/__tests__/render-feature-scheduling.unit.test.d.ts.map +1 -0
  250. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts +2 -0
  251. package/dist/__tests__/render-feature-stage-failed-policy-owner.unit.test.d.ts.map +1 -0
  252. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts +2 -0
  253. package/dist/__tests__/render-feature-stage-fault-recovery.unit.test.d.ts.map +1 -0
  254. package/dist/__tests__/render-feature-staging.unit.test.d.ts +2 -0
  255. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +1 -0
  256. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts +2 -0
  257. package/dist/__tests__/render-feature-visibility-context.test-d.d.ts.map +1 -0
  258. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts +2 -0
  259. package/dist/__tests__/render-feature-visibility-context.unit.test.d.ts.map +1 -0
  260. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts +2 -0
  261. package/dist/__tests__/render-feature-zero-work.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts +7 -0
  263. package/dist/__tests__/render-graph-compute-raster-gpu.d.ts.map +1 -0
  264. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts +2 -0
  265. package/dist/__tests__/render-graph-compute-raster.browser.test.d.ts.map +1 -0
  266. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts +2 -0
  267. package/dist/__tests__/render-graph-compute-raster.dawn.test.d.ts.map +1 -0
  268. package/dist/__tests__/render-graph-hzb-gpu.d.ts +7 -0
  269. package/dist/__tests__/render-graph-hzb-gpu.d.ts.map +1 -0
  270. package/dist/__tests__/render-graph-hzb.browser.test.d.ts +2 -0
  271. package/dist/__tests__/render-graph-hzb.browser.test.d.ts.map +1 -0
  272. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts +2 -0
  273. package/dist/__tests__/render-graph-hzb.dawn.test.d.ts.map +1 -0
  274. package/dist/__tests__/render-graph-primitives.unit.test.d.ts +2 -0
  275. package/dist/__tests__/render-graph-primitives.unit.test.d.ts.map +1 -0
  276. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts +12 -0
  277. package/dist/__tests__/render-graph-storage-indirect-gpu.d.ts.map +1 -0
  278. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts +2 -0
  279. package/dist/__tests__/render-graph-storage-indirect.browser.test.d.ts.map +1 -0
  280. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts +2 -0
  281. package/dist/__tests__/render-graph-storage-indirect.dawn.test.d.ts.map +1 -0
  282. package/dist/__tests__/render-scene-projection.unit.test.d.ts +2 -0
  283. package/dist/__tests__/render-scene-projection.unit.test.d.ts.map +1 -0
  284. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts +2 -0
  285. package/dist/__tests__/renderer-factory-material-contract.unit.test.d.ts.map +1 -0
  286. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  287. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  288. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +2 -0
  289. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +1 -0
  290. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts +2 -0
  291. package/dist/__tests__/rhi-backend-package-boundary.unit.test.d.ts.map +1 -0
  292. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +2 -0
  293. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +1 -0
  294. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts +2 -0
  295. package/dist/__tests__/scriptable-pack-consumer.test-d.d.ts.map +1 -0
  296. package/dist/__tests__/shader-stage-surface.unit.test.d.ts +2 -0
  297. package/dist/__tests__/shader-stage-surface.unit.test.d.ts.map +1 -0
  298. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts +2 -0
  299. package/dist/__tests__/ssao-kernel-surface.unit.test.d.ts.map +1 -0
  300. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +2 -0
  301. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +1 -0
  302. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +2 -0
  303. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +1 -0
  304. package/dist/__tests__/surface-configuration.unit.test.d.ts +2 -0
  305. package/dist/__tests__/surface-configuration.unit.test.d.ts.map +1 -0
  306. package/dist/__tests__/taa-history-store.unit.test.d.ts +2 -0
  307. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +1 -0
  308. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +2 -0
  309. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +1 -0
  310. package/dist/__tests__/temporal-inspection.unit.test.d.ts +2 -0
  311. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +1 -0
  312. package/dist/__tests__/texture-usage-surface.unit.test.d.ts +2 -0
  313. package/dist/__tests__/texture-usage-surface.unit.test.d.ts.map +1 -0
  314. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts +2 -0
  315. package/dist/__tests__/typed-pipeline-topology.unit.test.d.ts.map +1 -0
  316. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts +2 -0
  317. package/dist/__tests__/urp-pipeline-targets.unit.test.d.ts.map +1 -0
  318. package/dist/__tests__/urp-pipeline.unit.test.d.ts +2 -0
  319. package/dist/__tests__/urp-pipeline.unit.test.d.ts.map +1 -0
  320. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts +2 -0
  321. package/dist/__tests__/vertex-color-pipeline.unit.test.d.ts.map +1 -0
  322. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts +2 -0
  323. package/dist/__tests__/vertex-layout-consumer.unit.test.d.ts.map +1 -0
  324. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts +2 -0
  325. package/dist/__tests__/visibility-diagnostics.integration.test.d.ts.map +1 -0
  326. package/dist/__tests__/visibility-extract.integration.test.d.ts +2 -0
  327. package/dist/__tests__/visibility-extract.integration.test.d.ts.map +1 -0
  328. package/dist/__tests__/visibility-extract.perf.test.d.ts +2 -0
  329. package/dist/__tests__/visibility-extract.perf.test.d.ts.map +1 -0
  330. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts +2 -0
  331. package/dist/__tests__/visibility-feature-dedup.integration.test.d.ts.map +1 -0
  332. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts +2 -0
  333. package/dist/__tests__/visibility-hidden-report.unit.test.d.ts.map +1 -0
  334. package/dist/__tests__/visibility-instances.integration.test.d.ts +2 -0
  335. package/dist/__tests__/visibility-instances.integration.test.d.ts.map +1 -0
  336. package/dist/__tests__/visibility-multi-world.integration.test.d.ts +2 -0
  337. package/dist/__tests__/visibility-multi-world.integration.test.d.ts.map +1 -0
  338. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts +2 -0
  339. package/dist/__tests__/visibility-producer-matrix.integration.test.d.ts.map +1 -0
  340. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts +2 -0
  341. package/dist/__tests__/visibility-producer-matrix.unit.test.d.ts.map +1 -0
  342. package/dist/__tests__/visibility-public-surface.test-d.d.ts +2 -0
  343. package/dist/__tests__/visibility-public-surface.test-d.d.ts.map +1 -0
  344. package/dist/__tests__/visibility-resolver.unit.test.d.ts +2 -0
  345. package/dist/__tests__/visibility-resolver.unit.test.d.ts.map +1 -0
  346. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts +2 -0
  347. package/dist/__tests__/visibility-snapshot-contract.unit.test.d.ts.map +1 -0
  348. package/dist/__tests__/vocabulary.unit.test.d.ts +2 -0
  349. package/dist/__tests__/vocabulary.unit.test.d.ts.map +1 -0
  350. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +2 -0
  351. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +1 -0
  352. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +2 -0
  353. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
  354. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +2 -0
  355. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +1 -0
  356. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +2 -0
  357. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +1 -0
  358. package/dist/assets/asset-decoders.d.ts +5 -0
  359. package/dist/assets/asset-decoders.d.ts.map +1 -0
  360. package/dist/assets/render-asset-port.d.ts +17 -0
  361. package/dist/assets/render-asset-port.d.ts.map +1 -0
  362. package/dist/assets/resolve-render-asset.d.ts +6 -0
  363. package/dist/assets/resolve-render-asset.d.ts.map +1 -0
  364. package/dist/authoring.d.ts +12 -0
  365. package/dist/authoring.d.ts.map +1 -0
  366. package/dist/authoring.mjs +5 -0
  367. package/dist/authoring.mjs.map +1 -0
  368. package/dist/chunk-33UF5SAO.mjs +7397 -0
  369. package/dist/chunk-33UF5SAO.mjs.map +1 -0
  370. package/dist/chunk-A5QCJSNL.mjs +29913 -0
  371. package/dist/chunk-A5QCJSNL.mjs.map +1 -0
  372. package/dist/chunk-JMSB7AR4.mjs +3 -0
  373. package/dist/chunk-JMSB7AR4.mjs.map +1 -0
  374. package/dist/chunk-LXNGO6AO.mjs +569 -0
  375. package/dist/chunk-LXNGO6AO.mjs.map +1 -0
  376. package/dist/chunk-QRXPSX4X.mjs +659 -0
  377. package/dist/chunk-QRXPSX4X.mjs.map +1 -0
  378. package/dist/chunk-YAKEQPWO.mjs +1439 -0
  379. package/dist/chunk-YAKEQPWO.mjs.map +1 -0
  380. package/dist/cluster-binner.d.ts +152 -0
  381. package/dist/cluster-binner.d.ts.map +1 -0
  382. package/dist/components/__tests__/atmosphere-red.test.d.ts +2 -0
  383. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +1 -0
  384. package/dist/components/__tests__/atmosphere.test.d.ts +2 -0
  385. package/dist/components/__tests__/atmosphere.test.d.ts.map +1 -0
  386. package/dist/components/__tests__/fog.test-d.d.ts +2 -0
  387. package/dist/components/__tests__/fog.test-d.d.ts.map +1 -0
  388. package/dist/components/__tests__/fog.test.d.ts +2 -0
  389. package/dist/components/__tests__/fog.test.d.ts.map +1 -0
  390. package/dist/components/__tests__/schema-parity.unit.test.d.ts +2 -0
  391. package/dist/components/__tests__/schema-parity.unit.test.d.ts.map +1 -0
  392. package/dist/components/__tests__/visibility-schema.unit.test.d.ts +2 -0
  393. package/dist/components/__tests__/visibility-schema.unit.test.d.ts.map +1 -0
  394. package/dist/components/atmosphere.d.ts +18 -0
  395. package/dist/components/atmosphere.d.ts.map +1 -0
  396. package/dist/components/camera.d.ts +311 -0
  397. package/dist/components/camera.d.ts.map +1 -0
  398. package/dist/components/directional-light.d.ts +76 -0
  399. package/dist/components/directional-light.d.ts.map +1 -0
  400. package/dist/components/environment.d.ts +116 -0
  401. package/dist/components/environment.d.ts.map +1 -0
  402. package/dist/components/glyph-text.d.ts +26 -0
  403. package/dist/components/glyph-text.d.ts.map +1 -0
  404. package/dist/components/index.d.ts +22 -0
  405. package/dist/components/index.d.ts.map +1 -0
  406. package/dist/components/instances.d.ts +41 -0
  407. package/dist/components/instances.d.ts.map +1 -0
  408. package/dist/components/layer.d.ts +34 -0
  409. package/dist/components/layer.d.ts.map +1 -0
  410. package/dist/components/light-helpers.d.ts +53 -0
  411. package/dist/components/light-helpers.d.ts.map +1 -0
  412. package/dist/components/mesh-filter.d.ts +24 -0
  413. package/dist/components/mesh-filter.d.ts.map +1 -0
  414. package/dist/components/mesh-renderer.d.ts +33 -0
  415. package/dist/components/mesh-renderer.d.ts.map +1 -0
  416. package/dist/components/point-light-shadow.d.ts +27 -0
  417. package/dist/components/point-light-shadow.d.ts.map +1 -0
  418. package/dist/components/point-light.d.ts +35 -0
  419. package/dist/components/point-light.d.ts.map +1 -0
  420. package/dist/components/post-process-params.d.ts +5 -0
  421. package/dist/components/post-process-params.d.ts.map +1 -0
  422. package/dist/components/scene-instance.d.ts +140 -0
  423. package/dist/components/scene-instance.d.ts.map +1 -0
  424. package/dist/components/sort-key.d.ts +44 -0
  425. package/dist/components/sort-key.d.ts.map +1 -0
  426. package/dist/components/spot-light.d.ts +81 -0
  427. package/dist/components/spot-light.d.ts.map +1 -0
  428. package/dist/components/sprite-animation.d.ts +75 -0
  429. package/dist/components/sprite-animation.d.ts.map +1 -0
  430. package/dist/components/sprite-instances.d.ts +51 -0
  431. package/dist/components/sprite-instances.d.ts.map +1 -0
  432. package/dist/components/sprite-playback-mode.d.ts +37 -0
  433. package/dist/components/sprite-playback-mode.d.ts.map +1 -0
  434. package/dist/components/sprite-region-override.d.ts +47 -0
  435. package/dist/components/sprite-region-override.d.ts.map +1 -0
  436. package/dist/components/tile-layer.d.ts +101 -0
  437. package/dist/components/tile-layer.d.ts.map +1 -0
  438. package/dist/components/tilemap.d.ts +25 -0
  439. package/dist/components/tilemap.d.ts.map +1 -0
  440. package/dist/components/visibility.d.ts +22 -0
  441. package/dist/components/visibility.d.ts.map +1 -0
  442. package/dist/construct-renderer.d.ts +2 -0
  443. package/dist/construct-renderer.d.ts.map +1 -0
  444. package/dist/construct-renderer.mjs +6 -0
  445. package/dist/construct-renderer.mjs.map +1 -0
  446. package/dist/debug-draw-glue.d.ts +56 -0
  447. package/dist/debug-draw-glue.d.ts.map +1 -0
  448. package/dist/deferred-lighting.d.ts +13 -0
  449. package/dist/deferred-lighting.d.ts.map +1 -0
  450. package/dist/dynamic-texture-store.d.ts +42 -0
  451. package/dist/dynamic-texture-store.d.ts.map +1 -0
  452. package/dist/engine-metrics.d.ts +23 -0
  453. package/dist/engine-metrics.d.ts.map +1 -0
  454. package/dist/environment/__tests__/failure-injection.test.d.ts +2 -0
  455. package/dist/environment/__tests__/failure-injection.test.d.ts.map +1 -0
  456. package/dist/environment/__tests__/generation-red.test.d.ts +2 -0
  457. package/dist/environment/__tests__/generation-red.test.d.ts.map +1 -0
  458. package/dist/environment/__tests__/generation.test.d.ts +2 -0
  459. package/dist/environment/__tests__/generation.test.d.ts.map +1 -0
  460. package/dist/environment/__tests__/graph-transaction.test.d.ts +2 -0
  461. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +1 -0
  462. package/dist/environment/__tests__/inspection-red.test.d.ts +2 -0
  463. package/dist/environment/__tests__/inspection-red.test.d.ts.map +1 -0
  464. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +2 -0
  465. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +1 -0
  466. package/dist/environment/__tests__/pipeline-topology.test.d.ts +2 -0
  467. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +1 -0
  468. package/dist/environment/__tests__/readiness.test.d.ts +2 -0
  469. package/dist/environment/__tests__/readiness.test.d.ts.map +1 -0
  470. package/dist/environment/__tests__/recovery.test.d.ts +2 -0
  471. package/dist/environment/__tests__/recovery.test.d.ts.map +1 -0
  472. package/dist/environment/__tests__/resize-dispose.test.d.ts +2 -0
  473. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +1 -0
  474. package/dist/environment/__tests__/signature-red.test.d.ts +2 -0
  475. package/dist/environment/__tests__/signature-red.test.d.ts.map +1 -0
  476. package/dist/environment/__tests__/signature.test.d.ts +2 -0
  477. package/dist/environment/__tests__/signature.test.d.ts.map +1 -0
  478. package/dist/environment/descriptors.d.ts +2 -0
  479. package/dist/environment/descriptors.d.ts.map +1 -0
  480. package/dist/environment/extracted-environment.d.ts +53 -0
  481. package/dist/environment/extracted-environment.d.ts.map +1 -0
  482. package/dist/environment/generation.d.ts +62 -0
  483. package/dist/environment/generation.d.ts.map +1 -0
  484. package/dist/environment/gpu-bundle.d.ts +23 -0
  485. package/dist/environment/gpu-bundle.d.ts.map +1 -0
  486. package/dist/environment/graph.d.ts +108 -0
  487. package/dist/environment/graph.d.ts.map +1 -0
  488. package/dist/environment/inspection.d.ts +48 -0
  489. package/dist/environment/inspection.d.ts.map +1 -0
  490. package/dist/environment/lifecycle.d.ts +22 -0
  491. package/dist/environment/lifecycle.d.ts.map +1 -0
  492. package/dist/environment/readiness.d.ts +29 -0
  493. package/dist/environment/readiness.d.ts.map +1 -0
  494. package/dist/environment/signature.d.ts +70 -0
  495. package/dist/environment/signature.d.ts.map +1 -0
  496. package/dist/errors/ecs-validation.d.ts +3 -0
  497. package/dist/errors/ecs-validation.d.ts.map +1 -0
  498. package/dist/errors/index.d.ts +4 -0
  499. package/dist/errors/index.d.ts.map +1 -0
  500. package/dist/errors/recover.d.ts +78 -0
  501. package/dist/errors/recover.d.ts.map +1 -0
  502. package/dist/errors/render.d.ts +633 -0
  503. package/dist/errors/render.d.ts.map +1 -0
  504. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +2 -0
  505. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +1 -0
  506. package/dist/extract/__tests__/environment-source.test.d.ts +2 -0
  507. package/dist/extract/__tests__/environment-source.test.d.ts.map +1 -0
  508. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +2 -0
  509. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +1 -0
  510. package/dist/extract/directional-csm.d.ts +129 -0
  511. package/dist/extract/directional-csm.d.ts.map +1 -0
  512. package/dist/extract/index.d.ts +5 -0
  513. package/dist/extract/index.d.ts.map +1 -0
  514. package/dist/extract/material-interface.d.ts +56 -0
  515. package/dist/extract/material-interface.d.ts.map +1 -0
  516. package/dist/extract/schema-readers.d.ts +20 -0
  517. package/dist/extract/schema-readers.d.ts.map +1 -0
  518. package/dist/extract/visibility.d.ts +26 -0
  519. package/dist/extract/visibility.d.ts.map +1 -0
  520. package/dist/features/graph-contribution.d.ts +64 -0
  521. package/dist/features/graph-contribution.d.ts.map +1 -0
  522. package/dist/features/host.d.ts +100 -0
  523. package/dist/features/host.d.ts.map +1 -0
  524. package/dist/features/index.d.ts +21 -0
  525. package/dist/features/index.d.ts.map +1 -0
  526. package/dist/features/morph/index.d.ts +3 -0
  527. package/dist/features/morph/index.d.ts.map +1 -0
  528. package/dist/features/morph/morph-bounds.d.ts +42 -0
  529. package/dist/features/morph/morph-bounds.d.ts.map +1 -0
  530. package/dist/features/morph/morph-feature.d.ts +45 -0
  531. package/dist/features/morph/morph-feature.d.ts.map +1 -0
  532. package/dist/features/prepared-gpu-work.d.ts +113 -0
  533. package/dist/features/prepared-gpu-work.d.ts.map +1 -0
  534. package/dist/features/prepared-graphics-store.d.ts +65 -0
  535. package/dist/features/prepared-graphics-store.d.ts.map +1 -0
  536. package/dist/features/prepared-graphics.d.ts +225 -0
  537. package/dist/features/prepared-graphics.d.ts.map +1 -0
  538. package/dist/features/render-graph-compute.d.ts +13 -0
  539. package/dist/features/render-graph-compute.d.ts.map +1 -0
  540. package/dist/features/render-graph-contribution.d.ts +15 -0
  541. package/dist/features/render-graph-contribution.d.ts.map +1 -0
  542. package/dist/features/render-graph-raster.d.ts +34 -0
  543. package/dist/features/render-graph-raster.d.ts.map +1 -0
  544. package/dist/features/render-graph-resources.d.ts +11 -0
  545. package/dist/features/render-graph-resources.d.ts.map +1 -0
  546. package/dist/features/scene-temporal.d.ts +45 -0
  547. package/dist/features/scene-temporal.d.ts.map +1 -0
  548. package/dist/features/taa-resolve.d.ts +21 -0
  549. package/dist/features/taa-resolve.d.ts.map +1 -0
  550. package/dist/features/targets.d.ts +32 -0
  551. package/dist/features/targets.d.ts.map +1 -0
  552. package/dist/features/types.d.ts +247 -0
  553. package/dist/features/types.d.ts.map +1 -0
  554. package/dist/frame-chain.d.ts +14 -0
  555. package/dist/frame-chain.d.ts.map +1 -0
  556. package/dist/fullscreen-post-process-pass.d.ts +178 -0
  557. package/dist/fullscreen-post-process-pass.d.ts.map +1 -0
  558. package/dist/glyph-text-layout-system.d.ts +18 -0
  559. package/dist/glyph-text-layout-system.d.ts.map +1 -0
  560. package/dist/gpu-driven/batch-topology.d.ts +124 -0
  561. package/dist/gpu-driven/batch-topology.d.ts.map +1 -0
  562. package/dist/gpu-driven/production-raster.d.ts +150 -0
  563. package/dist/gpu-driven/production-raster.d.ts.map +1 -0
  564. package/dist/gpu-driven/view-gpu.d.ts +141 -0
  565. package/dist/gpu-driven/view-gpu.d.ts.map +1 -0
  566. package/dist/gpu-driven/view-reference.d.ts +15 -0
  567. package/dist/gpu-driven/view-reference.d.ts.map +1 -0
  568. package/dist/gpu-resource-store.d.ts +294 -0
  569. package/dist/gpu-resource-store.d.ts.map +1 -0
  570. package/dist/gpu-resource.d.ts +73 -0
  571. package/dist/gpu-resource.d.ts.map +1 -0
  572. package/dist/gpu-scene-schema.d.ts +171 -0
  573. package/dist/gpu-scene-schema.d.ts.map +1 -0
  574. package/dist/gpu-scene.d.ts +81 -0
  575. package/dist/gpu-scene.d.ts.map +1 -0
  576. package/dist/gpu-stage.d.ts +4 -0
  577. package/dist/gpu-stage.d.ts.map +1 -0
  578. package/dist/gpu-texture-usage.d.ts +6 -0
  579. package/dist/gpu-texture-usage.d.ts.map +1 -0
  580. package/dist/gpu-usage.d.ts +9 -0
  581. package/dist/gpu-usage.d.ts.map +1 -0
  582. package/dist/hdrp-buffers.d.ts +213 -0
  583. package/dist/hdrp-buffers.d.ts.map +1 -0
  584. package/dist/hdrp-cluster-membership.d.ts +2 -0
  585. package/dist/hdrp-cluster-membership.d.ts.map +1 -0
  586. package/dist/hdrp-pipeline.d.ts +36 -0
  587. package/dist/hdrp-pipeline.d.ts.map +1 -0
  588. package/dist/ibl/IblPipelineCache.d.ts +274 -0
  589. package/dist/ibl/IblPipelineCache.d.ts.map +1 -0
  590. package/dist/ibl/cubemap-projection.d.ts +23 -0
  591. package/dist/ibl/cubemap-projection.d.ts.map +1 -0
  592. package/dist/ibl/face-uniforms.d.ts +65 -0
  593. package/dist/ibl/face-uniforms.d.ts.map +1 -0
  594. package/dist/ibl/skylight-bind-group.d.ts +130 -0
  595. package/dist/ibl/skylight-bind-group.d.ts.map +1 -0
  596. package/dist/index.d.ts +57 -0
  597. package/dist/index.d.ts.map +1 -0
  598. package/dist/index.mjs +5 -0
  599. package/dist/index.mjs.map +1 -0
  600. package/dist/instance-buffer-cache.d.ts +59 -0
  601. package/dist/instance-buffer-cache.d.ts.map +1 -0
  602. package/dist/internal.d.ts +74 -0
  603. package/dist/internal.d.ts.map +1 -0
  604. package/dist/internal.mjs +45 -0
  605. package/dist/internal.mjs.map +1 -0
  606. package/dist/lifecycle.d.ts +28 -0
  607. package/dist/lifecycle.d.ts.map +1 -0
  608. package/dist/light-buffer-layout.d.ts +164 -0
  609. package/dist/light-buffer-layout.d.ts.map +1 -0
  610. package/dist/materials.d.ts +50 -0
  611. package/dist/materials.d.ts.map +1 -0
  612. package/dist/mesh-material-bindings.d.ts +44 -0
  613. package/dist/mesh-material-bindings.d.ts.map +1 -0
  614. package/dist/mesh-update-errors.d.ts +71 -0
  615. package/dist/mesh-update-errors.d.ts.map +1 -0
  616. package/dist/mipmap-generator.d.ts +39 -0
  617. package/dist/mipmap-generator.d.ts.map +1 -0
  618. package/dist/param-schema-projection-census.d.ts +18 -0
  619. package/dist/param-schema-projection-census.d.ts.map +1 -0
  620. package/dist/pbr-pipeline.d.ts +253 -0
  621. package/dist/pbr-pipeline.d.ts.map +1 -0
  622. package/dist/persistent-render-scene.d.ts +158 -0
  623. package/dist/persistent-render-scene.d.ts.map +1 -0
  624. package/dist/pipeline/index.d.ts +11 -0
  625. package/dist/pipeline/index.d.ts.map +1 -0
  626. package/dist/pipeline-builder.d.ts +122 -0
  627. package/dist/pipeline-builder.d.ts.map +1 -0
  628. package/dist/pipeline-errors.d.ts +110 -0
  629. package/dist/pipeline-errors.d.ts.map +1 -0
  630. package/dist/pipeline-spec.d.ts +506 -0
  631. package/dist/pipeline-spec.d.ts.map +1 -0
  632. package/dist/plugin.d.ts +17 -0
  633. package/dist/plugin.d.ts.map +1 -0
  634. package/dist/post-process-errors.d.ts +182 -0
  635. package/dist/post-process-errors.d.ts.map +1 -0
  636. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +2 -0
  637. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +1 -0
  638. package/dist/prepare/index.d.ts +4 -0
  639. package/dist/prepare/index.d.ts.map +1 -0
  640. package/dist/prepare/prepared-graphics-resolver.d.ts +62 -0
  641. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -0
  642. package/dist/prepare/schema-readers.d.ts +11 -0
  643. package/dist/prepare/schema-readers.d.ts.map +1 -0
  644. package/dist/record/__tests__/environment-record.test.d.ts +2 -0
  645. package/dist/record/__tests__/environment-record.test.d.ts.map +1 -0
  646. package/dist/record/__tests__/frame-targets.unit.test.d.ts +2 -0
  647. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +1 -0
  648. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts +2 -0
  649. package/dist/record/__tests__/material-bg-cache.unit.test.d.ts.map +1 -0
  650. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts +2 -0
  651. package/dist/record/__tests__/material-slot-plan.unit.test.d.ts.map +1 -0
  652. package/dist/record/__tests__/membership-timing.unit.test.d.ts +2 -0
  653. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +1 -0
  654. package/dist/record/__tests__/render-submission.integration.test.d.ts +2 -0
  655. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +1 -0
  656. package/dist/record/__tests__/render-submission.perf.test.d.ts +2 -0
  657. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +1 -0
  658. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +2 -0
  659. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +1 -0
  660. package/dist/record/__tests__/video-texture-view.unit.test.d.ts +2 -0
  661. package/dist/record/__tests__/video-texture-view.unit.test.d.ts.map +1 -0
  662. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +2 -0
  663. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +1 -0
  664. package/dist/record/frame-lighting.d.ts +187 -0
  665. package/dist/record/frame-lighting.d.ts.map +1 -0
  666. package/dist/record/frame-observation.d.ts +38 -0
  667. package/dist/record/frame-observation.d.ts.map +1 -0
  668. package/dist/record/frame-snapshot.d.ts +429 -0
  669. package/dist/record/frame-snapshot.d.ts.map +1 -0
  670. package/dist/record/frame-targets.d.ts +53 -0
  671. package/dist/record/frame-targets.d.ts.map +1 -0
  672. package/dist/record/frame.d.ts +59 -0
  673. package/dist/record/frame.d.ts.map +1 -0
  674. package/dist/record/helpers.d.ts +101 -0
  675. package/dist/record/helpers.d.ts.map +1 -0
  676. package/dist/record/index.d.ts +15 -0
  677. package/dist/record/index.d.ts.map +1 -0
  678. package/dist/record/main-pass-geometry.d.ts +20 -0
  679. package/dist/record/main-pass-geometry.d.ts.map +1 -0
  680. package/dist/record/main-pass-material.d.ts +173 -0
  681. package/dist/record/main-pass-material.d.ts.map +1 -0
  682. package/dist/record/main-pass-skin.d.ts +46 -0
  683. package/dist/record/main-pass-skin.d.ts.map +1 -0
  684. package/dist/record/main-pass-sprite-draws.d.ts +18 -0
  685. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -0
  686. package/dist/record/main-pass-sprite.d.ts +69 -0
  687. package/dist/record/main-pass-sprite.d.ts.map +1 -0
  688. package/dist/record/main-pass.d.ts +20 -0
  689. package/dist/record/main-pass.d.ts.map +1 -0
  690. package/dist/record/material-payload.d.ts +43 -0
  691. package/dist/record/material-payload.d.ts.map +1 -0
  692. package/dist/record/material-slot-plan.d.ts +26 -0
  693. package/dist/record/material-slot-plan.d.ts.map +1 -0
  694. package/dist/record/membership-timing.d.ts +232 -0
  695. package/dist/record/membership-timing.d.ts.map +1 -0
  696. package/dist/record/mesh-ssbo.d.ts +173 -0
  697. package/dist/record/mesh-ssbo.d.ts.map +1 -0
  698. package/dist/record/shadow-caster-uniform.d.ts +8 -0
  699. package/dist/record/shadow-caster-uniform.d.ts.map +1 -0
  700. package/dist/record/shadow-pass.d.ts +125 -0
  701. package/dist/record/shadow-pass.d.ts.map +1 -0
  702. package/dist/record/shadow-submit-mode.d.ts +66 -0
  703. package/dist/record/shadow-submit-mode.d.ts.map +1 -0
  704. package/dist/record/skybox-post-pass.d.ts +33 -0
  705. package/dist/record/skybox-post-pass.d.ts.map +1 -0
  706. package/dist/record/typed-frame-graph.d.ts +13 -0
  707. package/dist/record/typed-frame-graph.d.ts.map +1 -0
  708. package/dist/record/view-ubo.d.ts +39 -0
  709. package/dist/record/view-ubo.d.ts.map +1 -0
  710. package/dist/render-data.d.ts +143 -0
  711. package/dist/render-data.d.ts.map +1 -0
  712. package/dist/render-dispatch-membership.d.ts +47 -0
  713. package/dist/render-dispatch-membership.d.ts.map +1 -0
  714. package/dist/render-graph-primitives.d.ts +424 -0
  715. package/dist/render-graph-primitives.d.ts.map +1 -0
  716. package/dist/render-pipeline-context.d.ts +289 -0
  717. package/dist/render-pipeline-context.d.ts.map +1 -0
  718. package/dist/render-pipeline-target.d.ts +16 -0
  719. package/dist/render-pipeline-target.d.ts.map +1 -0
  720. package/dist/render-pipeline.d.ts +149 -0
  721. package/dist/render-pipeline.d.ts.map +1 -0
  722. package/dist/render-scene-projection.d.ts +174 -0
  723. package/dist/render-scene-projection.d.ts.map +1 -0
  724. package/dist/render-system-extract.d.ts +1096 -0
  725. package/dist/render-system-extract.d.ts.map +1 -0
  726. package/dist/render-system-fold.d.ts +266 -0
  727. package/dist/render-system-fold.d.ts.map +1 -0
  728. package/dist/render-system.d.ts +814 -0
  729. package/dist/render-system.d.ts.map +1 -0
  730. package/dist/renderer/asset-service.d.ts +10 -0
  731. package/dist/renderer/asset-service.d.ts.map +1 -0
  732. package/dist/renderer/backend-selection.d.ts +26 -0
  733. package/dist/renderer/backend-selection.d.ts.map +1 -0
  734. package/dist/renderer/environment-classify.d.ts +6 -0
  735. package/dist/renderer/environment-classify.d.ts.map +1 -0
  736. package/dist/renderer/environment-error.d.ts +13 -0
  737. package/dist/renderer/environment-error.d.ts.map +1 -0
  738. package/dist/renderer/material/assembly.d.ts +22 -0
  739. package/dist/renderer/material/assembly.d.ts.map +1 -0
  740. package/dist/renderer/material/pipeline-projection.d.ts +91 -0
  741. package/dist/renderer/material/pipeline-projection.d.ts.map +1 -0
  742. package/dist/renderer/renderer-factory.d.ts +283 -0
  743. package/dist/renderer/renderer-factory.d.ts.map +1 -0
  744. package/dist/renderer.d.ts +771 -0
  745. package/dist/renderer.d.ts.map +1 -0
  746. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +33 -0
  747. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -0
  748. package/dist/scene-utils/collect-subtree.d.ts +11 -0
  749. package/dist/scene-utils/collect-subtree.d.ts.map +1 -0
  750. package/dist/shadow-atlas.d.ts +117 -0
  751. package/dist/shadow-atlas.d.ts.map +1 -0
  752. package/dist/ssao-buffers.d.ts +31 -0
  753. package/dist/ssao-buffers.d.ts.map +1 -0
  754. package/dist/ssao-config.d.ts +28 -0
  755. package/dist/ssao-config.d.ts.map +1 -0
  756. package/dist/ssao-data.d.ts +34 -0
  757. package/dist/ssao-data.d.ts.map +1 -0
  758. package/dist/surface-format.d.ts +10 -0
  759. package/dist/surface-format.d.ts.map +1 -0
  760. package/dist/systems/active-camera.d.ts +53 -0
  761. package/dist/systems/active-camera.d.ts.map +1 -0
  762. package/dist/systems/pass-selector.d.ts +24 -0
  763. package/dist/systems/pass-selector.d.ts.map +1 -0
  764. package/dist/systems/skin-palette-allocator.d.ts +51 -0
  765. package/dist/systems/skin-palette-allocator.d.ts.map +1 -0
  766. package/dist/systems/transparent-sort-config.d.ts +91 -0
  767. package/dist/systems/transparent-sort-config.d.ts.map +1 -0
  768. package/dist/taa-history-store.d.ts +88 -0
  769. package/dist/taa-history-store.d.ts.map +1 -0
  770. package/dist/temporal-coverage.d.ts +35 -0
  771. package/dist/temporal-coverage.d.ts.map +1 -0
  772. package/dist/temporal-frame-transaction.d.ts +92 -0
  773. package/dist/temporal-frame-transaction.d.ts.map +1 -0
  774. package/dist/temporal-inspection.d.ts +57 -0
  775. package/dist/temporal-inspection.d.ts.map +1 -0
  776. package/dist/temporal-view.d.ts +43 -0
  777. package/dist/temporal-view.d.ts.map +1 -0
  778. package/dist/tilemap/resolve-tileset-runtime.d.ts +23 -0
  779. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +1 -0
  780. package/dist/tilemap-chunk-extract-system.d.ts +142 -0
  781. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -0
  782. package/dist/typed-render-graph-primitives.d.ts +59 -0
  783. package/dist/typed-render-graph-primitives.d.ts.map +1 -0
  784. package/dist/typed-shadow-passes.d.ts +11 -0
  785. package/dist/typed-shadow-passes.d.ts.map +1 -0
  786. package/dist/urp-pipeline.d.ts +4 -0
  787. package/dist/urp-pipeline.d.ts.map +1 -0
  788. package/package.json +94 -0
  789. package/src/__tests__/analytic-sky-contract.test.ts +27 -0
  790. package/src/__tests__/analytic-sky-falsify-carriers.mjs +43 -0
  791. package/src/__tests__/analytic-sky-falsify.test.ts +94 -0
  792. package/src/__tests__/assets-runtime-handoff.integration.test.ts +36 -0
  793. package/src/__tests__/authoring-path.unit.test.ts +14 -0
  794. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +21 -0
  795. package/src/__tests__/backend-selection.integration.test.ts +11 -0
  796. package/src/__tests__/callback-inference.test-d.ts +5 -0
  797. package/src/__tests__/camera-temporal.test-d.ts +8 -0
  798. package/src/__tests__/camera-temporal.test.ts +188 -0
  799. package/src/__tests__/cluster-binner.test.ts +272 -0
  800. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +17 -0
  801. package/src/__tests__/construct-renderer-identity.unit.test.ts +10 -0
  802. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +34 -0
  803. package/src/__tests__/direct-light-snapshot.unit.test.ts +71 -0
  804. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +18 -0
  805. package/src/__tests__/environment-inspection.test.ts +45 -0
  806. package/src/__tests__/factory-contract.integration.test.ts +331 -0
  807. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +18 -0
  808. package/src/__tests__/fog-ai-user.fixture.ts +350 -0
  809. package/src/__tests__/fog-custom-render-feature.fixture.ts +33 -0
  810. package/src/__tests__/fog-custom-render-feature.integration.test.ts +76 -0
  811. package/src/__tests__/fog-inspection.integration.test.ts +127 -0
  812. package/src/__tests__/fog-owner-state.integration.test.ts +112 -0
  813. package/src/__tests__/fog-pipeline-topology.integration.test.ts +93 -0
  814. package/src/__tests__/fog-public-surface.integration.test.ts +60 -0
  815. package/src/__tests__/fog-ray-contract.integration.test.ts +73 -0
  816. package/src/__tests__/fog-source-absence.integration.test.ts +51 -0
  817. package/src/__tests__/fog-temporal.integration.test.ts +115 -0
  818. package/src/__tests__/frame-chain.unit.test.ts +26 -0
  819. package/src/__tests__/frame-observation.contract.test.ts +103 -0
  820. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +172 -0
  821. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +347 -0
  822. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +12 -0
  823. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +16 -0
  824. package/src/__tests__/gpu-driven-production.integration.test.ts +609 -0
  825. package/src/__tests__/gpu-driven-scaling.unit.test.ts +90 -0
  826. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +192 -0
  827. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +128 -0
  828. package/src/__tests__/gpu-driven-view.browser.test.ts +19 -0
  829. package/src/__tests__/gpu-driven-view.dawn.test.ts +17 -0
  830. package/src/__tests__/gpu-driven-view.unit.test.ts +455 -0
  831. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +59 -0
  832. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +27 -0
  833. package/src/__tests__/gpu-scene-render-graph-gpu.ts +309 -0
  834. package/src/__tests__/gpu-scene-render-graph.browser.test.ts +19 -0
  835. package/src/__tests__/gpu-scene-render-graph.dawn.test.ts +19 -0
  836. package/src/__tests__/gpu-scene-schema.unit.test.ts +16 -0
  837. package/src/__tests__/gpu-scene.dawn.test.ts +209 -0
  838. package/src/__tests__/gpu-scene.unit.test.ts +161 -0
  839. package/src/__tests__/hdrp-pipeline.unit.test.ts +100 -0
  840. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +23 -0
  841. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +124 -0
  842. package/src/__tests__/injection-kind-owner.test-d.ts +14 -0
  843. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +719 -0
  844. package/src/__tests__/light-buffer-layout.unit.test.ts +85 -0
  845. package/src/__tests__/material-contract-inventory.unit.test.ts +24 -0
  846. package/src/__tests__/material-cooked-projection.unit.test.ts +177 -0
  847. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +69 -0
  848. package/src/__tests__/material-derived-payload.integration.test.ts +164 -0
  849. package/src/__tests__/material-snapshot-mutation.integration.test.ts +58 -0
  850. package/src/__tests__/material-static-dynamic-route.unit.test.ts +113 -0
  851. package/src/__tests__/material-stride-surface.unit.test.ts +32 -0
  852. package/src/__tests__/materials.unit.test.ts +25 -0
  853. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +107 -0
  854. package/src/__tests__/mesh-material-bindings.unit.test.ts +89 -0
  855. package/src/__tests__/mesh-stride-surface.unit.test.ts +16 -0
  856. package/src/__tests__/morph-culling-reentry.dawn.test.ts +166 -0
  857. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +78 -0
  858. package/src/__tests__/morph-visual-evidence.integration.test.ts +66 -0
  859. package/src/__tests__/nineslice-handle-surface.unit.test.ts +14 -0
  860. package/src/__tests__/param-schema-projection-census.unit.test.ts +40 -0
  861. package/src/__tests__/persistent-render-scene.unit.test.ts +1311 -0
  862. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +167 -0
  863. package/src/__tests__/pipeline-pass-trace.test.ts +92 -0
  864. package/src/__tests__/pipeline-stage-owner.test-d.ts +13 -0
  865. package/src/__tests__/plugin.test.ts +25 -0
  866. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +208 -0
  867. package/src/__tests__/prepared-buffer-kind-owner.test-d.ts +29 -0
  868. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +129 -0
  869. package/src/__tests__/prepared-graphics-capability.unit.test.ts +140 -0
  870. package/src/__tests__/prepared-graphics-generation.unit.test.ts +175 -0
  871. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +206 -0
  872. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +29 -0
  873. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +180 -0
  874. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +287 -0
  875. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +105 -0
  876. package/src/__tests__/prepared-graphics-store.unit.test.ts +154 -0
  877. package/src/__tests__/prepared-graphics-validation.unit.test.ts +176 -0
  878. package/src/__tests__/profiler-default-off.test.ts +22 -0
  879. package/src/__tests__/profiler-phase-catalog.test.ts +66 -0
  880. package/src/__tests__/profiler-phase-integration.test.ts +70 -0
  881. package/src/__tests__/profiler-phase-token.test.ts +84 -0
  882. package/src/__tests__/public-pipeline-id.test-d.ts +6 -0
  883. package/src/__tests__/public-surface.test-d.ts +32 -0
  884. package/src/__tests__/recover-error-policy-owner.unit.test.ts +127 -0
  885. package/src/__tests__/render-dispatch-membership.unit.test.ts +117 -0
  886. package/src/__tests__/render-error-code-owner.test-d.ts +115 -0
  887. package/src/__tests__/render-error-detail-ssot.test-d.ts +234 -0
  888. package/src/__tests__/render-error-exhaustive.test-d.ts +84 -0
  889. package/src/__tests__/render-feature-assembly.test-d.ts +51 -0
  890. package/src/__tests__/render-feature-construction.unit.test.ts +124 -0
  891. package/src/__tests__/render-feature-context.test-d.ts +81 -0
  892. package/src/__tests__/render-feature-contract.test-d.ts +58 -0
  893. package/src/__tests__/render-feature-diagnostics.unit.test.ts +151 -0
  894. package/src/__tests__/render-feature-docs.unit.test.ts +88 -0
  895. package/src/__tests__/render-feature-error-code-owner.test-d.ts +27 -0
  896. package/src/__tests__/render-feature-errors.unit.test.ts +47 -0
  897. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +46 -0
  898. package/src/__tests__/render-feature-gpu-work.integration.test.ts +377 -0
  899. package/src/__tests__/render-feature-graph.integration.test.ts +205 -0
  900. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +200 -0
  901. package/src/__tests__/render-feature-order.unit.test.ts +66 -0
  902. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +101 -0
  903. package/src/__tests__/render-feature-prepared-errors.test-d.ts +82 -0
  904. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +141 -0
  905. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +122 -0
  906. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +59 -0
  907. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +107 -0
  908. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +96 -0
  909. package/src/__tests__/render-feature-prepared-graphics.unit.test.ts +121 -0
  910. package/src/__tests__/render-feature-public-surface.test-d.ts +75 -0
  911. package/src/__tests__/render-feature-retry.unit.test.ts +128 -0
  912. package/src/__tests__/render-feature-scheduling.unit.test.ts +122 -0
  913. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +146 -0
  914. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +236 -0
  915. package/src/__tests__/render-feature-staging.unit.test.ts +94 -0
  916. package/src/__tests__/render-feature-visibility-context.test-d.ts +38 -0
  917. package/src/__tests__/render-feature-visibility-context.unit.test.ts +38 -0
  918. package/src/__tests__/render-feature-zero-work.unit.test.ts +82 -0
  919. package/src/__tests__/render-graph-compute-raster-gpu.ts +342 -0
  920. package/src/__tests__/render-graph-compute-raster.browser.test.ts +16 -0
  921. package/src/__tests__/render-graph-compute-raster.dawn.test.ts +22 -0
  922. package/src/__tests__/render-graph-hzb-gpu.ts +239 -0
  923. package/src/__tests__/render-graph-hzb.browser.test.ts +16 -0
  924. package/src/__tests__/render-graph-hzb.dawn.test.ts +23 -0
  925. package/src/__tests__/render-graph-primitives.unit.test.ts +22 -0
  926. package/src/__tests__/render-graph-storage-indirect-gpu.ts +162 -0
  927. package/src/__tests__/render-graph-storage-indirect.browser.test.ts +21 -0
  928. package/src/__tests__/render-graph-storage-indirect.dawn.test.ts +28 -0
  929. package/src/__tests__/render-scene-projection.unit.test.ts +206 -0
  930. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +125 -0
  931. package/src/__tests__/renderer-lifecycle.integration.test.ts +10 -0
  932. package/src/__tests__/renderer-render-scene-public.test-d.ts +27 -0
  933. package/src/__tests__/rhi-backend-package-boundary.unit.test.ts +11 -0
  934. package/src/__tests__/scene-temporal-coverage.unit.test.ts +259 -0
  935. package/src/__tests__/scriptable-pack-consumer.test-d.ts +14 -0
  936. package/src/__tests__/shader-stage-surface.unit.test.ts +38 -0
  937. package/src/__tests__/ssao-kernel-surface.unit.test.ts +15 -0
  938. package/src/__tests__/sun-snapshot-consumers.test.ts +35 -0
  939. package/src/__tests__/surface-backend-kind-owner.test-d.ts +42 -0
  940. package/src/__tests__/surface-configuration.unit.test.ts +92 -0
  941. package/src/__tests__/taa-history-store.unit.test.ts +196 -0
  942. package/src/__tests__/temporal-frame-transaction.integration.test.ts +537 -0
  943. package/src/__tests__/temporal-inspection.unit.test.ts +138 -0
  944. package/src/__tests__/texture-usage-surface.unit.test.ts +61 -0
  945. package/src/__tests__/typed-pipeline-topology.unit.test.ts +389 -0
  946. package/src/__tests__/urp-pipeline-targets.unit.test.ts +52 -0
  947. package/src/__tests__/urp-pipeline.unit.test.ts +14 -0
  948. package/src/__tests__/vertex-color-pipeline.unit.test.ts +124 -0
  949. package/src/__tests__/vertex-layout-consumer.unit.test.ts +25 -0
  950. package/src/__tests__/visibility-diagnostics.integration.test.ts +66 -0
  951. package/src/__tests__/visibility-extract.integration.test.ts +89 -0
  952. package/src/__tests__/visibility-extract.perf.test.ts +96 -0
  953. package/src/__tests__/visibility-feature-dedup.integration.test.ts +57 -0
  954. package/src/__tests__/visibility-hidden-report.unit.test.ts +37 -0
  955. package/src/__tests__/visibility-instances.integration.test.ts +50 -0
  956. package/src/__tests__/visibility-multi-world.integration.test.ts +54 -0
  957. package/src/__tests__/visibility-producer-matrix.integration.test.ts +191 -0
  958. package/src/__tests__/visibility-producer-matrix.unit.test.ts +96 -0
  959. package/src/__tests__/visibility-public-surface.test-d.ts +26 -0
  960. package/src/__tests__/visibility-resolver.unit.test.ts +84 -0
  961. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +59 -0
  962. package/src/__tests__/vocabulary.unit.test.ts +21 -0
  963. package/src/assets/__tests__/asset-decoders.unit.test.ts +92 -0
  964. package/src/assets/__tests__/mipmap-generator.unit.test.ts +52 -0
  965. package/src/assets/__tests__/render-asset-port.unit.test.ts +54 -0
  966. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +47 -0
  967. package/src/assets/asset-decoders.ts +158 -0
  968. package/src/assets/render-asset-port.ts +44 -0
  969. package/src/assets/resolve-render-asset.ts +13 -0
  970. package/src/authoring.ts +24 -0
  971. package/src/cluster-binner.ts +700 -0
  972. package/src/components/__tests__/atmosphere-red.test.ts +51 -0
  973. package/src/components/__tests__/atmosphere.test.ts +79 -0
  974. package/src/components/__tests__/fog.test-d.ts +49 -0
  975. package/src/components/__tests__/fog.test.ts +60 -0
  976. package/src/components/__tests__/schema-parity.unit.test.ts +25 -0
  977. package/src/components/__tests__/visibility-schema.unit.test.ts +35 -0
  978. package/src/components/atmosphere.ts +64 -0
  979. package/src/components/camera.ts +512 -0
  980. package/src/components/directional-light.ts +120 -0
  981. package/src/components/environment.ts +206 -0
  982. package/src/components/glyph-text.ts +63 -0
  983. package/src/components/index.ts +49 -0
  984. package/src/components/instances.ts +207 -0
  985. package/src/components/layer.ts +69 -0
  986. package/src/components/light-helpers.ts +188 -0
  987. package/src/components/mesh-filter.ts +59 -0
  988. package/src/components/mesh-renderer.ts +61 -0
  989. package/src/components/point-light-shadow.ts +43 -0
  990. package/src/components/point-light.ts +65 -0
  991. package/src/components/post-process-params.ts +35 -0
  992. package/src/components/scene-instance.ts +193 -0
  993. package/src/components/sort-key.ts +75 -0
  994. package/src/components/spot-light.ts +124 -0
  995. package/src/components/sprite-animation.ts +169 -0
  996. package/src/components/sprite-instances.ts +179 -0
  997. package/src/components/sprite-playback-mode.ts +73 -0
  998. package/src/components/sprite-region-override.ts +106 -0
  999. package/src/components/tile-layer.ts +161 -0
  1000. package/src/components/tilemap.ts +48 -0
  1001. package/src/components/visibility.ts +53 -0
  1002. package/src/construct-renderer.ts +4 -0
  1003. package/src/debug-draw-glue.ts +169 -0
  1004. package/src/deferred-lighting.ts +92 -0
  1005. package/src/dynamic-texture-store.ts +111 -0
  1006. package/src/engine-metrics.ts +89 -0
  1007. package/src/environment/README.md +76 -0
  1008. package/src/environment/__tests__/failure-injection.test.ts +50 -0
  1009. package/src/environment/__tests__/generation-red.test.ts +64 -0
  1010. package/src/environment/__tests__/generation.test.ts +37 -0
  1011. package/src/environment/__tests__/graph-transaction.test.ts +85 -0
  1012. package/src/environment/__tests__/inspection-red.test.ts +53 -0
  1013. package/src/environment/__tests__/lifecycle-evidence.test.ts +40 -0
  1014. package/src/environment/__tests__/pipeline-topology.test.ts +33 -0
  1015. package/src/environment/__tests__/readiness.test.ts +42 -0
  1016. package/src/environment/__tests__/recovery.test.ts +62 -0
  1017. package/src/environment/__tests__/resize-dispose.test.ts +30 -0
  1018. package/src/environment/__tests__/signature-red.test.ts +45 -0
  1019. package/src/environment/__tests__/signature.test.ts +60 -0
  1020. package/src/environment/descriptors.ts +7 -0
  1021. package/src/environment/extracted-environment.ts +239 -0
  1022. package/src/environment/generation.ts +158 -0
  1023. package/src/environment/gpu-bundle.ts +144 -0
  1024. package/src/environment/graph.ts +588 -0
  1025. package/src/environment/inspection.ts +107 -0
  1026. package/src/environment/lifecycle.ts +124 -0
  1027. package/src/environment/readiness.ts +76 -0
  1028. package/src/environment/signature.ts +185 -0
  1029. package/src/errors/ecs-validation.ts +16 -0
  1030. package/src/errors/index.ts +3 -0
  1031. package/src/errors/recover.ts +119 -0
  1032. package/src/errors/render.ts +1244 -0
  1033. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +391 -0
  1034. package/src/extract/__tests__/environment-source.test.ts +105 -0
  1035. package/src/extract/__tests__/schema-readers.unit.test.ts +16 -0
  1036. package/src/extract/directional-csm.ts +959 -0
  1037. package/src/extract/index.ts +10 -0
  1038. package/src/extract/material-interface.ts +604 -0
  1039. package/src/extract/schema-readers.ts +27 -0
  1040. package/src/extract/visibility.ts +120 -0
  1041. package/src/features/graph-contribution.ts +577 -0
  1042. package/src/features/host.ts +1097 -0
  1043. package/src/features/index.ts +100 -0
  1044. package/src/features/morph/index.ts +24 -0
  1045. package/src/features/morph/morph-bounds.ts +123 -0
  1046. package/src/features/morph/morph-feature.ts +287 -0
  1047. package/src/features/prepared-gpu-work.ts +902 -0
  1048. package/src/features/prepared-graphics-store.ts +435 -0
  1049. package/src/features/prepared-graphics.ts +479 -0
  1050. package/src/features/render-graph-compute.ts +60 -0
  1051. package/src/features/render-graph-contribution.ts +95 -0
  1052. package/src/features/render-graph-raster.ts +308 -0
  1053. package/src/features/render-graph-resources.ts +36 -0
  1054. package/src/features/scene-temporal.ts +274 -0
  1055. package/src/features/taa-resolve.ts +244 -0
  1056. package/src/features/targets.ts +83 -0
  1057. package/src/features/types.ts +291 -0
  1058. package/src/frame-chain.ts +21 -0
  1059. package/src/fullscreen-post-process-pass.ts +406 -0
  1060. package/src/glyph-text-layout-system.ts +447 -0
  1061. package/src/gpu-driven/batch-topology.ts +423 -0
  1062. package/src/gpu-driven/production-raster.ts +1705 -0
  1063. package/src/gpu-driven/view-gpu.ts +849 -0
  1064. package/src/gpu-driven/view-reference.ts +110 -0
  1065. package/src/gpu-resource-store.ts +1921 -0
  1066. package/src/gpu-resource.ts +159 -0
  1067. package/src/gpu-scene-schema.ts +224 -0
  1068. package/src/gpu-scene.ts +855 -0
  1069. package/src/gpu-stage.ts +9 -0
  1070. package/src/gpu-texture-usage.ts +12 -0
  1071. package/src/gpu-usage.ts +14 -0
  1072. package/src/hdrp-buffers.ts +689 -0
  1073. package/src/hdrp-cluster-membership.ts +70 -0
  1074. package/src/hdrp-pipeline.ts +525 -0
  1075. package/src/ibl/IblPipelineCache.ts +1246 -0
  1076. package/src/ibl/cubemap-projection.ts +60 -0
  1077. package/src/ibl/face-uniforms.ts +150 -0
  1078. package/src/ibl/skylight-bind-group.ts +513 -0
  1079. package/src/index.ts +271 -0
  1080. package/src/instance-buffer-cache.ts +123 -0
  1081. package/src/internal.ts +88 -0
  1082. package/src/lifecycle.ts +123 -0
  1083. package/src/light-buffer-layout.ts +346 -0
  1084. package/src/materials.ts +236 -0
  1085. package/src/mesh-material-bindings.ts +104 -0
  1086. package/src/mesh-update-errors.ts +113 -0
  1087. package/src/mipmap-generator.ts +244 -0
  1088. package/src/param-schema-projection-census.ts +73 -0
  1089. package/src/pbr-pipeline.ts +749 -0
  1090. package/src/persistent-render-scene.ts +1752 -0
  1091. package/src/pipeline/index.ts +40 -0
  1092. package/src/pipeline-builder.ts +386 -0
  1093. package/src/pipeline-errors.ts +172 -0
  1094. package/src/pipeline-spec.ts +1768 -0
  1095. package/src/plugin.ts +137 -0
  1096. package/src/post-process-errors.ts +304 -0
  1097. package/src/prepare/__tests__/schema-readers.unit.test.ts +16 -0
  1098. package/src/prepare/index.ts +8 -0
  1099. package/src/prepare/prepared-graphics-resolver.ts +455 -0
  1100. package/src/prepare/schema-readers.ts +20 -0
  1101. package/src/record/__tests__/environment-record.test.ts +35 -0
  1102. package/src/record/__tests__/frame-targets.unit.test.ts +54 -0
  1103. package/src/record/__tests__/material-bg-cache.unit.test.ts +41 -0
  1104. package/src/record/__tests__/material-slot-plan.unit.test.ts +76 -0
  1105. package/src/record/__tests__/membership-timing.unit.test.ts +524 -0
  1106. package/src/record/__tests__/render-submission.integration.test.ts +76 -0
  1107. package/src/record/__tests__/render-submission.perf.test.ts +141 -0
  1108. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +88 -0
  1109. package/src/record/__tests__/video-texture-view.unit.test.ts +90 -0
  1110. package/src/record/__tests__/view-ubo-layout.unit.test.ts +101 -0
  1111. package/src/record/frame-lighting.ts +1183 -0
  1112. package/src/record/frame-observation.ts +122 -0
  1113. package/src/record/frame-snapshot.ts +515 -0
  1114. package/src/record/frame-targets.ts +372 -0
  1115. package/src/record/frame.ts +1874 -0
  1116. package/src/record/helpers.ts +289 -0
  1117. package/src/record/index.ts +15 -0
  1118. package/src/record/main-pass-geometry.ts +1014 -0
  1119. package/src/record/main-pass-material.ts +716 -0
  1120. package/src/record/main-pass-skin.ts +51 -0
  1121. package/src/record/main-pass-sprite-draws.ts +1056 -0
  1122. package/src/record/main-pass-sprite.ts +166 -0
  1123. package/src/record/main-pass.ts +588 -0
  1124. package/src/record/material-payload.ts +292 -0
  1125. package/src/record/material-slot-plan.ts +68 -0
  1126. package/src/record/membership-timing.ts +1012 -0
  1127. package/src/record/mesh-ssbo.ts +406 -0
  1128. package/src/record/shadow-caster-uniform.ts +37 -0
  1129. package/src/record/shadow-pass.ts +2387 -0
  1130. package/src/record/shadow-submit-mode.ts +277 -0
  1131. package/src/record/skybox-post-pass.ts +594 -0
  1132. package/src/record/typed-frame-graph.ts +499 -0
  1133. package/src/record/view-ubo.ts +206 -0
  1134. package/src/render-data.ts +385 -0
  1135. package/src/render-dispatch-membership.ts +155 -0
  1136. package/src/render-graph-primitives.ts +1586 -0
  1137. package/src/render-pipeline-context.ts +332 -0
  1138. package/src/render-pipeline-target.ts +96 -0
  1139. package/src/render-pipeline.ts +343 -0
  1140. package/src/render-scene-projection.ts +1738 -0
  1141. package/src/render-system-extract.ts +5203 -0
  1142. package/src/render-system-fold.ts +531 -0
  1143. package/src/render-system.ts +3258 -0
  1144. package/src/renderer/asset-service.ts +32 -0
  1145. package/src/renderer/backend-selection.ts +121 -0
  1146. package/src/renderer/environment-classify.ts +30 -0
  1147. package/src/renderer/environment-error.ts +19 -0
  1148. package/src/renderer/material/assembly.ts +53 -0
  1149. package/src/renderer/material/pipeline-projection.ts +140 -0
  1150. package/src/renderer/renderer-factory.ts +9062 -0
  1151. package/src/renderer.ts +940 -0
  1152. package/src/scene-instances/post-spawn-resolve-joints.ts +168 -0
  1153. package/src/scene-utils/collect-subtree.ts +40 -0
  1154. package/src/shadow-atlas.ts +244 -0
  1155. package/src/ssao-buffers.ts +175 -0
  1156. package/src/ssao-config.ts +61 -0
  1157. package/src/ssao-data.ts +106 -0
  1158. package/src/surface-format.ts +37 -0
  1159. package/src/systems/active-camera.ts +116 -0
  1160. package/src/systems/pass-selector.ts +49 -0
  1161. package/src/systems/skin-palette-allocator.ts +294 -0
  1162. package/src/systems/transparent-sort-config.ts +211 -0
  1163. package/src/taa-history-store.ts +429 -0
  1164. package/src/temporal-coverage.ts +106 -0
  1165. package/src/temporal-frame-transaction.ts +301 -0
  1166. package/src/temporal-inspection.ts +194 -0
  1167. package/src/temporal-view.ts +174 -0
  1168. package/src/tilemap/resolve-tileset-runtime.ts +72 -0
  1169. package/src/tilemap-chunk-extract-system.ts +1307 -0
  1170. package/src/typed-render-graph-primitives.ts +530 -0
  1171. package/src/typed-shadow-passes.ts +195 -0
  1172. package/src/urp-pipeline.ts +340 -0
@@ -0,0 +1,1921 @@
1
+ // @forgeax/engine-runtime - GpuResourceStore
2
+ // (feat-20260601-gpu-resource-store-extraction M1; M2 added the deriveRenderData
3
+ // projection seam — see render-data.ts).
4
+ //
5
+ // Owns the GPU residency layer extracted from AssetRegistry: per-handle GPU
6
+ // texture / cubemap / mesh buffer caches plus the upload primitives that
7
+ // build them. The store is engine-agnostic by default (no @webgpu/types
8
+ // imports) and holds ZERO reference to AssetRegistry (D-2): every upload
9
+ // primitive receives its source POD from the caller, never reaches back into
10
+ // a registry. The cubemap path mints its EquirectAsset POD handle through
11
+ // a wire-injected `registerCube` callback (D-3) so CPU cataloguing stays the
12
+ // registry's job while the store keeps the single-call upload contract. The
13
+ // cubemap projection (`_uploadCubemapFromEquirect`) is internal (@internal,
14
+ // feat-20260630): AI users declare `Skylight{equirect}` and the render-system
15
+ // record arm drives the projection; the method is never reached from user code.
16
+ //
17
+ // Residency model (D-2 pull): consumers call `ensureResident(handle, pod)`
18
+ // at first draw-time access; the store builds the GPU resource on a miss and
19
+ // returns the cached handles on subsequent O(1) hits. There is no global
20
+ // replay queue -- the pull model is purely lazy (user ruling). Builtin
21
+ // meshes are NOT routed through `ensureResident`; createRenderer seeds them
22
+ // via its step-3 direct upload + pipelineState.meshes (D-1).
23
+ //
24
+ // Texture residency is SYNCHRONOUS (D-9): `uploadTexture`'s only async source
25
+ // was the one-time per-device mipmap shader-module build, which is hoisted to
26
+ // `prewarmMipmapPipeline` (called from `createRenderer.ready`, already async).
27
+ // After prewarm the per-texture mipmap blit is pure synchronous encoder work,
28
+ // so the sync `draw(world)` frame contract is preserved. A format that was
29
+ // not prewarmed surfaces a structured RhiError on the sync path -- it is never
30
+ // lazily awaited (that would break the sync draw contract).
31
+
32
+ import type { World } from '@forgeax/engine-ecs';
33
+ import type { VertexLayoutProjection } from '@forgeax/engine-geometry';
34
+ import { halfFloat } from '@forgeax/engine-math';
35
+ import {
36
+ type Buffer,
37
+ err,
38
+ ok,
39
+ type Result,
40
+ type RhiCaps,
41
+ type RhiDevice,
42
+ RhiError,
43
+ type Sampler,
44
+ type Texture,
45
+ type TextureView,
46
+ } from '@forgeax/engine-rhi';
47
+ import {
48
+ ASSET_ERROR_HINTS,
49
+ type AssetError,
50
+ type DecodedImage,
51
+ type EquirectAsset,
52
+ type Handle,
53
+ handleSlot,
54
+ IMAGE_ERROR_HINTS,
55
+ type ImageError,
56
+ type ImageErrorCode,
57
+ type ImageErrorDetailFor,
58
+ type ImageErrorFor,
59
+ type PrimitiveTopology,
60
+ type SamplerAsset,
61
+ type Submesh,
62
+ type TextureAsset,
63
+ type MeshAsset as TypesMeshAsset,
64
+ } from '@forgeax/engine-types';
65
+ import { GpuBuffer, GpuTexture } from './gpu-resource';
66
+ import { GPU_TEXTURE_USAGE_COPY_DST, GPU_TEXTURE_USAGE_TEXTURE_BINDING } from './gpu-texture-usage';
67
+ import {
68
+ GPU_BUFFER_USAGE_COPY_DST,
69
+ GPU_BUFFER_USAGE_INDEX,
70
+ GPU_BUFFER_USAGE_VERTEX,
71
+ } from './gpu-usage';
72
+ import {
73
+ createFaceUniformsBuffer,
74
+ createPrefilterUniformsBuffer,
75
+ writeAllFaceUniforms,
76
+ writeAllPrefilterUniforms,
77
+ } from './ibl/face-uniforms';
78
+ import {
79
+ CUBEMAP_FACE_VERTICES,
80
+ createIblPipelines,
81
+ runIblPrecompute,
82
+ } from './ibl/IblPipelineCache';
83
+ import type { RhiErrorListenerRegistry } from './lifecycle';
84
+ import {
85
+ type MeshRangeInvalidReason,
86
+ MeshUpdateError,
87
+ type MeshUpdateError as MeshUpdateErrorType,
88
+ } from './mesh-update-errors';
89
+ import {
90
+ blitMipmapsSync,
91
+ getOrCreateMipmapPipeline,
92
+ type MipmapBlitDevice,
93
+ type MipmapShaderModuleFactory,
94
+ } from './mipmap-generator';
95
+ import {
96
+ type CubeRenderData,
97
+ deriveMipUploadLayout,
98
+ deriveRenderDataCubemap,
99
+ deriveRenderDataMesh,
100
+ deriveRenderDataTexture,
101
+ type MeshRenderData,
102
+ type TextureRenderData,
103
+ } from './render-data';
104
+
105
+ // AssetError is constructed without importing the AssetRegistry's class; the
106
+ // store builds the 4-field surface (.code / .expected / .hint / .detail)
107
+ // directly against the @forgeax/engine-types SSOT (charter P5 producer /
108
+ // consumer split; mirrors AssetRegistry's local RuntimeImageError).
109
+ class RuntimeAssetError extends Error implements AssetError {
110
+ readonly code: AssetError['code'];
111
+ readonly expected: string;
112
+ readonly hint: string;
113
+ constructor(fields: { code: AssetError['code']; expected: string; hint: string }) {
114
+ super(`[AssetError ${fields.code}] expected: ${fields.expected}; hint: ${fields.hint}`);
115
+ this.name = 'AssetError';
116
+ this.code = fields.code;
117
+ this.expected = fields.expected;
118
+ this.hint = fields.hint;
119
+ }
120
+ }
121
+
122
+ function makeAssetError(fields: {
123
+ code: AssetError['code'];
124
+ expected: string;
125
+ hint: string;
126
+ }): AssetError {
127
+ return new RuntimeAssetError(fields);
128
+ }
129
+
130
+ const IMAGE_ERROR_EXPECTED_LOCAL: Readonly<Record<string, string>> = {
131
+ 'image-decode-failed': 'PNG / JPG byte stream decodes successfully',
132
+ 'image-format-unsupported': "format ends in '-srgb' iff colorSpace is 'srgb' (linear otherwise)",
133
+ 'image-dimension-out-of-bounds':
134
+ 'width and height fall under device caps maxTextureDimension2D (or 16384 hard cap)',
135
+ };
136
+
137
+ class RuntimeImageError<C extends ImageErrorCode> extends Error implements ImageErrorFor<C> {
138
+ readonly code: C;
139
+ readonly expected: string;
140
+ readonly hint: string;
141
+ readonly detail: ImageErrorDetailFor<C>;
142
+ constructor(detail: ImageErrorDetailFor<C>) {
143
+ const code = detail.code;
144
+ const expected = IMAGE_ERROR_EXPECTED_LOCAL[code] ?? '';
145
+ const hint = IMAGE_ERROR_HINTS[code];
146
+ super(`[ImageError ${code}] expected: ${expected}; hint: ${hint}`);
147
+ this.name = 'ImageError';
148
+ this.code = code;
149
+ this.expected = expected;
150
+ this.hint = hint;
151
+ this.detail = detail;
152
+ }
153
+ }
154
+
155
+ function makeImageError<C extends ImageErrorCode>(
156
+ detail: ImageErrorDetailFor<C>,
157
+ ): ImageErrorFor<C> {
158
+ return new RuntimeImageError<C>(detail);
159
+ }
160
+
161
+ // Extended device shape adding `queue.writeTexture` on top of
162
+ // `MipmapBlitDevice` (the mipmap-generator only needs the encoder + queue
163
+ // submit surface; uploadTexture additionally writes pixel bytes via
164
+ // `queue.writeTexture` -- spec anchor: WebGPU 26.6.4.4).
165
+ type MipmapBlitDeviceWithWriteTexture = MipmapBlitDevice & {
166
+ readonly queue: MipmapBlitDevice['queue'] & {
167
+ // biome-ignore lint/suspicious/noExplicitAny: shim accepts any descriptor
168
+ writeTexture(dst: any, data: any, layout: any, size: any): Result<void, any>;
169
+ };
170
+ };
171
+
172
+ // Extended device shape adding `createBuffer` + `queue.writeBuffer` on top of
173
+ // `MipmapBlitDevice` for the user-mesh GPU upload path.
174
+ type MipmapBlitDeviceWithBuffer = MipmapBlitDevice & {
175
+ // biome-ignore lint/suspicious/noExplicitAny: shim accepts any descriptor
176
+ createBuffer(desc: any): Result<any, any>;
177
+ readonly queue: MipmapBlitDevice['queue'] & {
178
+ // biome-ignore lint/suspicious/noExplicitAny: shim accepts any descriptor
179
+ writeBuffer(buffer: any, offset: number, data: any): Result<void, any>;
180
+ };
181
+ };
182
+
183
+ /** Cube-POD register-relay injected by the wire layer (D-3). */
184
+ type RegisterCube = (
185
+ world: World,
186
+ pod: EquirectAsset,
187
+ ) => Result<Handle<'EquirectAsset', 'shared'>, AssetError>;
188
+
189
+ // feat-20260612-rhi-destroy-renderer-dispose-gpu-lifecycle / M-3 / w11:
190
+ // the three handle map value types now hold GpuTexture / GpuBuffer wrappers
191
+ // (plan-strategy D-9). Views (TextureView) stay raw RHI handles -- they are
192
+ // not destroyable on their own; their lifetime is bound to the parent
193
+ // GpuTexture, which the wrapper owns. destroyAll() walks the GpuResource
194
+ // fields and forwards .destroy() to the RHI shim.
195
+ interface TextureGpuEntry {
196
+ readonly texture: GpuTexture;
197
+ /** Opaque RHI view handle; lifetime is bound to the parent texture. */
198
+ readonly view: TextureView;
199
+ }
200
+
201
+ // feat-20260630-equirect-kind-internalized-ibl-declarative-skyligh M2 / w11
202
+ // (D-3): the projection-status truth lives here (the store's cubemap map is the
203
+ // single authority — the SkylightSnapshot carries no status, D-3). `status`:
204
+ // - 'pending' — projection launched (fire-and-forget) but not complete; the
205
+ // record arm binds the white-cube fallback for this frame.
206
+ // - 'ready' — texture + cube view + 6 face views are live; bind the real
207
+ // IBL cube.
208
+ // - 'failed' — projection errored; recorded EXPLICITLY so the record arm
209
+ // stops and does NOT retry every frame (R-2 / AC-09). A failed entry has
210
+ // no GPU resources (texture/view are placeholders never bound).
211
+ // `texture`/`view`/`faceViews` are non-readonly so a 'pending' entry can be
212
+ // promoted to 'ready' in place (rebuilds the same slot). A 'failed' entry holds
213
+ // no GPU resources (`texture:null` / `view:undefined`): it exists only to mark
214
+ // the source as terminally failed so the record arm stops retrying (R-2).
215
+ interface CubemapGpuEntry {
216
+ status: 'pending' | 'ready' | 'failed';
217
+ texture: GpuTexture | null;
218
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU cubemap view (not a GpuResource)
219
+ view: any;
220
+ // biome-ignore lint/suspicious/noExplicitAny: per-face 2D views (6 faces; not GpuResources)
221
+ faceViews: readonly any[];
222
+ }
223
+
224
+ interface MeshGpuEntry {
225
+ readonly vertexBuffer: GpuBuffer;
226
+ /**
227
+ * Index buffer wrapper, or `null` for a vertex-only mesh
228
+ * (no `MeshAsset.indices`). When `null` the record stage takes the
229
+ * non-indexed `pass.draw(vertexCount)` path and never calls
230
+ * `setIndexBuffer`. Gated on `indexed` below.
231
+ */
232
+ readonly indexBuffer: GpuBuffer | null;
233
+ /**
234
+ * Allocation byte sizes for the vbo / ibo (mirrors GPUBuffer.size). Used
235
+ * by `updateMeshById` to decide reuse vs reallocation; tracked here so
236
+ * the runtime never reads `.size` off the opaque RHI handle (which is
237
+ * not on the spec-aligned RHI Buffer interface; charter §RHI form rules).
238
+ */
239
+ readonly vboBytes: number;
240
+ /** Allocation byte size for the ibo, or 0 when indexBuffer is null. */
241
+ readonly iboBytes: number;
242
+ /** Immutable geometry-owned layout projection used for all resident stride checks. */
243
+ readonly layoutProjection: VertexLayoutProjection;
244
+ readonly indexCount: number;
245
+ readonly indexFormat: 'uint16' | 'uint32';
246
+ /** Vertex count is derived from the geometry-owned projection stride. */
247
+ readonly vertexCount: number;
248
+ /** True when `MeshAsset.indices` is present (indexed draw path). */
249
+ readonly indexed: boolean;
250
+ /** Primitive topology (default 'triangle-list'). Mirrors MeshGpuHandles. */
251
+ readonly topology: PrimitiveTopology;
252
+ /**
253
+ * Submeshes from MeshAsset.submeshes, carried through to the record stage
254
+ * so per-submesh drawIndexed can iterate independently (feat-20260608 M4 / w16).
255
+ * For single-submesh meshes this is a 1-element array (byte-identical to pre-M4).
256
+ */
257
+ readonly submeshes: readonly import('@forgeax/engine-types').Submesh[];
258
+ }
259
+
260
+ function meshStrideBytes(layoutProjection: VertexLayoutProjection): number {
261
+ if (layoutProjection.arrayStride <= 0) {
262
+ throw new Error('mesh layout projection must have a positive array stride');
263
+ }
264
+ return layoutProjection.arrayStride;
265
+ }
266
+
267
+ function submeshesEqual(a: readonly Submesh[], b: readonly Submesh[]): boolean {
268
+ return (
269
+ a.length === b.length &&
270
+ a.every((left, index) => {
271
+ const right = b[index];
272
+ return (
273
+ right !== undefined &&
274
+ left.indexOffset === right.indexOffset &&
275
+ left.indexCount === right.indexCount &&
276
+ left.vertexCount === right.vertexCount &&
277
+ left.topology === right.topology &&
278
+ left.materialSlot === right.materialSlot
279
+ );
280
+ })
281
+ );
282
+ }
283
+
284
+ /**
285
+ * GPU residency store. Owns the per-handle GPU caches and the upload
286
+ * primitives that build them. Constructed once per renderer; wired with the
287
+ * GPU device via `configureGpuDevice` after `Renderer.ready` resolves.
288
+ */
289
+ export class GpuResourceStore {
290
+ /** Monotonic token for mesh GPU residency or contents changes. */
291
+ meshResidencyEpoch = 0;
292
+ /** Monotonic token for texture/sampler identities used by material bind groups. */
293
+ materialResourceEpoch = 0;
294
+ private gpuDevice: MipmapBlitDevice | undefined = undefined;
295
+ // Shader-module factory injected at `configureGpuDevice`; threaded into the
296
+ // mipmap-pipeline prewarm + the IBL precompute path. `undefined` until wired.
297
+ private asyncCreateShaderModule: MipmapShaderModuleFactory | undefined = undefined;
298
+ // Cube-POD register relay injected at `configureGpuDevice` (D-3); the store
299
+ // never imports AssetRegistry, so CPU cataloguing flows through this fn.
300
+ private registerCube: RegisterCube | undefined = undefined;
301
+ // Error registry injected by createRenderer; evict / releaseUnreferenced
302
+ // fire structured errors through this channel (feat-20260619 D-1/D-6).
303
+ private errorRegistry: RhiErrorListenerRegistry | undefined = undefined;
304
+ // Hardware-probe caps injected at `configureGpuDevice`; guards the HDR cubemap
305
+ // path (_uploadCubemapFromEquirect) when `rgba16floatRenderable` is false.
306
+ private caps: RhiCaps | undefined = undefined;
307
+
308
+ private readonly textureGpuHandles: Map<number, TextureGpuEntry> = new Map();
309
+ private readonly samplerGpuHandles: Map<number, Sampler> = new Map();
310
+ private readonly cubemapGpuHandles: Map<number, CubemapGpuEntry> = new Map();
311
+ // Maps source EquirectAsset handle id -> minted cubemap handle so the same
312
+ // equirect source always resolves to the same cubemap (idempotent, A2).
313
+ private readonly cubemapIdempotentMap: Map<number, Handle<'EquirectAsset', 'shared'>> = new Map();
314
+ private readonly meshGpuHandles: Map<number, MeshGpuEntry> = new Map();
315
+
316
+ /**
317
+ * feat-20260723-cross-world-gpu-cache-collision: compose a cache key from
318
+ * the raw handle slot and the worldId so two worlds that independently
319
+ * allocate assets at the same slot number never collide in the GPU store.
320
+ * worldId=0 produces the bare slot (backward compat with single-world path).
321
+ */
322
+ private worldKey(slot: number, worldId: number): number {
323
+ return worldId === 0 ? slot : worldId * 0x1000000 + slot;
324
+ }
325
+
326
+ /**
327
+ * Wire the GPU device, shader-module factory, and cube-POD register relay.
328
+ * Called once by createRenderer after `Renderer.ready` resolves. This
329
+ * performs NO replay of CPU asset state:
330
+ * the pull model builds resources lazily at first `ensureResident` access.
331
+ */
332
+ configureGpuDevice(
333
+ device: MipmapBlitDevice,
334
+ asyncCreateShaderModule: MipmapShaderModuleFactory | undefined,
335
+ registerCube: RegisterCube,
336
+ caps: RhiCaps,
337
+ ): void {
338
+ this.meshResidencyEpoch += 1;
339
+ this.gpuDevice = device;
340
+ this.asyncCreateShaderModule = asyncCreateShaderModule;
341
+ this.registerCube = registerCube;
342
+ this.caps = caps;
343
+ }
344
+
345
+ /**
346
+ * Wrap a raw RHI Buffer handle into a GpuBuffer. The wrapper holds a
347
+ * reference to the device so `.destroy()` forwards to
348
+ * `device.destroyBuffer(handle)` (M-3 / w11; plan-strategy D-2).
349
+ *
350
+ * Pre: `configureGpuDevice` has been called. Callers that build a buffer
351
+ * via `device.createBuffer` already gate on a wired device, so this private
352
+ * helper trusts the caller; an unwired call is a programmer error and
353
+ * surfaces as a non-null assertion rather than a structured error.
354
+ */
355
+ private wrapBuf(rawHandle: Buffer): GpuBuffer {
356
+ const device = this.gpuDevice as MipmapBlitDevice & RhiDevice;
357
+ return new GpuBuffer(device, rawHandle);
358
+ }
359
+
360
+ private destroyMeshBuffer(buffer: GpuBuffer): void {
361
+ const result = buffer.destroy();
362
+ if (!result.ok) this.errorRegistry?.fire(result.error);
363
+ }
364
+
365
+ /** Wrap a raw RHI Texture handle into a GpuTexture (mirror of wrapBuf). */
366
+ private wrapTex(rawHandle: Texture): GpuTexture {
367
+ const device = this.gpuDevice as MipmapBlitDevice & RhiDevice;
368
+ return new GpuTexture(device, rawHandle);
369
+ }
370
+
371
+ /**
372
+ * Walk the three handle maps and destroy every GpuResource, then clear
373
+ * the maps. Called from `Renderer.dispose()` (M-5) as the first step of
374
+ * the dispose chain (plan-strategy D-2: dispose chain walks
375
+ * `gpuStore.destroyAll()` → `graph.drain()` → `instanceBuffers.clear()`
376
+ * → ...).
377
+ *
378
+ * Idempotent: a second call after the maps were cleared is a no-op
379
+ * (architecture-principles §6 idempotency). Each `.destroy()` call
380
+ * routes through the RHI shim's per-handle bookkeeping, so a stray
381
+ * second-destroy on a handle the runtime did not flip to destroyed
382
+ * surfaces as the structured `'destroy-after-destroy'` error from the
383
+ * RHI shim; that error is *not* re-thrown here -- destroyAll is a
384
+ * sweep that tolerates per-handle failures so the dispose chain can
385
+ * make progress (plan-strategy D-3 / D-8).
386
+ */
387
+ destroyAll(): void {
388
+ if (this.meshGpuHandles.size > 0) this.meshResidencyEpoch += 1;
389
+ // The cubemap path registers two entries (sourceId + cubeId) sharing one
390
+ // GpuTexture wrapper, so destroyAll must dedupe on the wrapper identity
391
+ // before forwarding `.destroy()` -- otherwise the second call surfaces
392
+ // `'destroy-after-destroy'` from the RHI shim. The `isDestroyed` getter
393
+ // on the wrapper is the dedupe gate (architecture-principles §6).
394
+ const destroyTex = (gpuTex: GpuTexture): void => {
395
+ if (!gpuTex.isDestroyed) gpuTex.destroy();
396
+ };
397
+ const destroyBuf = (gpuBuf: GpuBuffer): void => {
398
+ if (!gpuBuf.isDestroyed) gpuBuf.destroy();
399
+ };
400
+
401
+ for (const entry of this.textureGpuHandles.values()) {
402
+ destroyTex(entry.texture);
403
+ }
404
+ if (this.textureGpuHandles.size > 0 || this.samplerGpuHandles.size > 0) {
405
+ this.materialResourceEpoch += 1;
406
+ }
407
+ this.textureGpuHandles.clear();
408
+ this.samplerGpuHandles.clear();
409
+
410
+ for (const entry of this.cubemapGpuHandles.values()) {
411
+ if (entry.texture !== null) destroyTex(entry.texture);
412
+ }
413
+ this.cubemapGpuHandles.clear();
414
+ this.cubemapIdempotentMap.clear();
415
+
416
+ for (const entry of this.meshGpuHandles.values()) {
417
+ destroyBuf(entry.vertexBuffer);
418
+ if (entry.indexBuffer !== null) destroyBuf(entry.indexBuffer);
419
+ }
420
+ this.meshGpuHandles.clear();
421
+ }
422
+
423
+ /**
424
+ * Set the error registry channel (wired by createRenderer). evict /
425
+ * releaseUnreferenced fire structured errors here instead of throwing -
426
+ * sweeps continue past individual failures (feat-20260619 D-1/D-6).
427
+ */
428
+ setErrorRegistry(registry: RhiErrorListenerRegistry): void {
429
+ this.errorRegistry = registry;
430
+ }
431
+
432
+ /**
433
+ * evictTexture / evictMesh / evictCubemap — per-handle evict primitives.
434
+ *
435
+ * Reuses destroyAll's isDestroyed dedup logic + cubemap wrapper
436
+ * shared-dedup (feat-20260619 D-1). Returns {freed, errors} so callers
437
+ * can consume the aggregate result (D-3). Key not present -> no-op
438
+ * returning {freed:0, errors:[]}.
439
+ */
440
+ evictTexture(
441
+ handle: Handle<'TextureAsset', 'shared'>,
442
+ worldId: number = 0,
443
+ ): { freed: number; errors: RhiError[] } {
444
+ const id = this.worldKey(handleSlot(handle), worldId);
445
+ const entry = this.textureGpuHandles.get(id);
446
+ if (entry === undefined) return { freed: 0, errors: [] };
447
+
448
+ let freed = 0;
449
+ const errors: RhiError[] = [];
450
+
451
+ if (!entry.texture.isDestroyed) {
452
+ const r = entry.texture.destroy();
453
+ if (r.ok) {
454
+ freed = 1;
455
+ } else {
456
+ errors.push(r.error);
457
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
458
+ }
459
+ }
460
+
461
+ this.textureGpuHandles.delete(id);
462
+ this.materialResourceEpoch += 1;
463
+ return { freed, errors };
464
+ }
465
+
466
+ evictMesh(
467
+ handle: Handle<'MeshAsset', 'shared'>,
468
+ worldId: number = 0,
469
+ ): { freed: number; errors: RhiError[] } {
470
+ const id = this.worldKey(handleSlot(handle), worldId);
471
+ const entry = this.meshGpuHandles.get(id);
472
+ if (entry === undefined) return { freed: 0, errors: [] };
473
+
474
+ let freed = 0;
475
+ const errors: RhiError[] = [];
476
+
477
+ const destroyBuf = (gpuBuf: GpuBuffer): void => {
478
+ if (!gpuBuf.isDestroyed) {
479
+ const r = gpuBuf.destroy();
480
+ if (r.ok) {
481
+ freed += 1;
482
+ } else {
483
+ errors.push(r.error);
484
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
485
+ }
486
+ }
487
+ };
488
+
489
+ destroyBuf(entry.vertexBuffer);
490
+ if (entry.indexBuffer !== null) destroyBuf(entry.indexBuffer);
491
+
492
+ this.meshGpuHandles.delete(id);
493
+ this.meshResidencyEpoch += 1;
494
+ return { freed: freed > 0 ? 1 : 0, errors };
495
+ }
496
+
497
+ evictCubemap(id: number): { freed: number; errors: RhiError[] } {
498
+ const entry = this.cubemapGpuHandles.get(id);
499
+ if (entry === undefined) return { freed: 0, errors: [] };
500
+
501
+ let freed = 0;
502
+ const errors: RhiError[] = [];
503
+
504
+ // cubemap wrapper shared-dedup (D-1): sourceId and cubeId may share one
505
+ // GpuTexture wrapper. The isDestroyed gate ensures the underlying RHI
506
+ // texture is destroyed at most once, even when both entries are evicted.
507
+ // A 'failed' entry holds no GPU texture (texture:null) — nothing to free.
508
+ if (entry.texture !== null && !entry.texture.isDestroyed) {
509
+ const r = entry.texture.destroy();
510
+ if (r.ok) {
511
+ freed = 1;
512
+ } else {
513
+ errors.push(r.error);
514
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
515
+ }
516
+ }
517
+
518
+ this.cubemapGpuHandles.delete(id);
519
+ return { freed, errors };
520
+ }
521
+
522
+ /**
523
+ * releaseUnreferenced — iterate the three handle maps and evict entries
524
+ * whose key is NOT in `liveSet`.
525
+ *
526
+ * Iterates Map keys (not liveSet — store has no reverse index, D-8).
527
+ * IDs in liveSet that don't exist in the store are naturally ignored.
528
+ * Empty liveSet -> full release; second call -> no-op (maps empty,
529
+ * evict primitives are key-not-present no-op).
530
+ */
531
+ releaseUnreferenced(liveSet: Set<number>): { freed: number; errors: RhiError[] } {
532
+ let freed = 0;
533
+ const errors: RhiError[] = [];
534
+ let meshResidencyChanged = false;
535
+ let materialResidencyChanged = false;
536
+
537
+ for (const key of this.textureGpuHandles.keys()) {
538
+ if (!liveSet.has(key)) {
539
+ const entry = this.textureGpuHandles.get(key);
540
+ if (entry !== undefined) {
541
+ if (!entry.texture.isDestroyed) {
542
+ const r = entry.texture.destroy();
543
+ if (r.ok) {
544
+ freed += 1;
545
+ } else {
546
+ errors.push(r.error);
547
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
548
+ }
549
+ }
550
+ this.textureGpuHandles.delete(key);
551
+ materialResidencyChanged = true;
552
+ }
553
+ }
554
+ }
555
+
556
+ for (const key of this.samplerGpuHandles.keys()) {
557
+ if (!liveSet.has(key)) {
558
+ this.samplerGpuHandles.delete(key);
559
+ materialResidencyChanged = true;
560
+ }
561
+ }
562
+
563
+ for (const key of this.cubemapGpuHandles.keys()) {
564
+ if (!liveSet.has(key)) {
565
+ const entry = this.cubemapGpuHandles.get(key);
566
+ if (entry !== undefined) {
567
+ // A 'failed' entry holds no GPU texture (texture:null) — nothing to free.
568
+ if (entry.texture !== null && !entry.texture.isDestroyed) {
569
+ const r = entry.texture.destroy();
570
+ if (r.ok) {
571
+ freed += 1;
572
+ } else {
573
+ errors.push(r.error);
574
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
575
+ }
576
+ }
577
+ this.cubemapGpuHandles.delete(key);
578
+ }
579
+ }
580
+ }
581
+
582
+ for (const key of this.meshGpuHandles.keys()) {
583
+ if (!liveSet.has(key)) {
584
+ const entry = this.meshGpuHandles.get(key);
585
+ if (entry !== undefined) {
586
+ if (!entry.vertexBuffer.isDestroyed) {
587
+ const r = entry.vertexBuffer.destroy();
588
+ if (r.ok) {
589
+ freed += 1;
590
+ } else {
591
+ errors.push(r.error);
592
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
593
+ }
594
+ }
595
+ if (entry.indexBuffer !== null && !entry.indexBuffer.isDestroyed) {
596
+ const r = entry.indexBuffer.destroy();
597
+ if (r.ok) {
598
+ freed += 1;
599
+ } else {
600
+ errors.push(r.error);
601
+ if (this.errorRegistry) this.errorRegistry.fire(r.error);
602
+ }
603
+ }
604
+ this.meshGpuHandles.delete(key);
605
+ meshResidencyChanged = true;
606
+ }
607
+ }
608
+ }
609
+
610
+ if (meshResidencyChanged) this.meshResidencyEpoch += 1;
611
+ if (materialResidencyChanged) this.materialResourceEpoch += 1;
612
+
613
+ return { freed, errors };
614
+ }
615
+
616
+ /**
617
+ * Prewarm the mipmap pipeline cache for the given texture formats (D-9).
618
+ * Called from `createRenderer.ready` (already async): builds the one-time
619
+ * mipmap shader module + per-format render pipeline into the mipmap-generator
620
+ * deviceCache so the per-texture mipmap blit at record-stage `ensureResident`
621
+ * is pure synchronous encoder work. A format absent from this list will make
622
+ * the sync `ensureResident` texture arm return a structured RhiError rather
623
+ * than lazily await a build (which would break the sync draw contract).
624
+ */
625
+ async prewarmMipmapPipeline(
626
+ device: MipmapBlitDevice,
627
+ formats: readonly GPUTextureFormat[],
628
+ ): Promise<Result<void, RhiError>> {
629
+ const factory = this.asyncCreateShaderModule;
630
+ if (factory === undefined) {
631
+ return err(
632
+ new RhiError({
633
+ code: 'rhi-not-available',
634
+ expected: 'asyncCreateShaderModule wired by configureGpuDevice before prewarm',
635
+ hint: 'call gpuStore.configureGpuDevice(device, packShaderFactory, registerCube) before prewarmMipmapPipeline',
636
+ }),
637
+ );
638
+ }
639
+ for (const format of formats) {
640
+ const res = await getOrCreateMipmapPipeline(device, format, factory);
641
+ if (!res.ok) {
642
+ return err(
643
+ new RhiError({
644
+ code: 'rhi-not-available',
645
+ expected: `mipmap pipeline for format ${format} builds during prewarm`,
646
+ hint: `prewarmMipmapPipeline failed building the mipmap pipeline for ${format}; the format may be unsupported by the device`,
647
+ }),
648
+ );
649
+ }
650
+ }
651
+ return ok(undefined);
652
+ }
653
+
654
+ /**
655
+ * Return the GpuTexture wrapper for a `Handle<TextureAsset>` if it has been
656
+ * made resident, else `undefined`.
657
+ *
658
+ * @internal — test-only seam for cow-survivor / AC-02 integration tests; not
659
+ * part of the engine's public API surface.
660
+ */
661
+ _getTextureGpuTexture(
662
+ handle: Handle<'TextureAsset', 'shared'>,
663
+ worldId: number = 0,
664
+ ): GpuTexture | undefined {
665
+ return this.textureGpuHandles.get(this.worldKey(handleSlot(handle), worldId))?.texture;
666
+ }
667
+
668
+ /**
669
+ * Return the GPU texture-view for a `Handle<TextureAsset>` if it has been
670
+ * made resident, else `undefined`.
671
+ */
672
+ getTextureGpuView(
673
+ handle: Handle<'TextureAsset', 'shared'>,
674
+ worldId: number = 0,
675
+ ): TextureView | undefined {
676
+ return this.textureGpuHandles.get(this.worldKey(handleSlot(handle), worldId))?.view;
677
+ }
678
+
679
+ /**
680
+ * Lazily materialise and cache a sampler descriptor for a material texture.
681
+ * Samplers are opaque, non-destroyable RHI handles, so disposal only drops
682
+ * this store's cache and lets the device own their lifetime.
683
+ */
684
+ ensureSamplerResident(
685
+ handle: Handle<'SamplerAsset', 'shared'>,
686
+ pod: SamplerAsset,
687
+ worldId: number = 0,
688
+ ): Result<Sampler, RhiError> {
689
+ const key = this.worldKey(handleSlot(handle), worldId);
690
+ const existing = this.samplerGpuHandles.get(key);
691
+ if (existing !== undefined) return ok(existing);
692
+ const device = this.gpuDevice as (MipmapBlitDevice & RhiDevice) | undefined;
693
+ if (device === undefined) {
694
+ return err(
695
+ new RhiError({
696
+ code: 'rhi-not-available',
697
+ expected: 'GPU device configured before SamplerAsset residency',
698
+ hint: 'call gpuStore.configureGpuDevice before drawing a material with a sampler',
699
+ }),
700
+ );
701
+ }
702
+ const { kind: _kind, ...descriptor } = pod;
703
+ const created = device.createSampler(descriptor);
704
+ if (!created.ok) return created;
705
+ this.samplerGpuHandles.set(key, created.value);
706
+ this.materialResourceEpoch += 1;
707
+ return created;
708
+ }
709
+
710
+ /**
711
+ * Return the GpuTexture wrapper for the cubemap, or `undefined` if not
712
+ * uploaded yet. Consumers that need the raw RHI Texture handle (e.g.
713
+ * `device.createTextureView` arguments) read `.handle` on the wrapper;
714
+ * `.destroy()` routes through the destroy chain (M-3 / w11).
715
+ */
716
+ getCubemapGpuTexture(handle: Handle<'EquirectAsset', 'shared'>): GpuTexture | undefined {
717
+ // A 'failed' entry has texture:null; normalise to undefined (not resident).
718
+ return this.cubemapGpuHandles.get(handleSlot(handle))?.texture ?? undefined;
719
+ }
720
+
721
+ /** Return the full-cube texture view, or `undefined` if not uploaded yet. */
722
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU texture view
723
+ getCubemapGpuView(handle: Handle<'EquirectAsset', 'shared'>): any | undefined {
724
+ return this.cubemapGpuHandles.get(handleSlot(handle))?.view;
725
+ }
726
+
727
+ /** Return per-face 2D views (6 faces), or `undefined` if not uploaded yet. */
728
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU texture views
729
+ getCubemapFaceViews(handle: Handle<'EquirectAsset', 'shared'>): readonly any[] | undefined {
730
+ return this.cubemapGpuHandles.get(handleSlot(handle))?.faceViews;
731
+ }
732
+
733
+ /**
734
+ * Query the projection status for an equirect source handle (D-3 SSOT: the
735
+ * store's CubemapGpuEntry is the single authority). Returns `undefined` when
736
+ * no projection has been launched for this source yet (the record arm reads
737
+ * this to decide whether to fire the lazy projection; feat-20260630 M3 / w18):
738
+ * - undefined -> no entry: caller may launch projection (fire-and-forget)
739
+ * - 'pending' -> projection launched, not complete: bind white-cube fallback
740
+ * - 'ready' -> projected cube + IBL views live: bind real IBL
741
+ * - 'failed' -> projection errored: bind white fallback, do NOT retry (R-2)
742
+ */
743
+ getCubemapStatus(
744
+ handle: Handle<'EquirectAsset', 'shared'>,
745
+ ): 'pending' | 'ready' | 'failed' | undefined {
746
+ return this.cubemapGpuHandles.get(handleSlot(handle))?.status;
747
+ }
748
+
749
+ /**
750
+ * Return the GPU vertex / index buffer handles + index count for a
751
+ * `Handle<MeshAsset>` if resident, else `undefined`. Consumers treat this
752
+ * as the canonical "mesh asset has GPU residency" probe.
753
+ */
754
+ getMeshGpuHandles(
755
+ handle: Handle<'MeshAsset', 'shared'>,
756
+ worldId: number = 0,
757
+ ): MeshGpuEntry | undefined {
758
+ return this.meshGpuHandles.get(this.worldKey(handleSlot(handle), worldId));
759
+ }
760
+
761
+ /**
762
+ * Pull-model residency: build the GPU resource for `handle` from the
763
+ * caller-provided POD on a miss, return the cached handles on a hit (D-2).
764
+ *
765
+ * - mesh POD -> synchronous vertex / index buffer upload (mirrors the
766
+ * pre-extraction `uploadMeshById`).
767
+ * - texture POD -> synchronous texture upload + mipmap blit (D-9). The
768
+ * mipmap pipeline MUST have been prewarmed via `prewarmMipmapPipeline`;
769
+ * an un-prewarmed format returns a structured RhiError (never awaits).
770
+ *
771
+ * Cubemap is NOT routed here -- it is an eager user call
772
+ * (`_uploadCubemapFromEquirect`). Builtin meshes are NOT routed here either
773
+ * (createRenderer step-3 owns them; D-1).
774
+ */
775
+ ensureResident(
776
+ handle: Handle<'MeshAsset', 'shared'> | Handle<'TextureAsset', 'shared'>,
777
+ pod: TypesMeshAsset | TextureAsset,
778
+ worldId: number = 0,
779
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU handle entry union
780
+ ): Result<any, RhiError | AssetError | ImageError> {
781
+ const id = handleSlot(handle);
782
+ // Hit: O(1) cache lookup, never re-projects (AC-09 -- deriveRenderData*
783
+ // runs only on a miss). The miss arms below dispatch on `pod.kind` with NO
784
+ // default: only the two GPU-resource kinds reachable here (mesh / texture)
785
+ // have arms, so a third reachable kind would surface as a `tsc -b`
786
+ // exhaustiveness error at the switch rather than a silent fallthrough
787
+ // (AC-06; the cube-texture kind is the eager `_uploadCubemapFromEquirect`
788
+ // path, not routed here).
789
+ switch (pod.kind) {
790
+ case 'mesh': {
791
+ const key = this.worldKey(id, worldId);
792
+ const existing = this.meshGpuHandles.get(key);
793
+ if (existing !== undefined) return ok(existing);
794
+ const projected = deriveRenderDataMesh(pod);
795
+ if (!projected.ok) return projected;
796
+ return this.uploadMeshById(key, pod, projected.value);
797
+ }
798
+ case 'texture': {
799
+ const texKey = this.worldKey(id, worldId);
800
+ const existing = this.textureGpuHandles.get(texKey);
801
+ if (existing !== undefined) return ok(existing);
802
+ const projected = deriveRenderDataTexture(pod);
803
+ if (!projected.ok) return projected;
804
+ const decoded: DecodedImage = decodedFromTexture(pod);
805
+ return this.uploadTextureSync(
806
+ handle as Handle<'TextureAsset', 'shared'>,
807
+ pod,
808
+ decoded,
809
+ projected.value,
810
+ worldId,
811
+ );
812
+ }
813
+ }
814
+ }
815
+
816
+ /**
817
+ * Eager public surface: upload decoded image bytes into a GPU texture and
818
+ * cache (texture + view) under the handle. The TextureAsset POD supplies the
819
+ * GPU format (D-2: caller provides POD, store never reaches a registry); the
820
+ * DecodedImage supplies the pixel bytes + colorSpace. Retains the async
821
+ * signature so callers that have not prewarmed can drive a mipmap build here
822
+ * (the one async source).
823
+ */
824
+ async uploadTexture(
825
+ handle: Handle<'TextureAsset', 'shared'>,
826
+ pod: TextureAsset,
827
+ decoded: DecodedImage,
828
+ worldId: number = 0,
829
+ ): Promise<Result<void, AssetError | ImageError | RhiError>> {
830
+ const device = this.gpuDevice;
831
+ const projected = deriveRenderDataTexture(pod);
832
+ if (!projected.ok) return projected;
833
+ const prepared = this.prepareTextureUpload(handle, pod, decoded, projected.value);
834
+ if (!prepared.ok) return prepared;
835
+ if (device === undefined) return ok(undefined);
836
+ const { tex, levels, gpuTexture } = prepared.value;
837
+ const cacheKey = this.worldKey(handleSlot(handle), worldId);
838
+ if (gpuTexture === undefined) return ok(undefined);
839
+
840
+ if (!projected.value.compressed && decoded.mipmap === true && levels > 1) {
841
+ const factory = this.asyncCreateShaderModule;
842
+ if (factory === undefined) {
843
+ return err(
844
+ new RhiError({
845
+ code: 'rhi-not-available',
846
+ expected: 'asyncCreateShaderModule wired by configureGpuDevice',
847
+ hint: 'GpuResourceStore.uploadTexture mipmap branch needs a shader-module factory; rhi-webgpu / rhi-wgpu shims expose it via pack.createShaderModule. Explicit-rhi instances must surface the factory on the RhiInstance.',
848
+ }),
849
+ );
850
+ }
851
+ const pipelineRes = await getOrCreateMipmapPipeline(device, tex.format, factory);
852
+ if (!pipelineRes.ok) {
853
+ return err(
854
+ new RhiError({
855
+ code: 'rhi-not-available',
856
+ expected: `mipmap pipeline for format ${tex.format} builds`,
857
+ hint: 'GpuResourceStore.uploadTexture could not build the mipmap pipeline',
858
+ }),
859
+ );
860
+ }
861
+ const blitRes = blitMipmapsSync(device, gpuTexture, {
862
+ format: tex.format,
863
+ width: tex.width,
864
+ height: tex.height,
865
+ levels,
866
+ });
867
+ if (!blitRes.ok) return blitRes as Result<void, RhiError>;
868
+ }
869
+
870
+ const viewRes = device.createTextureView(gpuTexture, {
871
+ label: `texture-view-${cacheKey}`,
872
+ dimension: '2d',
873
+ });
874
+ if (!viewRes.ok) return viewRes;
875
+ const previous = this.textureGpuHandles.get(cacheKey);
876
+ const next = {
877
+ texture: this.wrapTex(gpuTexture),
878
+ view: viewRes.value,
879
+ };
880
+ this.textureGpuHandles.set(cacheKey, next);
881
+ this.materialResourceEpoch += 1;
882
+ if (
883
+ previous !== undefined &&
884
+ previous.texture !== next.texture &&
885
+ !previous.texture.isDestroyed
886
+ ) {
887
+ previous.texture.destroy();
888
+ }
889
+ return ok(undefined);
890
+ }
891
+
892
+ /**
893
+ * Synchronous texture upload used by `ensureResident` (D-9). Identical to
894
+ * `uploadTexture` except the mipmap pipeline is read from the prewarmed
895
+ * cache via the synchronous `blitMipmapsSync` -- an un-prewarmed format
896
+ * returns a structured RhiError instead of awaiting a build.
897
+ */
898
+ private uploadTextureSync(
899
+ handle: Handle<'TextureAsset', 'shared'>,
900
+ pod: TextureAsset,
901
+ decoded: DecodedImage,
902
+ renderData: TextureRenderData,
903
+ worldId: number = 0,
904
+ ): Result<TextureGpuEntry, AssetError | ImageError | RhiError> {
905
+ const device = this.gpuDevice;
906
+ const prepared = this.prepareTextureUpload(handle, pod, decoded, renderData);
907
+ if (!prepared.ok) return prepared;
908
+ if (device === undefined || prepared.value.gpuTexture === undefined) {
909
+ return err(
910
+ new RhiError({
911
+ code: 'rhi-not-available',
912
+ expected: 'GpuResourceStore.configureGpuDevice wired before ensureResident',
913
+ hint: 'a texture ensureResident ran before the GPU device was wired; call gpuStore.configureGpuDevice in createRenderer',
914
+ }),
915
+ );
916
+ }
917
+ const { tex, levels, gpuTexture } = prepared.value;
918
+ const cacheKey = this.worldKey(handleSlot(handle), worldId);
919
+
920
+ if (!renderData.compressed && decoded.mipmap === true && levels > 1) {
921
+ const blitRes = blitMipmapsSync(device, gpuTexture, {
922
+ format: tex.format,
923
+ width: tex.width,
924
+ height: tex.height,
925
+ levels,
926
+ });
927
+ if (!blitRes.ok) return blitRes as Result<TextureGpuEntry, RhiError>;
928
+ }
929
+
930
+ const viewRes = device.createTextureView(gpuTexture, {
931
+ label: `texture-view-${cacheKey}`,
932
+ dimension: '2d',
933
+ });
934
+ if (!viewRes.ok) return viewRes;
935
+ const entry: TextureGpuEntry = { texture: this.wrapTex(gpuTexture), view: viewRes.value };
936
+ const previous = this.textureGpuHandles.get(cacheKey);
937
+ this.textureGpuHandles.set(cacheKey, entry);
938
+ this.materialResourceEpoch += 1;
939
+ if (
940
+ previous !== undefined &&
941
+ previous.texture !== entry.texture &&
942
+ !previous.texture.isDestroyed
943
+ ) {
944
+ previous.texture.destroy();
945
+ }
946
+ return ok(entry);
947
+ }
948
+
949
+ /**
950
+ * Shared texture-upload prelude: format / colorSpace consistency assertion,
951
+ * GPU texture allocation + writeTexture. Returns `gpuTexture: undefined`
952
+ * (with ok) when no device is wired (deferred path).
953
+ */
954
+ private prepareTextureUpload(
955
+ handle: Handle<'TextureAsset', 'shared'>,
956
+ pod: TextureAsset,
957
+ decoded: DecodedImage,
958
+ renderData: TextureRenderData,
959
+ ): Result<
960
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU texture handle
961
+ { id: number; tex: TextureAsset; levels: number; gpuTexture: any | undefined },
962
+ AssetError | ImageError | RhiError
963
+ > {
964
+ const id = handleSlot(handle);
965
+ // The store does not hold the registry (D-2); the caller-provided POD is
966
+ // the GPU-format SSOT and `renderData` is its projection (format / usage /
967
+ // mipLevelCount). `decoded` supplies the pixel bytes + colorSpace; the
968
+ // assertion below guards the actual upload-source colorSpace against the
969
+ // projected format (the projection already checked the POD's own colorSpace).
970
+ const tex = pod;
971
+ const levels = renderData.mipLevelCount;
972
+
973
+ const formatExpected: 'srgb' | 'linear' = renderData.format.endsWith('-srgb')
974
+ ? 'srgb'
975
+ : 'linear';
976
+ if (decoded.colorSpace !== formatExpected) {
977
+ const detail: ImageErrorDetailFor<'image-format-unsupported'> = {
978
+ code: 'image-format-unsupported',
979
+ actualMime: decoded.mime,
980
+ formatColorSpaceConflict: {
981
+ format: renderData.format,
982
+ colorSpace: decoded.colorSpace,
983
+ expected: formatExpected,
984
+ },
985
+ };
986
+ return err(makeImageError(detail));
987
+ }
988
+
989
+ const device = this.gpuDevice;
990
+ if (device === undefined) {
991
+ return ok({ id, tex, levels, gpuTexture: undefined });
992
+ }
993
+
994
+ // WebGL2/wgpu exposes texture limits that are lower than many source
995
+ // images (for example the 2085px LearnOpenGL Mars texture). Reject the
996
+ // upload before allocating a handle; binding a texture that the backend
997
+ // accepted syntactically but cannot use later surfaces only as a generic
998
+ // invalid-bind-group submit error.
999
+ const maxDimension =
1000
+ (device as unknown as { readonly limits?: { readonly maxTextureDimension2D?: number } })
1001
+ .limits?.maxTextureDimension2D ?? 16_384;
1002
+ if (tex.width > maxDimension || tex.height > maxDimension) {
1003
+ return err(
1004
+ makeImageError({
1005
+ code: 'image-dimension-out-of-bounds',
1006
+ requested: { width: tex.width, height: tex.height },
1007
+ limit: maxDimension,
1008
+ }),
1009
+ );
1010
+ }
1011
+
1012
+ const createTexRes = device.createTexture({
1013
+ label: `texture-${id}`,
1014
+ size: {
1015
+ width: renderData.physicalExtent.width,
1016
+ height: renderData.physicalExtent.height,
1017
+ depthOrArrayLayers: 1,
1018
+ },
1019
+ mipLevelCount: levels,
1020
+ sampleCount: 1,
1021
+ dimension: '2d',
1022
+ format: renderData.format,
1023
+ usage: renderData.usage,
1024
+ viewFormats: [],
1025
+ });
1026
+ if (!createTexRes.ok) return createTexRes;
1027
+ const gpuTexture = createTexRes.value;
1028
+ const queue = (device as unknown as MipmapBlitDeviceWithWriteTexture).queue;
1029
+
1030
+ if (renderData.compressed) {
1031
+ // feat-20260707 M5 / w36 (AC-08): block-compressed textures carry their
1032
+ // mip chain in `data` (offline-baked -- the GPU cannot generate compressed
1033
+ // mips). Upload each level with its own block-padded bytesPerRow /
1034
+ // rowsPerImage and mip-major byte offset (deriveMipUploadLayout, SSOT
1035
+ // block math). Full-subresource copies retain their logical size, including
1036
+ // non-block-aligned dimensions. queue.writeTexture avoids the 256 B
1037
+ // copyBufferToTexture alignment trap.
1038
+ const layout = deriveMipUploadLayout(renderData.format, tex.width, tex.height, levels);
1039
+ for (const lvl of layout) {
1040
+ const slice = decoded.bytes.subarray(lvl.byteOffset, lvl.byteOffset + lvl.byteLength);
1041
+ const writeRes = queue.writeTexture(
1042
+ { texture: gpuTexture, mipLevel: lvl.level, origin: { x: 0, y: 0, z: 0 } },
1043
+ slice,
1044
+ { offset: 0, bytesPerRow: lvl.bytesPerRow, rowsPerImage: lvl.rowsPerImage },
1045
+ { width: lvl.copyWidth, height: lvl.copyHeight, depthOrArrayLayers: 1 },
1046
+ );
1047
+ if (!writeRes.ok) return writeRes;
1048
+ }
1049
+ return ok({ id, tex, levels, gpuTexture });
1050
+ }
1051
+
1052
+ // Uncompressed base-mip write; higher mips (when mipmap) are GPU-generated by
1053
+ // the caller's blit pass. rowsPerImage is the pixel height for linear RGBA.
1054
+ const bytesPerRow = renderData.bytesPerRow;
1055
+ const writeTextureRes = queue.writeTexture(
1056
+ { texture: gpuTexture, mipLevel: 0, origin: { x: 0, y: 0, z: 0 } },
1057
+ decoded.bytes,
1058
+ { offset: 0, bytesPerRow, rowsPerImage: tex.height },
1059
+ { width: tex.width, height: tex.height, depthOrArrayLayers: 1 },
1060
+ );
1061
+ if (!writeTextureRes.ok) return writeTextureRes;
1062
+
1063
+ return ok({ id, tex, levels, gpuTexture });
1064
+ }
1065
+
1066
+ /**
1067
+ * Project an equirectangular HDR `EquirectAsset` into a GPU cubemap + IBL
1068
+ * precompute. NOT part of the `ensureResident` pull path.
1069
+ *
1070
+ * @internal — feat-20260630 D-3 / F-9: the cubemap projection is engine
1071
+ * internals, not a user surface. AI users declare `Skylight{equirect}` and
1072
+ * the render-system record arm (same package) drives this method per-frame;
1073
+ * the `_` prefix + `@internal` mark it package-internal (lint:internal gate)
1074
+ * so it never appears as a user-facing call. (A cross-file `private` is not
1075
+ * reachable by the record arm; package-internal is the correct visibility.)
1076
+ *
1077
+ * Idempotent: a second call with the same source handle returns the cached
1078
+ * cubemap handle (no second GPU texture). The minted cubemap handle is an
1079
+ * `EquirectAsset` shared ref catalogued via the injected `registerCube` relay
1080
+ * (D-3); the store never imports AssetRegistry.
1081
+ *
1082
+ * Status (D-3): every entry written carries `status`. A failed projection
1083
+ * records `status:'failed'` EXPLICITLY (R-2 / AC-09) so the caller never
1084
+ * retries by inferring "no entry => try again".
1085
+ */
1086
+ async _uploadCubemapFromEquirect(
1087
+ world: World,
1088
+ sourceHandle: Handle<'EquirectAsset', 'shared'>,
1089
+ sourcePod: EquirectAsset,
1090
+ ): Promise<Result<Handle<'EquirectAsset', 'shared'>, AssetError | RhiError>> {
1091
+ const sourceId = handleSlot(sourceHandle);
1092
+
1093
+ const existing = this.cubemapIdempotentMap.get(sourceId);
1094
+ if (existing !== undefined) {
1095
+ return ok(existing);
1096
+ }
1097
+
1098
+ // R-2 / AC-09: a previously-failed projection is recorded EXPLICITLY as a
1099
+ // 'failed' entry. Short-circuit here so the record arm never retries the
1100
+ // upload every frame (the missing-key inference would loop forever).
1101
+ if (this.cubemapGpuHandles.get(sourceId)?.status === 'failed') {
1102
+ return err(
1103
+ new RhiError({
1104
+ code: 'feature-not-enabled',
1105
+ expected: 'a prior cubemap projection for this equirect source did not fail',
1106
+ hint: 'this equirect source already failed projection; the record arm must not retry (R-2). Inspect the original failure on the error channel',
1107
+ }),
1108
+ );
1109
+ }
1110
+
1111
+ // feat-20260630 M3 / w18: a projection already in flight is marked
1112
+ // 'pending' synchronously below (before the first await). A re-entry while
1113
+ // pending short-circuits so the fire-and-forget record arm launches the
1114
+ // async projection exactly once per source (D-4 idempotent; the record arm
1115
+ // calls this every frame until status flips to ready/failed). The pending
1116
+ // entry holds no live GPU resources yet; the record arm binds the white
1117
+ // fallback while pending.
1118
+ if (this.cubemapGpuHandles.get(sourceId)?.status === 'pending') {
1119
+ return ok(sourceHandle);
1120
+ }
1121
+
1122
+ // Record a failed projection explicitly so a re-query short-circuits and the
1123
+ // record arm never retries every frame (R-2 / AC-09). The placeholder
1124
+ // texture wrapper is never bound (a 'failed' entry has no live GPU view).
1125
+ const recordFailed = <E>(error: E): Result<never, E> => {
1126
+ this.cubemapGpuHandles.set(sourceId, {
1127
+ status: 'failed',
1128
+ texture: null,
1129
+ view: undefined,
1130
+ faceViews: [],
1131
+ });
1132
+ return err(error);
1133
+ };
1134
+
1135
+ const registerCube = this.registerCube;
1136
+ if (registerCube === undefined) {
1137
+ return recordFailed(
1138
+ makeAssetError({
1139
+ code: 'asset-not-found',
1140
+ expected: 'GpuResourceStore.configureGpuDevice wired with registerCube',
1141
+ hint: 'call gpuStore.configureGpuDevice(device, factory, registerCube) before _uploadCubemapFromEquirect',
1142
+ }),
1143
+ );
1144
+ }
1145
+
1146
+ if (sourcePod.kind !== 'equirect') {
1147
+ return recordFailed(
1148
+ makeAssetError({
1149
+ code: 'asset-not-found',
1150
+ expected: `source POD for handle id ${sourceId} is an EquirectAsset`,
1151
+ hint: ASSET_ERROR_HINTS['asset-not-found'],
1152
+ }),
1153
+ );
1154
+ }
1155
+
1156
+ // feat-20260630 M3 / w18: mark the source 'pending' SYNCHRONOUSLY (this runs
1157
+ // before the first `await` below, so the fire-and-forget record arm that
1158
+ // never awaits still observes the pending entry on the next frame's
1159
+ // getCubemapStatus). All sync fail-fast gates (idempotent / failed / pending
1160
+ // / registerCube / caps / kind) have passed, so the projection is committed;
1161
+ // a re-entry while async work is in flight short-circuits on the 'pending'
1162
+ // guard above. The entry holds no live GPU resources yet (record binds the
1163
+ // white fallback while pending); the texture/views are filled in below when
1164
+ // the projection completes (status flips to 'ready'), or replaced by a
1165
+ // 'failed' entry via recordFailed if any later step errors.
1166
+ this.cubemapGpuHandles.set(sourceId, {
1167
+ status: 'pending',
1168
+ texture: null,
1169
+ view: undefined,
1170
+ faceViews: [],
1171
+ });
1172
+
1173
+ // The cubemap projection + IBL precompute consume a 2D-image view of the
1174
+ // source. EquirectAsset mirrors the TextureAsset 2D surface (width / height
1175
+ // / format / data / colorSpace) but has no CPU mip chain, so the derived
1176
+ // texture view declares `mipmap:false` (the IBL prefilter mip chain is a
1177
+ // GPU-side pass, not a CPU-authored level set).
1178
+ const sourceTex: TextureAsset = {
1179
+ kind: 'texture',
1180
+ width: sourcePod.width,
1181
+ height: sourcePod.height,
1182
+ format: sourcePod.format,
1183
+ data: sourcePod.data,
1184
+ colorSpace: sourcePod.colorSpace,
1185
+ mipmap: false,
1186
+ };
1187
+
1188
+ // Project the equirect source POD into the cubemap descriptor (D-5): the
1189
+ // asset-semantic decisions (format / colorSpace validation, square cube
1190
+ // face size, rgba32f->rgba16f narrowing) live in the pure projection; the
1191
+ // resource build (texture / views / IBL precompute) + the byte conversion
1192
+ // stay here in the store.
1193
+ const projected: CubeRenderData | undefined = (() => {
1194
+ const p = deriveRenderDataCubemap(sourceTex);
1195
+ return p.ok ? p.value : undefined;
1196
+ })();
1197
+ if (projected === undefined) {
1198
+ return recordFailed(
1199
+ makeAssetError({
1200
+ code: 'invalid-source-format',
1201
+ expected: "format 'rgba16float' or 'rgba32float' with colorSpace 'linear'",
1202
+ hint: ASSET_ERROR_HINTS['invalid-source-format'],
1203
+ }),
1204
+ );
1205
+ }
1206
+
1207
+ const tex: TextureAsset = projected.needsHalfConversion
1208
+ ? {
1209
+ kind: 'texture',
1210
+ width: sourceTex.width,
1211
+ height: sourceTex.height,
1212
+ format: projected.outputFormat,
1213
+ data: halfFloat.f32ToF16Bytes(
1214
+ sourceTex.data instanceof Uint8ClampedArray
1215
+ ? new Uint8Array(
1216
+ sourceTex.data.buffer,
1217
+ sourceTex.data.byteOffset,
1218
+ sourceTex.data.byteLength,
1219
+ )
1220
+ : sourceTex.data,
1221
+ ),
1222
+ colorSpace: 'linear',
1223
+ mipmap: false,
1224
+ }
1225
+ : sourceTex;
1226
+
1227
+ const cubeFaceSize = projected.cubeFaceSize;
1228
+ // The source equirect stays float for filtering, but WebGL2 cannot render
1229
+ // rgba16float attachments. Downlevel only the precompute outputs to the
1230
+ // universally renderable rgba8 path; the same format is threaded through
1231
+ // the cubemap and all three IBL side textures by IblPipelineCache.
1232
+ const outputFormat = this.caps?.rgba16floatRenderable === false ? 'rgba8unorm' : tex.format;
1233
+
1234
+ // Lazy projection runs from the record arm, where the device is always
1235
+ // wired (research R-5). The device-not-wired queue + placeholder cube path
1236
+ // is removed (D-7); a missing device here is a fail-fast, not a queue.
1237
+ const device = this.gpuDevice;
1238
+ if (device === undefined) {
1239
+ return recordFailed(
1240
+ new RhiError({
1241
+ code: 'rhi-not-available',
1242
+ expected: 'GpuResourceStore.configureGpuDevice wired before cubemap projection',
1243
+ hint: 'a cubemap projection ran before the GPU device was wired; the record arm projects only after the device is configured',
1244
+ }),
1245
+ );
1246
+ }
1247
+
1248
+ // Usage flags for the small equirect helper texture (sampled source for the
1249
+ // IBL precompute pass); the cube texture's usage comes from the projection.
1250
+ // biome-ignore lint/suspicious/noExplicitAny: union of shim/raw return shapes
1251
+ const unwrap = (r: any): any => {
1252
+ if (r === null || r === undefined) return undefined;
1253
+ if (typeof r === 'object' && 'ok' in r) return r.ok ? r.value : undefined;
1254
+ return r;
1255
+ };
1256
+ // biome-ignore lint/suspicious/noExplicitAny: shim/raw device split
1257
+ const makeTextureView = (dev: any, texture: any, desc: any): any => {
1258
+ if (typeof dev.createTextureView === 'function') {
1259
+ const u = unwrap(dev.createTextureView(texture, desc));
1260
+ if (u !== undefined) return u;
1261
+ }
1262
+ if (texture !== null && texture !== undefined && typeof texture.createView === 'function') {
1263
+ try {
1264
+ return texture.createView(desc);
1265
+ } catch {
1266
+ return undefined;
1267
+ }
1268
+ }
1269
+ return undefined;
1270
+ };
1271
+
1272
+ const gpuTextureRet = device.createTexture({
1273
+ label: `cubemap-${sourceId}`,
1274
+ size: { width: cubeFaceSize, height: cubeFaceSize, depthOrArrayLayers: 6 },
1275
+ mipLevelCount: 1,
1276
+ sampleCount: 1,
1277
+ dimension: '2d',
1278
+ format: outputFormat,
1279
+ usage: projected.cubeUsage,
1280
+ viewFormats: [],
1281
+ });
1282
+ const gpuTexture = unwrap(gpuTextureRet);
1283
+ if (gpuTexture === undefined) {
1284
+ return recordFailed(
1285
+ makeAssetError({
1286
+ code: 'ibl-precompute-not-dispatched',
1287
+ expected: `device.createTexture cubemap-${sourceId} to return a valid texture`,
1288
+ hint: ASSET_ERROR_HINTS['ibl-precompute-not-dispatched'],
1289
+ }),
1290
+ );
1291
+ }
1292
+
1293
+ const cubeView = makeTextureView(device, gpuTexture, {
1294
+ label: `cubemap-view-${sourceId}`,
1295
+ dimension: 'cube',
1296
+ arrayLayerCount: 6,
1297
+ });
1298
+ if (cubeView === undefined) {
1299
+ return recordFailed(
1300
+ makeAssetError({
1301
+ code: 'ibl-precompute-not-dispatched',
1302
+ expected: `device.createTextureView cubemap-view-${sourceId} to return a valid view`,
1303
+ hint: ASSET_ERROR_HINTS['ibl-precompute-not-dispatched'],
1304
+ }),
1305
+ );
1306
+ }
1307
+
1308
+ // biome-ignore lint/suspicious/noExplicitAny: opaque GPU texture views
1309
+ const faceViews: any[] = [];
1310
+ for (let face = 0; face < 6; face++) {
1311
+ const fv = makeTextureView(device, gpuTexture, {
1312
+ label: `cubemap-face-${sourceId}-${face}`,
1313
+ dimension: '2d',
1314
+ baseArrayLayer: face,
1315
+ arrayLayerCount: 1,
1316
+ });
1317
+ if (fv === undefined) {
1318
+ return recordFailed(
1319
+ makeAssetError({
1320
+ code: 'ibl-precompute-not-dispatched',
1321
+ expected: `device.createTextureView cubemap-face-${sourceId}-${face} to return a valid view`,
1322
+ hint: ASSET_ERROR_HINTS['ibl-precompute-not-dispatched'],
1323
+ }),
1324
+ );
1325
+ }
1326
+ faceViews.push(fv);
1327
+ }
1328
+
1329
+ // M-3 / w11: a single GpuTexture wrapper is shared between sourceId
1330
+ // and cubeId entries (the underlying RHI handle is the same physical
1331
+ // texture). destroyAll() walks each entry, so attempting to destroy
1332
+ // twice via two wrappers would surface 'destroy-after-destroy' on
1333
+ // the second pass; sharing one wrapper keeps the destroy chain
1334
+ // surfacing exactly one destroy call per physical resource.
1335
+ const gpuTextureWrapper = this.wrapTex(gpuTexture);
1336
+
1337
+ this.cubemapGpuHandles.set(sourceId, {
1338
+ status: 'ready',
1339
+ texture: gpuTextureWrapper,
1340
+ view: cubeView,
1341
+ faceViews,
1342
+ });
1343
+
1344
+ // The minted cubemap handle is a synthetic shared ref (identity token for
1345
+ // the GPU cube residency); its POD is an EquirectAsset placeholder matching
1346
+ // the projected dimensions/format (D-3: the retired cube-texture asset kind
1347
+ // is gone; the relay mints an EquirectAsset shared ref instead).
1348
+ const cubeAsset: EquirectAsset = {
1349
+ kind: 'equirect',
1350
+ width: cubeFaceSize,
1351
+ height: cubeFaceSize,
1352
+ format: tex.format,
1353
+ data: tex.data,
1354
+ colorSpace: 'linear',
1355
+ };
1356
+ const regResult = registerCube(world, cubeAsset);
1357
+ if (!regResult.ok) return recordFailed(regResult.error);
1358
+ const cubeHandle = regResult.value;
1359
+ const cubeId = handleSlot(cubeHandle);
1360
+
1361
+ this.cubemapGpuHandles.set(cubeId, {
1362
+ status: 'ready',
1363
+ texture: gpuTextureWrapper,
1364
+ view: cubeView,
1365
+ faceViews,
1366
+ });
1367
+
1368
+ this.cubemapIdempotentMap.set(sourceId, cubeHandle);
1369
+
1370
+ if (this.asyncCreateShaderModule !== undefined) {
1371
+ // biome-ignore lint/suspicious/noExplicitAny: device shim narrowed at runtime
1372
+ const ipDevice = device as any;
1373
+ const pipelinesRes = await createIblPipelines(
1374
+ ipDevice,
1375
+ // biome-ignore lint/suspicious/noExplicitAny: factory signatures are interoperable; device shim is structural
1376
+ this.asyncCreateShaderModule as any,
1377
+ outputFormat,
1378
+ );
1379
+ if (pipelinesRes.ok) {
1380
+ // biome-ignore lint/suspicious/noExplicitAny: device shim
1381
+ const fdevice = device as any;
1382
+ const equirectGpuTexRet = fdevice.createTexture({
1383
+ label: `equirect-${sourceId}`,
1384
+ size: { width: tex.width, height: tex.height, depthOrArrayLayers: 1 },
1385
+ mipLevelCount: 1,
1386
+ sampleCount: 1,
1387
+ dimension: '2d',
1388
+ format: tex.format,
1389
+ usage: GPU_TEXTURE_USAGE_TEXTURE_BINDING | GPU_TEXTURE_USAGE_COPY_DST,
1390
+ viewFormats: [],
1391
+ });
1392
+ const equirectGpuTex = unwrap(equirectGpuTexRet);
1393
+ if (equirectGpuTex !== undefined && typeof fdevice.queue?.writeTexture === 'function') {
1394
+ const bytesPerPixel =
1395
+ tex.format === 'rgba32float' ? 16 : tex.format === 'rgba16float' ? 8 : 4;
1396
+ fdevice.queue.writeTexture(
1397
+ { texture: equirectGpuTex },
1398
+ tex.data,
1399
+ { bytesPerRow: tex.width * bytesPerPixel, rowsPerImage: tex.height },
1400
+ { width: tex.width, height: tex.height, depthOrArrayLayers: 1 },
1401
+ );
1402
+ }
1403
+ const equirectView =
1404
+ equirectGpuTex !== undefined
1405
+ ? makeTextureView(fdevice, equirectGpuTex, {
1406
+ label: `equirect-view-${sourceId}`,
1407
+ dimension: '2d',
1408
+ })
1409
+ : undefined;
1410
+ const faceBuf = unwrap(createFaceUniformsBuffer(ipDevice));
1411
+ const prefBuf = unwrap(createPrefilterUniformsBuffer(ipDevice));
1412
+ const cubeVertex = unwrap(
1413
+ fdevice.createBuffer({
1414
+ label: 'ibl-cube-verts',
1415
+ size: CUBEMAP_FACE_VERTICES.byteLength,
1416
+ usage: GPU_BUFFER_USAGE_VERTEX | GPU_BUFFER_USAGE_COPY_DST,
1417
+ mappedAtCreation: false,
1418
+ }),
1419
+ );
1420
+ if (
1421
+ equirectGpuTex !== undefined &&
1422
+ equirectView !== undefined &&
1423
+ faceBuf !== undefined &&
1424
+ prefBuf !== undefined &&
1425
+ cubeVertex !== undefined &&
1426
+ typeof fdevice.queue?.writeBuffer === 'function'
1427
+ ) {
1428
+ fdevice.queue.writeBuffer(cubeVertex, 0, CUBEMAP_FACE_VERTICES);
1429
+ writeAllFaceUniforms(ipDevice, faceBuf);
1430
+ writeAllPrefilterUniforms(ipDevice, prefBuf);
1431
+ const runRes = runIblPrecompute({
1432
+ device: ipDevice,
1433
+ equirectGpuTex,
1434
+ equirectView,
1435
+ cubeGpuTex: gpuTexture,
1436
+ cubeView,
1437
+ cubeFaceViews: faceViews,
1438
+ faceUniformsBuffer: faceBuf,
1439
+ prefilterUniformsBuffer: prefBuf,
1440
+ cubeVertexBuffer: cubeVertex,
1441
+ });
1442
+ if (!runRes.ok) {
1443
+ return recordFailed(
1444
+ makeAssetError({
1445
+ code: 'ibl-precompute-not-dispatched',
1446
+ expected: runRes.error.expected,
1447
+ hint: runRes.error.hint,
1448
+ }),
1449
+ );
1450
+ }
1451
+ }
1452
+ }
1453
+ }
1454
+
1455
+ return ok(cubeHandle);
1456
+ }
1457
+
1458
+ /**
1459
+ * Upload `MeshAsset.vertices` + `MeshAsset.indices` to GPU buffers and cache
1460
+ * the handles under the asset id. Synchronous; mirrors the pre-extraction
1461
+ * `uploadMeshById` byte-for-byte. Returns the cached entry on success.
1462
+ */
1463
+ private uploadMeshById(
1464
+ id: number,
1465
+ mesh: TypesMeshAsset,
1466
+ renderData: MeshRenderData,
1467
+ ): Result<MeshGpuEntry, RhiError> {
1468
+ const device = this.gpuDevice as MipmapBlitDeviceWithBuffer | undefined;
1469
+ if (device === undefined) {
1470
+ return err(
1471
+ new RhiError({
1472
+ code: 'rhi-not-available',
1473
+ expected: 'GpuResourceStore.configureGpuDevice wired before mesh ensureResident',
1474
+ hint: 'a mesh ensureResident ran before the GPU device was wired; call gpuStore.configureGpuDevice in createRenderer',
1475
+ }),
1476
+ );
1477
+ }
1478
+
1479
+ // biome-ignore lint/suspicious/noExplicitAny: union of shim/raw return shapes
1480
+ const unwrapBuffer = (r: any): any => {
1481
+ if (r === null || r === undefined) return undefined;
1482
+ if (typeof r === 'object' && 'ok' in r) return r.ok ? r.value : undefined;
1483
+ return r;
1484
+ };
1485
+ // biome-ignore lint/suspicious/noExplicitAny: union of shim/raw write return
1486
+ const writeOk = (r: any): boolean => {
1487
+ if (r === undefined) return true;
1488
+ if (typeof r === 'object' && 'ok' in r) return r.ok === true;
1489
+ return true;
1490
+ };
1491
+
1492
+ const indices = mesh.indices;
1493
+ const indexBytesUnpadded = indices === undefined ? 0 : indices.byteLength;
1494
+ const indexBytes = renderData.indexByteLength;
1495
+
1496
+ const vboRet = device.createBuffer({
1497
+ label: `mesh-${id}-vbo`,
1498
+ size: renderData.vertexByteLength,
1499
+ usage: renderData.vertexUsage,
1500
+ mappedAtCreation: false,
1501
+ });
1502
+ const vbo = unwrapBuffer(vboRet);
1503
+ if (vbo === undefined) {
1504
+ return err(
1505
+ new RhiError({
1506
+ code: 'webgpu-runtime-error',
1507
+ expected: `device.createBuffer mesh-${id}-vbo to return a valid buffer`,
1508
+ hint: 'mesh vertex buffer allocation returned undefined',
1509
+ }),
1510
+ );
1511
+ }
1512
+ // Vertex-only mesh: skip the index buffer entirely. The indexed path below
1513
+ // is unchanged byte-for-byte when `indices` is present.
1514
+ let ibo: unknown = null;
1515
+ if (indices !== undefined) {
1516
+ const iboRet = device.createBuffer({
1517
+ label: `mesh-${id}-ibo`,
1518
+ size: indexBytes,
1519
+ usage: renderData.indexUsage,
1520
+ mappedAtCreation: false,
1521
+ });
1522
+ ibo = unwrapBuffer(iboRet);
1523
+ if (ibo === undefined) {
1524
+ return err(
1525
+ new RhiError({
1526
+ code: 'webgpu-runtime-error',
1527
+ expected: `device.createBuffer mesh-${id}-ibo to return a valid buffer`,
1528
+ hint: 'mesh index buffer allocation returned undefined',
1529
+ }),
1530
+ );
1531
+ }
1532
+ }
1533
+
1534
+ const vboWriteRet = device.queue.writeBuffer(vbo, 0, mesh.vertices);
1535
+ if (!writeOk(vboWriteRet)) {
1536
+ return err(
1537
+ new RhiError({
1538
+ code: 'webgpu-runtime-error',
1539
+ expected: `queue.writeBuffer mesh-${id}-vbo to succeed`,
1540
+ hint: 'mesh vertex buffer write failed',
1541
+ }),
1542
+ );
1543
+ }
1544
+
1545
+ if (indices !== undefined) {
1546
+ const indexSrc = new Uint8Array(indexBytes);
1547
+ indexSrc.set(new Uint8Array(indices.buffer, indices.byteOffset, indexBytesUnpadded));
1548
+ const iboWriteRet = device.queue.writeBuffer(ibo, 0, indexSrc);
1549
+ if (!writeOk(iboWriteRet)) {
1550
+ return err(
1551
+ new RhiError({
1552
+ code: 'webgpu-runtime-error',
1553
+ expected: `queue.writeBuffer mesh-${id}-ibo to succeed`,
1554
+ hint: 'mesh index buffer write failed',
1555
+ }),
1556
+ );
1557
+ }
1558
+ }
1559
+
1560
+ const layoutProjection = renderData.layoutProjection;
1561
+ const strideBytes = meshStrideBytes(layoutProjection);
1562
+ const entry: MeshGpuEntry = {
1563
+ vertexBuffer: this.wrapBuf(vbo as Buffer),
1564
+ indexBuffer: ibo === null ? null : this.wrapBuf(ibo as Buffer),
1565
+ vboBytes: renderData.vertexByteLength,
1566
+ iboBytes: indices === undefined ? 0 : indexBytes,
1567
+ indexCount: renderData.indexCount,
1568
+ indexFormat: renderData.indexFormat,
1569
+ vertexCount: mesh.vertices.byteLength / strideBytes,
1570
+ indexed: indices !== undefined,
1571
+ topology: renderData.submeshes[0]?.topology ?? 'triangle-list',
1572
+ submeshes: renderData.submeshes,
1573
+ layoutProjection,
1574
+ };
1575
+ this.meshGpuHandles.set(id, entry);
1576
+ this.meshResidencyEpoch += 1;
1577
+ return ok(entry);
1578
+ }
1579
+
1580
+ /**
1581
+ * Update an existing resident mesh without changing its shape or metadata.
1582
+ * A shape change must use a new asset handle; this method never reallocates
1583
+ * or silently changes the draw contract.
1584
+ */
1585
+ private updateMeshById(
1586
+ id: number,
1587
+ newVertices: Float32Array,
1588
+ newIndices: Uint16Array | Uint32Array | undefined,
1589
+ submeshes?: readonly Submesh[],
1590
+ ): Result<void, MeshUpdateErrorType | RhiError> {
1591
+ const device = this.gpuDevice as MipmapBlitDeviceWithBuffer | undefined;
1592
+ if (device === undefined) {
1593
+ return err(
1594
+ new RhiError({
1595
+ code: 'rhi-not-available',
1596
+ expected: 'GpuResourceStore.configureGpuDevice wired before mesh update',
1597
+ hint: 'configure the renderer GPU device before updating a mesh',
1598
+ }),
1599
+ );
1600
+ }
1601
+ const entry = this.meshGpuHandles.get(id);
1602
+ if (entry === undefined) {
1603
+ return err(
1604
+ new MeshUpdateError({
1605
+ code: 'mesh-not-resident',
1606
+ detail: { handle: id },
1607
+ }),
1608
+ );
1609
+ }
1610
+
1611
+ const strideBytes = meshStrideBytes(entry.layoutProjection);
1612
+ const expectedVertexBytes = entry.vertexCount * strideBytes;
1613
+ const shapeMismatch = (expected: string, actual: string) =>
1614
+ err(
1615
+ new MeshUpdateError({
1616
+ code: 'mesh-shape-mismatch',
1617
+ detail: { handle: id, expected, actual },
1618
+ }),
1619
+ );
1620
+ if (
1621
+ newVertices.byteLength !== expectedVertexBytes ||
1622
+ newVertices.byteLength % strideBytes !== 0
1623
+ ) {
1624
+ return shapeMismatch(
1625
+ `${expectedVertexBytes} vertex bytes at ${strideBytes}-byte stride`,
1626
+ `${newVertices.byteLength} vertex bytes`,
1627
+ );
1628
+ }
1629
+
1630
+ if (entry.indexed !== (newIndices !== undefined)) {
1631
+ return shapeMismatch(
1632
+ entry.indexed ? 'indexed mesh data' : 'vertex-only mesh data',
1633
+ newIndices === undefined ? 'vertex-only mesh data' : 'indexed mesh data',
1634
+ );
1635
+ }
1636
+ if (newIndices !== undefined) {
1637
+ const indexFormat = newIndices instanceof Uint32Array ? 'uint32' : 'uint16';
1638
+ const indexBytes = ((newIndices.byteLength + 3) >> 2) << 2;
1639
+ if (
1640
+ entry.indexBuffer === null ||
1641
+ indexFormat !== entry.indexFormat ||
1642
+ newIndices.length !== entry.indexCount ||
1643
+ indexBytes !== entry.iboBytes
1644
+ ) {
1645
+ return shapeMismatch(
1646
+ `${entry.indexFormat} index format with ${entry.indexCount} indices`,
1647
+ `${indexFormat} index format with ${newIndices.length} indices`,
1648
+ );
1649
+ }
1650
+ } else if (entry.indexBuffer !== null) {
1651
+ return shapeMismatch('indexed mesh data', 'vertex-only mesh data');
1652
+ }
1653
+
1654
+ const nextSubmeshes = submeshes ?? entry.submeshes;
1655
+ if (!submeshesEqual(entry.submeshes, nextSubmeshes)) {
1656
+ return shapeMismatch('unchanged submesh descriptors', 'different submesh descriptors');
1657
+ }
1658
+
1659
+ const vertexWrite = device.queue.writeBuffer(entry.vertexBuffer.handle, 0, newVertices);
1660
+ if (!vertexWrite.ok) return err(vertexWrite.error);
1661
+ if (newIndices !== undefined && entry.indexBuffer !== null) {
1662
+ const indexSrc = new Uint8Array(entry.iboBytes);
1663
+ indexSrc.set(new Uint8Array(newIndices.buffer, newIndices.byteOffset, newIndices.byteLength));
1664
+ const indexWrite = device.queue.writeBuffer(entry.indexBuffer.handle, 0, indexSrc);
1665
+ if (!indexWrite.ok) return err(indexWrite.error);
1666
+ }
1667
+ this.meshResidencyEpoch += 1;
1668
+ return ok(undefined);
1669
+ }
1670
+
1671
+ /**
1672
+ * Internal explicit rebuild path used when an owner has deliberately
1673
+ * replaced a mesh shape. Public callers should register a new MeshAsset
1674
+ * handle so CPU recovery data and GPU residency remain one authority.
1675
+ */
1676
+ private replaceMeshById(
1677
+ id: number,
1678
+ newVertices: Float32Array,
1679
+ newIndices: Uint16Array | Uint32Array | undefined,
1680
+ submeshes?: readonly Submesh[],
1681
+ ): Result<void, MeshUpdateErrorType | RhiError> {
1682
+ const device = this.gpuDevice as MipmapBlitDeviceWithBuffer | undefined;
1683
+ const entry = this.meshGpuHandles.get(id);
1684
+ if (device === undefined) {
1685
+ return err(
1686
+ new RhiError({
1687
+ code: 'rhi-not-available',
1688
+ expected: 'GpuResourceStore.configureGpuDevice wired before mesh replacement',
1689
+ hint: 'configure the renderer GPU device before replacing a mesh',
1690
+ }),
1691
+ );
1692
+ }
1693
+ if (entry === undefined) {
1694
+ return err(new MeshUpdateError({ code: 'mesh-not-resident', detail: { handle: id } }));
1695
+ }
1696
+ const strideBytes = meshStrideBytes(entry.layoutProjection);
1697
+ if (newVertices.byteLength === 0 || newVertices.byteLength % strideBytes !== 0) {
1698
+ return err(
1699
+ new MeshUpdateError({
1700
+ code: 'mesh-shape-mismatch',
1701
+ detail: {
1702
+ handle: id,
1703
+ expected: `vertex bytes divisible by ${strideBytes}`,
1704
+ actual: `${newVertices.byteLength} vertex bytes`,
1705
+ },
1706
+ }),
1707
+ );
1708
+ }
1709
+ const newVertexBytes = newVertices.byteLength;
1710
+ const newIndexBytes = newIndices === undefined ? 0 : ((newIndices.byteLength + 3) >> 2) << 2;
1711
+ const unwrapBuffer = (r: unknown): unknown => {
1712
+ if (r === null || r === undefined) return undefined;
1713
+ if (typeof r === 'object' && 'ok' in r) {
1714
+ return (r as { ok: boolean; value?: unknown }).ok
1715
+ ? (r as unknown as { value: unknown }).value
1716
+ : undefined;
1717
+ }
1718
+ return r;
1719
+ };
1720
+ const vbo = unwrapBuffer(
1721
+ device.createBuffer({
1722
+ label: `mesh-${id}-vbo`,
1723
+ size: newVertexBytes,
1724
+ usage: GPU_BUFFER_USAGE_VERTEX | GPU_BUFFER_USAGE_COPY_DST,
1725
+ mappedAtCreation: false,
1726
+ }),
1727
+ );
1728
+ if (vbo === undefined) {
1729
+ return err(
1730
+ new RhiError({
1731
+ code: 'webgpu-runtime-error',
1732
+ expected: `device.createBuffer mesh-${id}-vbo to return a valid buffer`,
1733
+ hint: 'mesh replacement vertex buffer allocation failed',
1734
+ }),
1735
+ );
1736
+ }
1737
+ const ibo =
1738
+ newIndices === undefined
1739
+ ? null
1740
+ : unwrapBuffer(
1741
+ device.createBuffer({
1742
+ label: `mesh-${id}-ibo`,
1743
+ size: newIndexBytes,
1744
+ usage: GPU_BUFFER_USAGE_INDEX | GPU_BUFFER_USAGE_COPY_DST,
1745
+ mappedAtCreation: false,
1746
+ }),
1747
+ );
1748
+ if (newIndices !== undefined && ibo === undefined) {
1749
+ this.destroyMeshBuffer(this.wrapBuf(vbo as Buffer));
1750
+ return err(
1751
+ new RhiError({
1752
+ code: 'webgpu-runtime-error',
1753
+ expected: `device.createBuffer mesh-${id}-ibo to return a valid buffer`,
1754
+ hint: 'mesh replacement index buffer allocation failed',
1755
+ }),
1756
+ );
1757
+ }
1758
+ const vertexBuffer = this.wrapBuf(vbo as Buffer);
1759
+ const indexBuffer = ibo === null ? null : this.wrapBuf(ibo as Buffer);
1760
+ const vertexWrite = device.queue.writeBuffer(vertexBuffer.handle, 0, newVertices);
1761
+ if (!vertexWrite.ok) {
1762
+ this.destroyMeshBuffer(vertexBuffer);
1763
+ if (indexBuffer !== null) this.destroyMeshBuffer(indexBuffer);
1764
+ return err(vertexWrite.error);
1765
+ }
1766
+ if (newIndices !== undefined && indexBuffer !== null) {
1767
+ const indexSrc = new Uint8Array(newIndexBytes);
1768
+ indexSrc.set(new Uint8Array(newIndices.buffer, newIndices.byteOffset, newIndices.byteLength));
1769
+ const indexWrite = device.queue.writeBuffer(indexBuffer.handle, 0, indexSrc);
1770
+ if (!indexWrite.ok) {
1771
+ this.destroyMeshBuffer(vertexBuffer);
1772
+ this.destroyMeshBuffer(indexBuffer);
1773
+ return err(indexWrite.error);
1774
+ }
1775
+ }
1776
+ const nextSubmeshes = submeshes ?? entry.submeshes;
1777
+ const nextEntry: MeshGpuEntry = {
1778
+ vertexBuffer,
1779
+ indexBuffer,
1780
+ vboBytes: newVertexBytes,
1781
+ iboBytes: newIndexBytes,
1782
+ indexCount: newIndices?.length ?? 0,
1783
+ indexFormat: newIndices instanceof Uint32Array ? 'uint32' : 'uint16',
1784
+ layoutProjection: entry.layoutProjection,
1785
+ vertexCount: newVertexBytes / strideBytes,
1786
+ indexed: newIndices !== undefined,
1787
+ topology: nextSubmeshes[0]?.topology ?? entry.topology,
1788
+ submeshes: nextSubmeshes,
1789
+ };
1790
+ this.meshGpuHandles.set(id, nextEntry);
1791
+ this.meshResidencyEpoch += 1;
1792
+ this.destroyMeshBuffer(entry.vertexBuffer);
1793
+ if (entry.indexBuffer !== null) this.destroyMeshBuffer(entry.indexBuffer);
1794
+ return ok(undefined);
1795
+ }
1796
+
1797
+ /**
1798
+ * Public surface for updating an existing unmanaged mesh handle's GPU buffer
1799
+ * data in-place. The handle must have been made resident.
1800
+ */
1801
+ updateMesh(
1802
+ handle: Handle<'MeshAsset', 'shared'>,
1803
+ newVertices: Float32Array,
1804
+ newIndices: Uint16Array | Uint32Array | undefined,
1805
+ worldId: number = 0,
1806
+ submeshes?: readonly Submesh[],
1807
+ ): Result<void, MeshUpdateErrorType | RhiError> {
1808
+ const id = this.worldKey(handleSlot(handle), worldId);
1809
+ return this.updateMeshById(id, newVertices, newIndices, submeshes);
1810
+ }
1811
+
1812
+ /** Explicit internal rebuild path; public callers should use a new asset handle. */
1813
+ replaceMesh(
1814
+ handle: Handle<'MeshAsset', 'shared'>,
1815
+ newVertices: Float32Array,
1816
+ newIndices: Uint16Array | Uint32Array | undefined,
1817
+ worldId: number = 0,
1818
+ submeshes?: readonly Submesh[],
1819
+ ): Result<void, MeshUpdateErrorType | RhiError> {
1820
+ const id = this.worldKey(handleSlot(handle), worldId);
1821
+ return this.replaceMeshById(id, newVertices, newIndices, submeshes);
1822
+ }
1823
+
1824
+ /** Upload a contiguous vertex range using the resident mesh stride. */
1825
+ updateMeshVertexRange(
1826
+ handle: Handle<'MeshAsset', 'shared'>,
1827
+ vertices: Float32Array,
1828
+ firstVertex: number,
1829
+ vertexCount: number,
1830
+ worldId: number = 0,
1831
+ ): Result<void, MeshUpdateErrorType | RhiError> {
1832
+ const id = this.worldKey(handleSlot(handle), worldId);
1833
+ const device = this.gpuDevice as MipmapBlitDeviceWithBuffer | undefined;
1834
+ if (device === undefined) {
1835
+ return err(
1836
+ new RhiError({
1837
+ code: 'rhi-not-available',
1838
+ expected: 'GpuResourceStore.configureGpuDevice wired before mesh range update',
1839
+ hint: 'configure the renderer GPU device before updating a mesh range',
1840
+ }),
1841
+ );
1842
+ }
1843
+ const entry = this.meshGpuHandles.get(id);
1844
+ if (entry === undefined) {
1845
+ return err(new MeshUpdateError({ code: 'mesh-not-resident', detail: { handle: id } }));
1846
+ }
1847
+ const strideBytes = meshStrideBytes(entry.layoutProjection);
1848
+ const invalidLocation = (
1849
+ reason: Exclude<MeshRangeInvalidReason, 'stride-mismatch'>,
1850
+ ): Result<void, MeshUpdateErrorType | RhiError> =>
1851
+ err(
1852
+ new MeshUpdateError({
1853
+ code: 'mesh-range-invalid',
1854
+ detail: {
1855
+ handle: id,
1856
+ firstVertex,
1857
+ vertexCount,
1858
+ residentVertexCount: entry.vertexCount,
1859
+ reason,
1860
+ },
1861
+ }),
1862
+ );
1863
+ const invalidStride = (
1864
+ expectedByteLength: number,
1865
+ actualByteLength: number,
1866
+ ): Result<void, MeshUpdateErrorType | RhiError> =>
1867
+ err(
1868
+ new MeshUpdateError({
1869
+ code: 'mesh-range-invalid',
1870
+ detail: {
1871
+ handle: id,
1872
+ firstVertex,
1873
+ vertexCount,
1874
+ residentVertexCount: entry.vertexCount,
1875
+ reason: 'stride-mismatch',
1876
+ expectedByteLength,
1877
+ actualByteLength,
1878
+ },
1879
+ }),
1880
+ );
1881
+ if (!Number.isInteger(firstVertex) || !Number.isInteger(vertexCount)) {
1882
+ return invalidLocation('non-integer');
1883
+ }
1884
+ if (firstVertex < 0 || vertexCount < 0) return invalidLocation('negative');
1885
+ if (vertexCount === 0) return invalidLocation('empty');
1886
+ if (firstVertex + vertexCount > entry.vertexCount) return invalidLocation('out-of-bounds');
1887
+ const expectedByteLength = vertexCount * strideBytes;
1888
+ if (vertices.byteLength !== expectedByteLength) {
1889
+ return invalidStride(expectedByteLength, vertices.byteLength);
1890
+ }
1891
+ const result = device.queue.writeBuffer(
1892
+ entry.vertexBuffer.handle,
1893
+ firstVertex * strideBytes,
1894
+ vertices,
1895
+ );
1896
+ if (!result.ok) return err(result.error);
1897
+ this.meshResidencyEpoch += 1;
1898
+ return ok(undefined);
1899
+ }
1900
+ }
1901
+
1902
+ /**
1903
+ * Synthesize the `DecodedImage` view the texture-upload prelude consumes from
1904
+ * a `TextureAsset` POD (the record-stage pull path holds only the POD). The
1905
+ * POD's `data` is the pixel bytes; `colorSpace` + `mipmap` drive the
1906
+ * consistency assertion + mip count.
1907
+ */
1908
+ function decodedFromTexture(tex: TextureAsset): DecodedImage {
1909
+ const bytes =
1910
+ tex.data instanceof Uint8ClampedArray
1911
+ ? new Uint8Array(tex.data.buffer, tex.data.byteOffset, tex.data.byteLength)
1912
+ : tex.data;
1913
+ return {
1914
+ bytes,
1915
+ width: tex.width,
1916
+ height: tex.height,
1917
+ mime: 'image/png',
1918
+ colorSpace: tex.colorSpace,
1919
+ mipmap: tex.mipmap,
1920
+ };
1921
+ }