@forgeax/engine-render 0.1.21 → 0.1.24

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 (584) hide show
  1. package/README.md +281 -38
  2. package/dist/assembly/backend-contract.d.ts +13 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/bundler-contract.d.ts +9 -0
  5. package/dist/assembly/bundler-contract.d.ts.map +1 -0
  6. package/dist/assembly/device-feature-admission.d.ts +8 -0
  7. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  8. package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
  9. package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
  10. package/dist/assembly/factory.d.ts +7 -235
  11. package/dist/assembly/factory.d.ts.map +1 -1
  12. package/dist/assembly/host-contract.d.ts +10 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +3 -2
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
  17. package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
  18. package/dist/assembly/material-shader-policy.d.ts +168 -0
  19. package/dist/assembly/material-shader-policy.d.ts.map +1 -0
  20. package/dist/assembly/material-shader-prewarm.d.ts +21 -0
  21. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
  22. package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
  23. package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
  25. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
  26. package/dist/assembly/recovery/generation.d.ts +46 -0
  27. package/dist/assembly/recovery/generation.d.ts.map +1 -0
  28. package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
  29. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
  30. package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
  31. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
  32. package/dist/assembly/renderer-facade.d.ts +10 -0
  33. package/dist/assembly/renderer-facade.d.ts.map +1 -0
  34. package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
  35. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  36. package/dist/assembly/renderer-helpers.d.ts +19 -0
  37. package/dist/assembly/renderer-helpers.d.ts.map +1 -0
  38. package/dist/assembly/renderer-lifecycle.d.ts +34 -0
  39. package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
  40. package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
  41. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
  42. package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
  43. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
  44. package/dist/assembly/webgpu-ready.d.ts +55 -0
  45. package/dist/assembly/webgpu-ready.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-renderer.d.ts +152 -0
  47. package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
  48. package/dist/authoring.mjs +1 -1
  49. package/dist/{chunk-PCHBPYML.mjs → chunk-GE3SDD72.mjs} +37 -5
  50. package/dist/chunk-GE3SDD72.mjs.map +1 -0
  51. package/dist/chunk-KZFTK6DO.mjs +1191 -0
  52. package/dist/chunk-KZFTK6DO.mjs.map +1 -0
  53. package/dist/{chunk-FS2KNUQH.mjs → chunk-Q752SHI5.mjs} +332 -568
  54. package/dist/chunk-Q752SHI5.mjs.map +1 -0
  55. package/dist/{chunk-6OPXDQ2E.mjs → chunk-RR5L4SRS.mjs} +33 -294
  56. package/dist/chunk-RR5L4SRS.mjs.map +1 -0
  57. package/dist/chunk-TFH5I7JJ.mjs +296 -0
  58. package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
  59. package/dist/chunk-UQYS7FRM.mjs +1003 -0
  60. package/dist/chunk-UQYS7FRM.mjs.map +1 -0
  61. package/dist/chunk-YKB5DQV7.mjs +345 -0
  62. package/dist/chunk-YKB5DQV7.mjs.map +1 -0
  63. package/dist/{chunk-5YADUCA7.mjs → chunk-YRUYGA4A.mjs} +1189 -1217
  64. package/dist/chunk-YRUYGA4A.mjs.map +1 -0
  65. package/dist/chunk-Z3YYH2MB.mjs +5082 -0
  66. package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
  67. package/dist/cluster-binner.d.ts +5 -0
  68. package/dist/cluster-binner.d.ts.map +1 -1
  69. package/dist/components/index.d.ts +3 -0
  70. package/dist/components/index.d.ts.map +1 -1
  71. package/dist/components/light-helpers.d.ts +4 -0
  72. package/dist/components/light-helpers.d.ts.map +1 -1
  73. package/dist/components/light-probe.d.ts +9 -0
  74. package/dist/components/light-probe.d.ts.map +1 -0
  75. package/dist/components/rect-area-light.d.ts +12 -0
  76. package/dist/components/rect-area-light.d.ts.map +1 -0
  77. package/dist/components/scene-instance.d.ts +4 -0
  78. package/dist/components/scene-instance.d.ts.map +1 -1
  79. package/dist/components/spot-light.d.ts +3 -0
  80. package/dist/components/spot-light.d.ts.map +1 -1
  81. package/dist/construct-renderer.mjs +27276 -23232
  82. package/dist/construct-renderer.mjs.map +1 -1
  83. package/dist/device/device-scope.d.ts +2 -0
  84. package/dist/device/device-scope.d.ts.map +1 -1
  85. package/dist/device/gpu-residency.d.ts +32 -5
  86. package/dist/device/gpu-residency.d.ts.map +1 -1
  87. package/dist/device/lifecycle-transaction.d.ts +2 -0
  88. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  89. package/dist/environment/frame.d.ts +5 -0
  90. package/dist/environment/frame.d.ts.map +1 -1
  91. package/dist/environment/inspection.d.ts +7 -0
  92. package/dist/environment/inspection.d.ts.map +1 -1
  93. package/dist/environment/lifecycle.d.ts +20 -2
  94. package/dist/environment/lifecycle.d.ts.map +1 -1
  95. package/dist/errors/gpu-driven.d.ts +26 -0
  96. package/dist/errors/gpu-driven.d.ts.map +1 -0
  97. package/dist/errors/index.d.ts +1 -0
  98. package/dist/errors/index.d.ts.map +1 -1
  99. package/dist/errors/recover.d.ts +67 -3
  100. package/dist/errors/recover.d.ts.map +1 -1
  101. package/dist/errors/render.d.ts +39 -1
  102. package/dist/errors/render.d.ts.map +1 -1
  103. package/dist/extract/contracts.d.ts +899 -0
  104. package/dist/extract/contracts.d.ts.map +1 -0
  105. package/dist/extract/gpu-driven.d.ts +50 -0
  106. package/dist/extract/gpu-driven.d.ts.map +1 -0
  107. package/dist/extract/visibility.d.ts.map +1 -1
  108. package/dist/features/host.d.ts +2 -0
  109. package/dist/features/host.d.ts.map +1 -1
  110. package/dist/features/prepared-gpu-work.d.ts +3 -0
  111. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  112. package/dist/features/prepared-graphics-store.d.ts +2 -0
  113. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  114. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  115. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  116. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  117. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  118. package/dist/gpu-driven/production-raster.d.ts +126 -2
  119. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  120. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  121. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  122. package/dist/gpu-scene-schema.d.ts +14 -0
  123. package/dist/gpu-scene-schema.d.ts.map +1 -1
  124. package/dist/gpu-scene.d.ts +9 -1
  125. package/dist/gpu-scene.d.ts.map +1 -1
  126. package/dist/gpu-usage.d.ts +0 -1
  127. package/dist/gpu-usage.d.ts.map +1 -1
  128. package/dist/hdrp-buffers.d.ts +3 -3
  129. package/dist/hdrp-buffers.d.ts.map +1 -1
  130. package/dist/ibl/IblPipelineCache.d.ts +7 -6
  131. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  132. package/dist/ibl/skylight-bind-group.d.ts +7 -1
  133. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  134. package/dist/index.d.ts +13 -2
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.mjs +90 -5
  137. package/dist/index.mjs.map +1 -1
  138. package/dist/inspection-types.d.ts +163 -1
  139. package/dist/inspection-types.d.ts.map +1 -1
  140. package/dist/internal.d.ts +9 -0
  141. package/dist/internal.d.ts.map +1 -1
  142. package/dist/internal.mjs +23 -2
  143. package/dist/internal.mjs.map +1 -1
  144. package/dist/light-buffer-layout.d.ts +60 -148
  145. package/dist/light-buffer-layout.d.ts.map +1 -1
  146. package/dist/materials.d.ts +34 -10
  147. package/dist/materials.d.ts.map +1 -1
  148. package/dist/mesh-material-bindings.d.ts +56 -0
  149. package/dist/mesh-material-bindings.d.ts.map +1 -1
  150. package/dist/occlusion-proxy.d.ts +4 -0
  151. package/dist/occlusion-proxy.d.ts.map +1 -0
  152. package/dist/pbr-pipeline.d.ts +58 -21
  153. package/dist/pbr-pipeline.d.ts.map +1 -1
  154. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  155. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
  156. package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
  157. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
  158. package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
  159. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
  160. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
  161. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  162. package/dist/pipeline-builder.d.ts +2 -0
  163. package/dist/pipeline-builder.d.ts.map +1 -1
  164. package/dist/pipeline-spec.d.ts +1 -1
  165. package/dist/pipeline-spec.d.ts.map +1 -1
  166. package/dist/plugin.d.ts.map +1 -1
  167. package/dist/points-lines/prepare.d.ts +3 -0
  168. package/dist/points-lines/prepare.d.ts.map +1 -1
  169. package/dist/points-lines/standard-owner.d.ts +33 -0
  170. package/dist/points-lines/standard-owner.d.ts.map +1 -0
  171. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  172. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  173. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  174. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  175. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  176. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  177. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  178. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  179. package/dist/record/frame-lighting.d.ts +8 -6
  180. package/dist/record/frame-lighting.d.ts.map +1 -1
  181. package/dist/record/frame-snapshot.d.ts +55 -10
  182. package/dist/record/frame-snapshot.d.ts.map +1 -1
  183. package/dist/record/frame-targets.d.ts.map +1 -1
  184. package/dist/record/frame.d.ts +21 -5
  185. package/dist/record/frame.d.ts.map +1 -1
  186. package/dist/record/gpu-timing.d.ts +19 -7
  187. package/dist/record/gpu-timing.d.ts.map +1 -1
  188. package/dist/record/helpers.d.ts +0 -20
  189. package/dist/record/helpers.d.ts.map +1 -1
  190. package/dist/record/main-pass-geometry.d.ts +20 -2
  191. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  192. package/dist/record/main-pass-material.d.ts +10 -18
  193. package/dist/record/main-pass-material.d.ts.map +1 -1
  194. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  195. package/dist/record/main-pass.d.ts.map +1 -1
  196. package/dist/record/mesh-ssbo.d.ts +11 -3
  197. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  198. package/dist/record/recovery-pipeline.d.ts +30 -0
  199. package/dist/record/recovery-pipeline.d.ts.map +1 -0
  200. package/dist/record/render-context.d.ts +82 -9
  201. package/dist/record/render-context.d.ts.map +1 -1
  202. package/dist/record/shadow-pass.d.ts.map +1 -1
  203. package/dist/record/typed-frame-graph.d.ts +49 -2
  204. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  205. package/dist/record/view-ubo.d.ts +1 -2
  206. package/dist/record/view-ubo.d.ts.map +1 -1
  207. package/dist/recovery/render-system-candidate.d.ts +65 -0
  208. package/dist/recovery/render-system-candidate.d.ts.map +1 -0
  209. package/dist/reflection/inspection.d.ts +10 -0
  210. package/dist/reflection/inspection.d.ts.map +1 -0
  211. package/dist/reflection/projection.d.ts +49 -0
  212. package/dist/reflection/projection.d.ts.map +1 -1
  213. package/dist/reflection/record-owner.d.ts +60 -0
  214. package/dist/reflection/record-owner.d.ts.map +1 -0
  215. package/dist/render-contract.d.ts +78 -15
  216. package/dist/render-contract.d.ts.map +1 -1
  217. package/dist/render-pipeline.d.ts +7 -0
  218. package/dist/render-pipeline.d.ts.map +1 -1
  219. package/dist/render-system-extract-tail.d.ts +12 -0
  220. package/dist/render-system-extract-tail.d.ts.map +1 -0
  221. package/dist/render-system-extract.d.ts +252 -30
  222. package/dist/render-system-extract.d.ts.map +1 -1
  223. package/dist/render-system.d.ts +140 -5
  224. package/dist/render-system.d.ts.map +1 -1
  225. package/dist/scene/probe-blend-record.d.ts +22 -0
  226. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  227. package/dist/scene/probe-blend.d.ts +142 -0
  228. package/dist/scene/probe-blend.d.ts.map +1 -0
  229. package/dist/scene/render-scene-types.d.ts +0 -6
  230. package/dist/scene/render-scene-types.d.ts.map +1 -1
  231. package/dist/scene/render-scene.d.ts +122 -9
  232. package/dist/scene/render-scene.d.ts.map +1 -1
  233. package/dist/scene/visibility/bounds.d.ts +20 -0
  234. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  235. package/dist/scene/visibility/budget.d.ts +16 -0
  236. package/dist/scene/visibility/budget.d.ts.map +1 -0
  237. package/dist/scene/visibility/facet.d.ts +73 -0
  238. package/dist/scene/visibility/facet.d.ts.map +1 -0
  239. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  240. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  241. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  242. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  243. package/dist/scene/visibility/inspection.d.ts +132 -0
  244. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  245. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  246. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  247. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  248. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  249. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  250. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  251. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  252. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  253. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  254. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  255. package/dist/scene/visibility/types.d.ts +34 -0
  256. package/dist/scene/visibility/types.d.ts.map +1 -0
  257. package/dist/ssr/admission.d.ts +122 -0
  258. package/dist/ssr/admission.d.ts.map +1 -0
  259. package/dist/ssr/composition.d.ts +32 -0
  260. package/dist/ssr/composition.d.ts.map +1 -0
  261. package/dist/ssr/errors.d.ts +39 -0
  262. package/dist/ssr/errors.d.ts.map +1 -0
  263. package/dist/ssr/identity.d.ts +13 -0
  264. package/dist/ssr/identity.d.ts.map +1 -0
  265. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  266. package/dist/temporal/frame-coordinator.d.ts +13 -0
  267. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  268. package/dist/temporal/frame.d.ts +2 -0
  269. package/dist/temporal/frame.d.ts.map +1 -1
  270. package/dist/temporal/index.mjs +6 -5
  271. package/dist/temporal/taa-history-store.d.ts +15 -1
  272. package/dist/temporal/taa-history-store.d.ts.map +1 -1
  273. package/dist/temporal/transaction.d.ts +5 -0
  274. package/dist/temporal/transaction.d.ts.map +1 -1
  275. package/dist/temporal/view.d.ts +7 -0
  276. package/dist/temporal/view.d.ts.map +1 -1
  277. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  278. package/dist/typed-render-graph-primitives.d.ts +4 -0
  279. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  280. package/dist/volume/passes.d.ts +8 -4
  281. package/dist/volume/passes.d.ts.map +1 -1
  282. package/package.json +20 -20
  283. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
  284. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  285. package/src/__tests__/device-feature-admission.unit.test.ts +19 -1
  286. package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
  287. package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
  288. package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
  289. package/src/__tests__/environment-generation.integration.test.ts +39 -0
  290. package/src/__tests__/evidence-identity.ts +13 -0
  291. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  292. package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
  293. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  294. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  295. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  296. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  297. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  298. package/src/__tests__/factory-contract.integration.test.ts +154 -6
  299. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
  300. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  301. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  302. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
  303. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
  304. package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
  305. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  306. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  307. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
  308. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  309. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  310. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  311. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  312. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  313. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  314. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  315. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  316. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  317. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  318. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  319. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  320. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  321. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  322. package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
  323. package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
  324. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  325. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  326. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  327. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  328. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  329. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  330. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  331. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  332. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  333. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  334. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  335. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  336. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  337. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  338. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  339. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  340. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  341. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  342. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  343. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  344. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  345. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  346. package/src/__tests__/material-contract-inventory.unit.test.ts +41 -9
  347. package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
  348. package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
  349. package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
  350. package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
  351. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  352. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  353. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  354. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  355. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  356. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  357. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  358. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  359. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  360. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  361. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  362. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  363. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  364. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  365. package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
  366. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  367. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
  368. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  369. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  370. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  371. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  372. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  373. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  374. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  375. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  376. package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
  377. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
  378. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  379. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  380. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  381. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  382. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  383. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  384. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  385. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  386. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  387. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  388. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  389. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  390. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  391. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +160 -17
  392. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
  393. package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
  394. package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
  395. package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
  396. package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
  397. package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
  398. package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
  399. package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
  400. package/src/__tests__/shader-manifest-fixture.ts +13 -16
  401. package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
  402. package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
  403. package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
  404. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  405. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  406. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  407. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  408. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  409. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
  410. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
  411. package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
  412. package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
  413. package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
  414. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  415. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  416. package/src/__tests__/transmission-prewarm.unit.test.ts +111 -32
  417. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  418. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  419. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  420. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  421. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  422. package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
  423. package/src/assembly/backend-contract.ts +13 -0
  424. package/src/assembly/bundler-contract.ts +9 -0
  425. package/src/assembly/device-feature-admission.ts +26 -9
  426. package/src/assembly/extended-lighting-fallback.ts +216 -0
  427. package/src/assembly/factory.ts +81 -9634
  428. package/src/assembly/host-contract.ts +10 -0
  429. package/src/assembly/material/assembly.ts +18 -2
  430. package/src/assembly/material/standard-layer-projection.ts +16 -0
  431. package/src/assembly/material-shader-policy.ts +854 -0
  432. package/src/assembly/material-shader-prewarm.ts +88 -0
  433. package/src/assembly/mesh-ssbo-grow.ts +270 -0
  434. package/src/assembly/recovery/device-loss-fanout.ts +89 -0
  435. package/src/assembly/recovery/generation.ts +141 -0
  436. package/src/assembly/recovery/recovery-attempt.ts +800 -0
  437. package/src/assembly/recovery/renderer-recover.ts +906 -0
  438. package/src/assembly/renderer-facade.ts +342 -0
  439. package/src/assembly/renderer-frame-transaction.ts +45 -0
  440. package/src/assembly/renderer-helpers.ts +99 -0
  441. package/src/assembly/renderer-lifecycle.ts +159 -0
  442. package/src/assembly/shader-prewarm-policy.ts +157 -0
  443. package/src/assembly/webgpu-ready-contract.ts +14 -0
  444. package/src/assembly/webgpu-ready.ts +4079 -0
  445. package/src/assembly/webgpu-renderer.ts +4095 -0
  446. package/src/cluster-binner.ts +31 -0
  447. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  448. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  449. package/src/components/camera.ts +1 -1
  450. package/src/components/index.ts +3 -0
  451. package/src/components/light-helpers.ts +52 -1
  452. package/src/components/light-probe.ts +13 -0
  453. package/src/components/rect-area-light.ts +15 -0
  454. package/src/components/scene-instance.ts +6 -0
  455. package/src/components/spot-light.ts +3 -0
  456. package/src/debug-draw-glue.ts +1 -1
  457. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  458. package/src/device/device-scope.ts +35 -6
  459. package/src/device/gpu-residency.ts +334 -35
  460. package/src/device/lifecycle-transaction.ts +12 -0
  461. package/src/environment/frame.ts +6 -0
  462. package/src/environment/inspection.ts +10 -0
  463. package/src/environment/lifecycle.ts +122 -9
  464. package/src/errors/gpu-driven.ts +92 -0
  465. package/src/errors/index.ts +1 -0
  466. package/src/errors/recover.ts +108 -5
  467. package/src/errors/render.ts +72 -1
  468. package/src/extract/camera.ts +3 -3
  469. package/src/extract/contracts.ts +974 -0
  470. package/src/extract/gpu-driven.ts +108 -0
  471. package/src/extract/visibility.ts +0 -23
  472. package/src/features/host.ts +16 -0
  473. package/src/features/prepared-gpu-work.ts +20 -2
  474. package/src/features/prepared-graphics-store.ts +17 -0
  475. package/src/gpu-driven/batch-topology.ts +206 -28
  476. package/src/gpu-driven/prepared-draw.ts +208 -0
  477. package/src/gpu-driven/production-raster.ts +1046 -39
  478. package/src/gpu-driven/view-gpu.ts +411 -29
  479. package/src/gpu-scene-schema.ts +13 -0
  480. package/src/gpu-scene.ts +137 -67
  481. package/src/gpu-usage.ts +0 -1
  482. package/src/hdrp-buffers.ts +6 -6
  483. package/src/ibl/IblPipelineCache.ts +134 -50
  484. package/src/ibl/skylight-bind-group.ts +26 -0
  485. package/src/index.ts +83 -1
  486. package/src/inspection-types.ts +220 -1
  487. package/src/internal.ts +38 -0
  488. package/src/light-buffer-layout.ts +157 -324
  489. package/src/materials.ts +278 -47
  490. package/src/mesh-material-bindings.ts +59 -0
  491. package/src/occlusion-proxy.ts +64 -0
  492. package/src/pbr-pipeline.ts +290 -60
  493. package/src/pipeline/standard-forward-lane.ts +47 -0
  494. package/src/pipeline/standard-lighting/graph.ts +2 -1
  495. package/src/pipeline/standard-lighting/light-frame.ts +3 -2
  496. package/src/pipeline/standard-lighting/topology.ts +1 -1
  497. package/src/pipeline/standard-lighting/transport.ts +2 -1
  498. package/src/pipeline/standard-pipeline.ts +2 -0
  499. package/src/pipeline-builder.ts +5 -2
  500. package/src/pipeline-spec.ts +12 -1
  501. package/src/plugin.ts +4 -0
  502. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
  503. package/src/points-lines/prepare.ts +9 -0
  504. package/src/points-lines/standard-owner.ts +403 -0
  505. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  506. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  507. package/src/prepare/extended-lighting/resources.ts +389 -0
  508. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  509. package/src/prepare/extended-lighting/state.ts +92 -0
  510. package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
  511. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  512. package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
  513. package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
  514. package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
  515. package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
  516. package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
  517. package/src/record/__tests__/temporal-payload.unit.test.ts +29 -28
  518. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +21 -2
  519. package/src/record/frame-lighting.ts +252 -53
  520. package/src/record/frame-snapshot.ts +72 -12
  521. package/src/record/frame-targets.ts +11 -1
  522. package/src/record/frame.ts +416 -95
  523. package/src/record/gpu-timing.ts +108 -44
  524. package/src/record/helpers.ts +1 -59
  525. package/src/record/main-pass-geometry.ts +434 -44
  526. package/src/record/main-pass-material.ts +324 -210
  527. package/src/record/main-pass-sprite-draws.ts +58 -92
  528. package/src/record/main-pass.ts +94 -6
  529. package/src/record/mesh-ssbo.ts +79 -46
  530. package/src/record/recovery-pipeline.ts +695 -0
  531. package/src/record/render-context.ts +99 -7
  532. package/src/record/shadow-pass.ts +66 -40
  533. package/src/record/typed-frame-graph.ts +270 -84
  534. package/src/record/view-ubo.ts +17 -27
  535. package/src/recovery/render-system-candidate.ts +839 -0
  536. package/src/reflection/inspection.ts +67 -0
  537. package/src/reflection/projection.ts +196 -1
  538. package/src/reflection/record-owner.ts +1283 -0
  539. package/src/render-contract.ts +82 -12
  540. package/src/render-pipeline.ts +5 -0
  541. package/src/render-system-extract-tail.ts +2983 -0
  542. package/src/render-system-extract.ts +290 -2784
  543. package/src/render-system.ts +1597 -1192
  544. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  545. package/src/scene/probe-blend-record.ts +54 -0
  546. package/src/scene/probe-blend.ts +813 -0
  547. package/src/scene/render-scene-types.ts +0 -7
  548. package/src/scene/render-scene.ts +972 -184
  549. package/src/scene/visibility/bounds.ts +57 -0
  550. package/src/scene/visibility/budget.ts +40 -0
  551. package/src/scene/visibility/facet.ts +400 -0
  552. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  553. package/src/scene/visibility/gpu-lod.ts +119 -0
  554. package/src/scene/visibility/inspection.ts +313 -0
  555. package/src/scene/visibility/lod-selector.ts +84 -0
  556. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  557. package/src/scene/visibility/occlusion-pass.ts +165 -0
  558. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  559. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  560. package/src/scene/visibility/types.ts +50 -0
  561. package/src/ssr/admission.ts +451 -0
  562. package/src/ssr/composition.ts +73 -0
  563. package/src/ssr/errors.ts +76 -0
  564. package/src/ssr/identity.ts +12 -0
  565. package/src/systems/skin-palette-allocator.ts +1 -1
  566. package/src/temporal/frame-coordinator.ts +30 -1
  567. package/src/temporal/frame.ts +14 -1
  568. package/src/temporal/taa-history-store.ts +46 -2
  569. package/src/temporal/temporal-view.ts +1 -1
  570. package/src/temporal/transaction.ts +9 -0
  571. package/src/temporal/view.ts +11 -0
  572. package/src/tilemap-chunk-extract-system.ts +5 -5
  573. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
  574. package/src/typed-render-graph-primitives.ts +48 -0
  575. package/src/volume/passes.ts +46 -49
  576. package/dist/.tsbuildinfo +0 -1
  577. package/dist/chunk-5YADUCA7.mjs.map +0 -1
  578. package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
  579. package/dist/chunk-BXBQQKFQ.mjs +0 -67
  580. package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
  581. package/dist/chunk-FS2KNUQH.mjs.map +0 -1
  582. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  583. package/dist/chunk-VFPLTKCU.mjs +0 -192
  584. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -0,0 +1,974 @@
1
+ // Shared render-extract snapshot contracts.
2
+ //
3
+ // The extract orchestrator owns traversal and policy; this leaf owns the
4
+ // immutable POD vocabulary shared by extract, record, and temporal projection.
5
+
6
+ import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
7
+ import type { EntityHandle, World } from '@forgeax/engine-ecs';
8
+ import type { Vec3 } from '@forgeax/engine-math';
9
+ import type { SceneHierarchySnapshot } from '@forgeax/engine-scene';
10
+ import type {
11
+ Handle,
12
+ MaterialAsset,
13
+ MaterialPass,
14
+ MaterialRenderState,
15
+ MaterialTextureCoordinates,
16
+ MeshLodLevel,
17
+ ParamSchemaEntry,
18
+ PrimitiveTopology,
19
+ TextureAsset,
20
+ } from '@forgeax/engine-types';
21
+ import type { DirectionalShadowQuality } from '../components/directional-shadow-filter';
22
+ import type { LightValidationError } from '../components/light-helpers';
23
+ import type {
24
+ RenderFeatureHiddenEntityReport,
25
+ RenderFeatureWorldVisibilitySnapshot,
26
+ } from '../features/types';
27
+ import type {
28
+ MeshMaterialBindingDiagnostic,
29
+ MeshMaterialBindingSource,
30
+ } from '../mesh-material-bindings';
31
+ import type { PointsLinesRetainedSnapshot } from '../points-lines/snapshot';
32
+ import type { ReflectionProbeFact } from '../reflection/projection';
33
+ import type { CameraSnapshot, CubeCameraSnapshot } from '../render-contract';
34
+ import type { SkinPaletteAllocator } from '../systems/skin-palette-allocator';
35
+ import type { SkinPaletteSlice } from '../systems/skin-palette-types';
36
+ import type { RenderTargetTextureSource } from '../targets/contracts';
37
+ import type { ValidatedVolumetricFog } from '../volume/component';
38
+ import type { VolumeProjectorTuple } from '../volume/temporal';
39
+ import type { EnvironmentFrame, FogFrame, FogSelectionFailure } from './environment';
40
+ import type { VisibilitySnapshot } from './visibility';
41
+
42
+ export interface DirectionalLightSnapshot {
43
+ readonly kind: 'directional';
44
+ readonly entity?: EntityHandle;
45
+ readonly direction: Vec3;
46
+ readonly color: Vec3;
47
+ readonly intensity: number;
48
+ }
49
+
50
+ /**
51
+ * PointLightSnapshot — omnidirectional point variant. `position` from the
52
+ * companion Transform; `invRangeSquared = 1 / range^2` host-folded via
53
+ * `computeInvRangeSquared` (range = +Infinity -> 0; range = 0 -> 1e8 NaN
54
+ * protection per D-S5).
55
+ */
56
+ export interface PointLightSnapshot {
57
+ readonly kind: 'point';
58
+ readonly entity?: EntityHandle | number;
59
+ readonly position: Vec3;
60
+ readonly color: Vec3;
61
+ readonly intensity: number;
62
+ readonly invRangeSquared: number;
63
+ /**
64
+ * feat-20260612-point-light-shadows-urp-hdrp M1 / T-M1-8 + M4 / T-M4-4:
65
+ * cube_array atlas layer index for this light's shadow map (0..3 for shadow
66
+ * casters; sentinel `-1` for non-shadow lights). Default `-1` per
67
+ * plan-strategy §D-2 — record stage / shader skips shadow sampling when the
68
+ * lane equals the sentinel. Joined with `pointShadow[]` by entity at the
69
+ * end of extract; HDRP record stage threads `shadowAtlasLayer + shadowNear +
70
+ * shadowFar` through `packLightSlot` as the §D-8 pad-lane payload.
71
+ */
72
+ readonly shadowAtlasLayer?: number;
73
+ /**
74
+ * Per-face perspective near plane (matches `PointLightShadow.nearPlane`).
75
+ * Used by HDRP `evalPointShadowed` for depth-ref reconstruction; rides
76
+ * `LightSlot.kind_and_pad.z` (byte 56..60) on the std430 std layout.
77
+ */
78
+ readonly shadowNear?: number;
79
+ /**
80
+ * Per-face perspective far plane (matches `PointLightShadow.farPlane`).
81
+ * Rides `LightSlot.kind_and_pad.w` (byte 60..64).
82
+ */
83
+ readonly shadowFar?: number;
84
+ }
85
+
86
+ /**
87
+ * PointShadowSnapshot — extract-stage view of one shadow-casting point light
88
+ * (feat-20260612-point-light-shadows-urp-hdrp M1 / T-M1-7).
89
+ *
90
+ * `entity` is the spawning entity (joins PointLight + PointLightShadow on the
91
+ * same archetype); `position` is the light world-space position resolved from
92
+ * the companion Transform (mirrors PointLightSnapshot.position).
93
+ * `shadowMatrices` is the 96-float packed mat4[6] table (column-major,
94
+ * 6 mat4 * 16 floats = 384 bytes) ready for UBO upload.
95
+ *
96
+ * Plan-strategy §D-3: the record stage allocates a dynamic-offset uniform
97
+ * buffer (384 B per-light, aligned to minUniformBufferOffsetAlignment, WebGPU
98
+ * min 256 -> 512 B stride). Extract owns the host-side `Float32Array(96)`;
99
+ * record owns the GPU `RhiBuffer` lifetime.
100
+ *
101
+ * `mapSize` / `nearPlane` / `farPlane` ride here so record stage can size the
102
+ * cube atlas faces and feed shader the proj constants without re-querying ECS.
103
+ * `shadowAtlasLayer` is assigned by extract in spawn order (0 .. cap-1) so the
104
+ * downstream LightSlot / packPointLight packers carry the layer index in
105
+ * pointPadW (T-M1-8 will rename to shadowAtlasLayer).
106
+ */
107
+ export interface PointShadowSnapshot {
108
+ /** Spawning entity index (joins PointLight + PointLightShadow + Transform). */
109
+ readonly entity: number;
110
+ /** World-space light position (sourced from companion Transform). */
111
+ readonly position: Vec3;
112
+ /** PointLightShadow.mapSize (per-face cube square dimension; 512 default). */
113
+ readonly mapSize: number;
114
+ readonly nearPlane: number;
115
+ readonly farPlane: number;
116
+ /**
117
+ * Atlas layer assigned by extract in spawn order (0..cap-1, where cap=4
118
+ * matches PointLightShadow cardinality). Sentinel -1 is reserved by the
119
+ * shader-side LightSlot for no-shadow lights (T-M1-8).
120
+ */
121
+ readonly shadowAtlasLayer: number;
122
+ /**
123
+ * 6 view-proj mat4 in face order [+X, -X, +Y, -Y, +Z, -Z] packed into one
124
+ * Float32Array(96). 16 floats per face = 64 B; 6 * 64 = 384 B raw. The
125
+ * record stage pads each slot to 512 B (256 alignment) when packing into
126
+ * the per-light dynamic-offset UBO (plan-strategy §D-3).
127
+ */
128
+ readonly shadowMatrices: Float32Array;
129
+ }
130
+
131
+ /**
132
+ * SpotLightSnapshot — cone-restricted variant. `position` from companion
133
+ * Transform; `direction` raw outgoing-vector; `cosInner` / `cosOuter` host
134
+ * pre-converted via `degToCos` so the shader sees only cosines (D-S2).
135
+ *
136
+ * feat-20260625-spot-light-shadow-mapping M1 w5: added shadow fields.
137
+ * castShadow (bool) gates shadow projection; lightViewProj is the perspective
138
+ * light-view-projection matrix computed in extract (undefined when castShadow
139
+ * is false, dir degenerates, or the light is clipped). shadowAtlasTile
140
+ * (i32 sentinel -1) is the allocated tile index 0..3 or -1 for unassigned
141
+ * (plan-strategy D-4). mapSize / nearPlane / farPlane are the source
142
+ * component shadow parameters carried through to the record stage.
143
+ */
144
+ export interface SpotLightSnapshot {
145
+ readonly kind: 'spot';
146
+ readonly entity?: EntityHandle | number;
147
+ readonly position: Vec3;
148
+ readonly direction: Vec3;
149
+ readonly color: Vec3;
150
+ readonly intensity: number;
151
+ readonly invRangeSquared: number;
152
+ readonly cosInner: number;
153
+ readonly cosOuter: number;
154
+ readonly iesProfileHandle?: number;
155
+ readonly cookieHandle?: number;
156
+ readonly iesProfileSlice?: number;
157
+ readonly cookieSlice?: number;
158
+ readonly iesProfileData?: Uint8Array;
159
+ readonly cookieData?: Uint8Array;
160
+ readonly cookieMatrix?: Float32Array;
161
+ readonly projectorSlice?: number;
162
+ readonly projectorData?: Uint8Array;
163
+ readonly projectorMatrix?: Float32Array;
164
+ readonly rollDeg?: number;
165
+ // ── shadow fields (feat-20260625-spot-light-shadow-mapping M1) ──
166
+ readonly castShadow: boolean;
167
+ readonly lightViewProj: Float32Array | undefined;
168
+ readonly mapSize: number;
169
+ readonly nearPlane: number;
170
+ readonly farPlane: number;
171
+ readonly shadowAtlasTile: number;
172
+ readonly shadowIntensity?: number;
173
+ readonly depthBias?: number;
174
+ readonly normalBias?: number;
175
+ readonly pcfKernelSize?: number;
176
+ readonly projectorHandle?: Handle<'TextureAsset', 'shared'>;
177
+ readonly projectorAsset?: TextureAsset;
178
+ readonly projectorGuid?: string;
179
+ readonly projectorGeneration?: number;
180
+ readonly projectorRevision?: number;
181
+ }
182
+
183
+ export interface RectAreaDirectLightSnapshot {
184
+ readonly kind: 'rect-area';
185
+ readonly position: Vec3;
186
+ readonly color: Vec3;
187
+ readonly intensity: number;
188
+ readonly invRangeSquared: number;
189
+ readonly halfWidth: number;
190
+ readonly halfHeight: number;
191
+ readonly axisX: Vec3;
192
+ readonly axisY: Vec3;
193
+ readonly shadowAtlasTile?: number;
194
+ }
195
+
196
+ export interface RectAreaWorldFrame {
197
+ readonly center: Vec3;
198
+ readonly axisX: Vec3;
199
+ readonly axisY: Vec3;
200
+ readonly normal: Vec3;
201
+ readonly halfWidth: number;
202
+ readonly halfHeight: number;
203
+ }
204
+
205
+ /**
206
+ * LightSnapshot — discriminated union of the three KHR_lights_punctual
207
+ * variants. AI users + the record stage perform an exhaustive switch on
208
+ * `kind`; missing arms are caught at compile time (no `default`,
209
+ * `assertNever`-style guards). Plan-strategy R-10.
210
+ */
211
+ export type LightSnapshot =
212
+ | DirectionalLightSnapshot
213
+ | PointLightSnapshot
214
+ | SpotLightSnapshot
215
+ | RectAreaDirectLightSnapshot;
216
+
217
+ /**
218
+ * ExtractedLights — three-bucket output of the extractFrame three-query
219
+ * union (M2 / w16 / AC-03). Plan-strategy section 3.1 EXT node:
220
+ * - `directional` — at most one (record-stage N>1 fail-fast lands in M3)
221
+ * - `point[]` — first-slice cap of 4 enforced at record stage (M3)
222
+ * - `spot[]` — first-slice cap of 4 enforced at record stage (M3)
223
+ * `directionalCount` exposes the raw count of DirectionalLight entities the
224
+ * extract observed (so the record stage can fire `render-system-multi-light`
225
+ * when N>1 without re-running the query). M3 / w19 will widen this with
226
+ * pointCount / spotCount fields once the matching record-time fail-fast
227
+ * lands; for M2 the field stays directional-only to keep AC-06 (a) intact.
228
+ */
229
+ export interface ExtractedLights {
230
+ readonly directional: DirectionalLightSnapshot | undefined;
231
+ readonly directionalCount: number;
232
+ readonly point: readonly PointLightSnapshot[];
233
+ readonly spot: readonly SpotLightSnapshot[];
234
+ readonly rect: readonly RectAreaDirectLightSnapshot[];
235
+ /**
236
+ * feat-20260613-csm-cascaded-shadow-maps M2 / w9: per-cascade light-view-
237
+ * projection matrices (one per cascade, length 4 pre-allocated). Each matrix
238
+ * is a column-major 16-float mat4 with atlas tile UV inset baked in
239
+ * (plan-strategy D-3). cascadeCount < 4: unused slots are zero matrices.
240
+ * Undefined when castShadow=false or no directional light.
241
+ */
242
+ readonly lightViewProj: readonly Float32Array[] | undefined;
243
+ /**
244
+ * feat-20260613-csm-cascaded-shadow-maps M2 / w9: view-space z depths
245
+ * of the PSSM split planes (length 4, Float32Array). cascadeCount < 4:
246
+ * unused slots are 0.0f. Undefined when castShadow=false or no directional
247
+ * light.
248
+ */
249
+ readonly splitPlanes: Float32Array | undefined;
250
+ /**
251
+ * feat-20260613-csm-cascaded-shadow-maps M2 / w9: effective cascade count
252
+ * from the DirectionalLight component (1..4). Undefined when castShadow=false
253
+ * or no directional light.
254
+ */
255
+ readonly cascadeCount: number | undefined;
256
+ /**
257
+ * feat-20260613-csm-cascaded-shadow-maps M2 / w9: cascade blend width
258
+ * from the DirectionalLight component (0..0.5). Undefined when castShadow=false
259
+ * or no directional light.
260
+ */
261
+ readonly cascadeBlend: number | undefined;
262
+ /**
263
+ * feat-20260520-directional-light-shadow-mapping M1c / w8:
264
+ * shadowMapSize from DirectionalLight.mapSize. Drives shadow RT
265
+ * lazy-allocate (idempotency: same size -> no rebuild). Undefined when
266
+ * castShadow=false or no directional light.
267
+ */
268
+ readonly shadowMapSize: number | undefined;
269
+ /**
270
+ * feat-20260621-merge-directionallightshadow-into-directionallight M2:
271
+ * depthBias from the merged DirectionalLight (constant shadow-bias floor).
272
+ * Populated when castShadow=true on the first-hit directional light;
273
+ * undefined otherwise.
274
+ */
275
+ readonly depthBias: number | undefined;
276
+ /**
277
+ * feat-20260621-merge-directionallightshadow-into-directionallight M2:
278
+ * normalBias from the merged DirectionalLight (slope-based shadow-bias
279
+ * coefficient).
280
+ * Populated when castShadow=true on the first-hit directional light;
281
+ * undefined otherwise.
282
+ */
283
+ readonly normalBias: number | undefined;
284
+ /**
285
+ * feat-20260621-merge-directionallightshadow-into-directionallight M2:
286
+ * pcfKernelSize from the merged DirectionalLight (PCF kernel width, odd>=1).
287
+ * Populated when castShadow=true on the first-hit directional light;
288
+ * undefined otherwise.
289
+ */
290
+ readonly directionalShadowQuality: DirectionalShadowQuality | undefined;
291
+ readonly directionalShadowError: LightValidationError | undefined;
292
+ /**
293
+ * feat-20260612-point-light-shadows-urp-hdrp M1 / T-M1-7:
294
+ * shadow-casting point lights (PointLight + PointLightShadow + Transform
295
+ * archetype join). Each entry carries the per-light 6-face VP matrices and
296
+ * the assigned cube_array atlas layer (0..3 in spawn order; sentinel -1 is
297
+ * reserved by the shader-side LightSlot for no-shadow point lights).
298
+ *
299
+ * Empty array when no PointLightShadow components exist (zero-cost gate per
300
+ * AC-09; record stage skips atlas allocation + shadow pass dispatch).
301
+ */
302
+ readonly pointShadow: readonly PointShadowSnapshot[];
303
+ /**
304
+ * bug-20260710-editor-cross-world-shadow: the RAW directional-shadow config
305
+ * (cascadeCount / splitLambda / cascadeBlend / mapSize / shadowDistance) of
306
+ * the first-hit castShadow DirectionalLight, carried unconditionally of
307
+ * whether this world had a camera. The {@link extractFrames} merge layer
308
+ * re-runs {@link computeDirectionalCsm} with this config + the surfaced
309
+ * camera so directional shadows work when the light and camera live in
310
+ * DIFFERENT worlds (editor editorWorld/sceneWorld super-composite). Undefined
311
+ * when castShadow=false or no directional light. The `lightViewProj` /
312
+ * `splitPlanes` fields above remain the *computed* per-world outputs (correct
313
+ * for single-world; recomputed at merge for cross-world).
314
+ */
315
+ readonly directionalCsmConfig: DirectionalCsmConfig | undefined;
316
+ /**
317
+ * bug-20260710-editor-cross-world-shadow: the light-direction of the
318
+ * first-hit castShadow DirectionalLight, carried so the merge layer can
319
+ * rebuild the light-view matrix. Redundant with `directional.direction` but
320
+ * kept explicit so the CSM recompute reads a single config bundle. Undefined
321
+ * when castShadow=false or no directional light.
322
+ */
323
+ readonly directionalCsmDirection: Vec3 | undefined;
324
+ }
325
+
326
+ /**
327
+ * SkylightSnapshot -- extract-stage view of one Skylight entity
328
+ * (feat-20260520-skylight-ibl-cubemap M4 / t26).
329
+ *
330
+ * `equirectHandle` carries the packed u32 handle for
331
+ * `Handle<EquirectAsset, 'shared'>`; the record stage drives the internal
332
+ * lazy cubemap projection from it and resolves the projected GPU cubemap via
333
+ * `GpuResidencyCache.getCubemapGpuView(...)` and related helpers
334
+ * (feat-20260630 M3 / w16-w18). The snapshot carries NO projection status
335
+ * field: the status truth lives in the store's CubemapGpuEntry (D-3 SSOT);
336
+ * record queries it once per frame.
337
+ *
338
+ * `intensity` defaults to 1.0 via the Skylight component token defaults
339
+ * (plan-strategy D-6: Skylight data flows through existing extract->record
340
+ * pipeline; no independent ECS system).
341
+ */
342
+ export interface SkylightSnapshot {
343
+ // 0 = no equirect supplied -> solid-color ambient via the white fallback
344
+ // cube (record falls to fallback resources when no IBL views are cached).
345
+ readonly equirectHandle: number;
346
+ readonly color: readonly [number, number, number];
347
+ readonly intensity: number;
348
+ /** Environment-space quaternion [x, y, z, w], identity by default. */
349
+ readonly rotation: readonly [number, number, number, number];
350
+ // feat-20260630 M3 / w19: the WINNING Skylight entity's packed handle (first
351
+ // archetype hit). Carried so the multi-Skylight once-warn can name which
352
+ // entity is used and which is ignored (F-8: warn carries conflicting entity
353
+ // info). 0 only if the bundle had no live entity (never happens for a hit).
354
+ readonly entityHandle: number;
355
+ }
356
+
357
+ /**
358
+ * SkyboxSnapshot -- extract-stage view of one SkyboxBackground entity
359
+ * (feat-20260531-skybox-env-background M2 / w5).
360
+ *
361
+ * `equirectHandle` carries the packed u32 handle for
362
+ * `Handle<EquirectAsset, 'shared'>`; the record stage resolves the projected
363
+ * GPU cubemap via `GpuResidencyCache.getCubemapGpuView(...)`.
364
+ *
365
+ * `mode` carries the raw `f32` column value (`SKYBOX_MODE_CUBEMAP = 0`).
366
+ * First hit wins per plan-strategy D-6; multi-entity once-warn in record stage.
367
+ */
368
+ export interface SkyboxSnapshot {
369
+ readonly equirectHandle: number;
370
+ readonly mode: number;
371
+ /** Environment-space quaternion [x, y, z, w], identity by default. */
372
+ readonly rotation: readonly [number, number, number, number];
373
+ // feat-20260630 M3 / w19: the WINNING SkyboxBackground entity's packed handle
374
+ // (first archetype hit), so the multi-SkyboxBackground once-warn can name the
375
+ // used entity (F-8 parity with the Skylight warn).
376
+ readonly entityHandle: number;
377
+ }
378
+
379
+ export interface LightProbeSnapshot {
380
+ readonly identity: string;
381
+ readonly position: readonly [number, number, number];
382
+ readonly radius: number;
383
+ readonly irradiance: Float32Array;
384
+ readonly admitted: boolean;
385
+ }
386
+
387
+ export interface ExtractedVolumetricFog {
388
+ readonly status: 'off' | 'available' | 'degraded';
389
+ readonly fog?: ValidatedVolumetricFog;
390
+ readonly densityHandle?: Handle<'TextureAsset', 'shared'>;
391
+ readonly densityAsset?: TextureAsset;
392
+ readonly guid?: string;
393
+ readonly generation?: number;
394
+ readonly digest?: string;
395
+ readonly worldId?: number;
396
+ readonly lightEntity?: EntityHandle;
397
+ readonly lightKind?: 'directional' | 'point' | 'spot';
398
+ readonly pointLightEntity?: EntityHandle;
399
+ readonly spotLightEntity?: EntityHandle;
400
+ readonly projector?: VolumeProjectorTuple;
401
+ readonly projectorHandle?: Handle<'TextureAsset', 'shared'>;
402
+ readonly projectorAsset?: TextureAsset;
403
+ }
404
+
405
+ export interface RenderableSnapshot {
406
+ readonly assetHandle: number;
407
+ readonly transform: TransformSnapshot;
408
+ readonly lods?: readonly MeshLodLevel[];
409
+ readonly lodHysteresis?: number;
410
+ /** Finite producer-owned local bounds retained for persistent CPU view work. */
411
+ readonly localAabb?: Float32Array;
412
+ /** Indexed single-submesh facts consumed by the first GPU-driven rigid lane. */
413
+ readonly gpuDrivenDraws?: readonly GpuDrivenDrawSnapshot[];
414
+ /**
415
+ * feat-20260608 M5 amend / w11-a: the entity's representative (first)
416
+ * material snapshot, kept as a same-name shorthand for `materials[0]`.
417
+ * Per-entity dispatch (shading model routing, sprite-vs-mesh split, the
418
+ * D-1/D-3 pipeline-tag pick) is uniform across the entity's submeshes
419
+ * today, so the existing 20+ `entry.source.material.X` consumers in the
420
+ * record stage stay unchanged. Per-submesh material data (baseColor /
421
+ * UBO payload / paramSnapshot) lives in `materials[i]`.
422
+ */
423
+ readonly material: MaterialSnapshot;
424
+ /**
425
+ * feat-20260608 M5 amend / w11-a: per-submesh MaterialSnapshot[]
426
+ * positionally aligned with `MeshAsset.submeshes[]` (plan §3.2 sequence
427
+ * step 6 + AC-08). Length always equals the entity's submesh count once
428
+ * the extract stage's count-mismatch validator (M2 / w12) has filtered
429
+ * misaligned spawns. The record stage reads `materials[i]` to upload the
430
+ * i-th material UBO slot before drawing the i-th submesh.
431
+ *
432
+ * Backward-compat: `materials[0] === material` (the legacy mid-grey
433
+ * default-material case-B path also routes through `materials = [default]`,
434
+ * keeping the legacy single-mesh-no-material spawn shape working without
435
+ * a special branch in record).
436
+ */
437
+ readonly materials: readonly MaterialSnapshot[];
438
+ /** Per-slot provenance trace from the shared mesh-material resolver. */
439
+ readonly materialBindingSources: readonly MeshMaterialBindingSource[];
440
+ /** Active structured override diagnostics for this renderable. */
441
+ readonly materialBindingDiagnostics?: readonly MeshMaterialBindingDiagnostic[];
442
+ /**
443
+ * feat-20260708-composited-multi-world-rendering M1 / D-1: the worldId
444
+ * of the world this renderable was extracted from. Defaults to 0 in
445
+ * single-world path (extractFrame always assigns 0). The merge layer
446
+ * (extractFrames in M2) stamps the correct worldId per world before
447
+ * the record stage consumes it. Combined with `entityKey` via
448
+ * `worldEntityKey(worldId, entityKey)` to form per-entity cache keys.
449
+ *
450
+ * Never rewrite `entityKey` itself — consumers that need the real
451
+ * entity handle (video provider, etc.) read the bare `entityKey`.
452
+ */
453
+ readonly worldId: number;
454
+ /**
455
+ * feat-20260531-per-frame-bind-group-cache M1 / w3: packed Entity u32
456
+ * (encodeEntity(indexSlot, generation)) surface'd from the extract
457
+ * stage. Stable per-entity identity for the record stage cache keys
458
+ * (material / instances / per-frame clean-up) without re-querying the
459
+ * World (charter P5 Pipeline Isolation: record stage only consumes
460
+ * snapshot POD). Reuses the encodeEntity calculation already performed
461
+ * at :1293 for the Instances path, and now also computed for plain
462
+ * (non-Instances) renderables.
463
+ *
464
+ * Never rewrite this field — cache keys use `worldEntityKey(worldId, entityKey)`,
465
+ * not the bare entityKey alone (D-1).
466
+ */
467
+ readonly entityKey: number;
468
+ /**
469
+ * feat-20260514 M3 (w15): when the entity carries an `Instances` component
470
+ * the extract stage materialises a fresh `Float32Array` snapshot of the
471
+ * packed mat4 transforms (16 f32 per instance, stride 16) plus a stable
472
+ * `cacheKey` (the entity's packed u32) and the `archVersion` (used by the
473
+ * record stage to invalidate its per-entity GPU buffer cache when the
474
+ * archetype storage grew). Absent (`undefined`) means the record stage
475
+ * falls back to the shared 1-element identity-mat4 storage buffer +
476
+ * `drawIndexed(.., 1, ..)`.
477
+ */
478
+ readonly instances?: InstancesSnapshot;
479
+ /**
480
+ * feat-20260625-sprite-instances-and-tilemap-terrain-static-batch M3 / w10
481
+ * (plan-strategy D-1 + D-9): when the entity carries a `SpriteInstances`
482
+ * component the extract stage materialises a paired snapshot — packed mat4
483
+ * `transforms` (16 f32, stride 16) + per-instance UV `regions` (4 f32,
484
+ * stride 4) — plus the same cache fingerprint pair (`cacheKey` = entity
485
+ * packed u32, `archVersion` = archetype version stamp at snapshot time).
486
+ * The record stage interleaves the two arrays into an 80B-per-instance
487
+ * single GPU buffer routed through `@group(3) @binding(0)` (BGL unchanged,
488
+ * D-1). Absent (`undefined`) means the entity is not a `SpriteInstances`
489
+ * carrier; the record stage falls back to its existing sprite path
490
+ * (material UBO region + identity-instance buffer).
491
+ *
492
+ * Three structured `EcsError` codes fire at extract entry and skip the
493
+ * renderable on violation (charter P3 explicit failure):
494
+ * - `'sprite-instances-mutually-exclusive-with-instances'`
495
+ * - `'sprite-instances-requires-sprite-shading-model'`
496
+ * - `'sprite-instances-count-mismatch'`
497
+ */
498
+ readonly spriteInstances?: SpriteInstancesSnapshot;
499
+ /**
500
+ * feat-20260523-skin-skeleton-animation M2 / T-21: when the entity carries
501
+ * a `Skin` component the extract stage populates this field with the
502
+ * skin palette slice metadata. The record stage uses this to route the
503
+ * draw to `forgeax::pbr-skin` pipeline + set the palette dynamic offset.
504
+ * Absent (`undefined`) means the entity is not skinned.
505
+ */
506
+ readonly skin?: SkinPaletteSlice;
507
+ /**
508
+ * ECS-owned morph weights. Presence selects the Standard Pipeline CPU
509
+ * specialized deformation lane; the asset remains the source of target
510
+ * deltas and the record stage only receives this frozen POD snapshot.
511
+ */
512
+ readonly morph?: MorphSnapshot;
513
+ /** Renderer-owned previous-frame facts attached during temporal projection. */
514
+ readonly temporal?: RenderableTemporalSnapshot;
515
+ /** Detached M2 authoring facts for the optional Points/Lines projection. */
516
+ readonly pointsLines?: PointsLinesRetainedSnapshot;
517
+ readonly probeBlendRecord?: import('../scene/probe-blend-record').ProbeBlendRecord;
518
+ }
519
+
520
+ export type RenderablePreviousSource = 'last-submitted' | 'current-seed';
521
+ export type RenderableReactiveReason =
522
+ | 'new-slot'
523
+ | 'generation-reuse'
524
+ | 'reentered'
525
+ | 'geometry-revision'
526
+ | 'material-revision'
527
+ | 'skinning-deformation'
528
+ | 'morph-deformation';
529
+ export interface RenderableTemporalSnapshot {
530
+ readonly previousEpoch: number | undefined;
531
+ readonly previousSource: RenderablePreviousSource;
532
+ readonly reactive: boolean;
533
+ readonly reactiveReasons: readonly RenderableReactiveReason[];
534
+ readonly previousTransform: TransformSnapshot;
535
+ readonly previousInstances: InstancesSnapshot | undefined;
536
+ readonly previousSkin: SkinPaletteSlice | undefined;
537
+ readonly previousMorphWeights: Float32Array | undefined;
538
+ }
539
+
540
+ export interface MorphSnapshot {
541
+ readonly weights: Float32Array;
542
+ readonly targetCount: number;
543
+ }
544
+
545
+ export interface GpuDrivenDrawSnapshot {
546
+ readonly kind: 'indexed' | 'non-indexed';
547
+ readonly first: number;
548
+ readonly count: number;
549
+ readonly baseVertex: number;
550
+ readonly materialSlot: number;
551
+ readonly topology: PrimitiveTopology;
552
+ readonly pipelineClass: string;
553
+ readonly materialResourceClass: string;
554
+ readonly projectedHeight?: number;
555
+ readonly lodRanges?: readonly {
556
+ readonly first: number;
557
+ readonly count: number;
558
+ readonly baseVertex: number;
559
+ }[];
560
+ }
561
+
562
+ export interface InstancesSnapshot {
563
+ /** Packed column-major mat4 transforms (16 f32 per instance). */
564
+ readonly transforms: Float32Array;
565
+ /** Number of instances (transforms.length / 16). */
566
+ readonly instanceCount: number;
567
+ /** Stable per-entity GPU buffer cache key (the packed Entity u32). */
568
+ readonly cacheKey: number;
569
+ /**
570
+ * Archetype version stamp at snapshot time. The record stage compares this
571
+ * against its cached version per cacheKey; a bump means the underlying
572
+ * BufferPool slot may have grown / been reallocated, forcing a fresh
573
+ * `device.createBuffer + queue.writeBuffer` round.
574
+ */
575
+ readonly archVersion: number;
576
+ }
577
+
578
+ /**
579
+ * feat-20260625-sprite-instances-and-tilemap-terrain-static-batch M3 / w10:
580
+ * extract-stage view of a `SpriteInstances` carrier (2D peer of
581
+ * `InstancesSnapshot`).
582
+ *
583
+ * Field shapes mirror `InstancesSnapshot` so the record-stage cache protocol
584
+ * (`(cacheKey, archVersion, byteLength)` fingerprint triple) is reused
585
+ * verbatim. The byte length consumed at upload time is the sum
586
+ * `transforms.byteLength + regions.byteLength` (= 80*N for N instances,
587
+ * plan-strategy D-1 interleaved single-buffer); the record stage builds the
588
+ * 80B/instance interleaved buffer once per (entity, archVersion, byteLength)
589
+ * fingerprint change.
590
+ */
591
+ export interface SpriteInstancesSnapshot {
592
+ /** Packed column-major mat4 transforms (16 f32 per instance, stride 16). */
593
+ readonly transforms: Float32Array;
594
+ /** Per-instance UV vec4 regions (4 f32 per instance, stride 4). */
595
+ readonly regions: Float32Array;
596
+ /**
597
+ * Number of instances. Derived from `transforms.length / 16` (equivalently
598
+ * `regions.length / 4`); the extract-entry validator guarantees the two
599
+ * derivations agree, otherwise it fires
600
+ * `'sprite-instances-count-mismatch'` and skips the renderable.
601
+ */
602
+ readonly instanceCount: number;
603
+ /** Stable per-entity GPU buffer cache key (the packed Entity u32, D-9). */
604
+ readonly cacheKey: number;
605
+ /** Archetype version stamp at snapshot time (cache invalidation fingerprint). */
606
+ readonly archVersion: number;
607
+ }
608
+
609
+ /**
610
+ * TransformSnapshot: extract-stage view of one entity's resolved world
611
+ * transform (feat-20260601 D-3). Holds the single `world` mat4 (column-major
612
+ * 16 floats, copied from the entity's `Transform.world` view written by
613
+ * propagateTransforms). The record stage copies these 16 floats straight into
614
+ * the mesh SSBO slot (zero `mat4.compose`); position / scale consumers derive
615
+ * from the mat4 via `mat4.getTranslation` / basis-column lengths.
616
+ */
617
+ export interface TransformSnapshot {
618
+ readonly world: Float32Array;
619
+ }
620
+
621
+ /**
622
+ * MaterialSnapshot: extract-stage view of one entity's material asset (M2 / w6
623
+ * of feat-20260517-merge-mesh-renderer-material-renderer; plan-strategy section 2.3).
624
+ *
625
+ * Adds optional `baseColorTexture` + `sampler` slots (consumed by the record
626
+ * stage's textured-material code path; M3 / w10 dropped the cast-over-firstMaterial
627
+ * pattern in favour of direct snapshot field reads).
628
+ *
629
+ * feat-20260522-learn-render-3-1-sponza-model-loading-with-multi-l M4 extends
630
+ * the snapshot with `metallicRoughnessTexture` and `normalTexture`
631
+ * so the record stage can wire PBR texture bindings 4 and 6
632
+ * from real GPU views instead of placeholder 1x1 white / flat-normal views.
633
+ *
634
+ * Bounded scope: the snapshot tracks only what the record stage actually
635
+ * consumes today (charter proposition 5 consistent abstraction; YAGNI for
636
+ * future-proof field bloat). Future MaterialAsset extensions (emissive / etc)
637
+ * drive snapshot extensions when the record stage starts consuming them, not
638
+ * vice-versa.
639
+ *
640
+ * tweak-20260701 M1: `shadingModel` field removed — shader identity via
641
+ * {@link materialShaderId} is the single source of truth for material dispatch.
642
+ */
643
+ export interface MaterialSnapshot {
644
+ readonly baseColor: Vec3;
645
+ readonly metallic: number;
646
+ readonly roughness: number;
647
+ readonly clearcoat?: number | undefined;
648
+ readonly clearcoatRoughness?: number | undefined;
649
+ /** Authored Standard PBR specular tint in linear runtime color space. */
650
+ readonly specularTint?: readonly [number, number, number] | undefined;
651
+ /**
652
+ * Schema-driven material shader identifier (feat-20260523 M4-T05).
653
+ * Populated when the material asset uses the schema-driven path
654
+ * (payload.materialShader set). Undefined for unlit/sprite legacy
655
+ * materials and for case-B defaultMaterialSnapshot.
656
+ *
657
+ * The record stage uses this as the pipeline cache key first-level
658
+ * discriminator (M4-T06).
659
+ */
660
+ readonly materialShaderId?: string | undefined;
661
+ /**
662
+ * Stable source handle for the material asset. Record uses this only for
663
+ * same-frame assembly reuse; GPU bind-group validity still comes from the
664
+ * resource-identity cache.
665
+ */
666
+ readonly materialHandle?: number | undefined;
667
+ /**
668
+ * The selected forward-pass state for this exact material. A mesh can bind
669
+ * different materials to its submeshes, so pipeline selection must read the
670
+ * state from the submesh snapshot rather than the entity's first material.
671
+ */
672
+ readonly renderState?: MaterialRenderState | undefined;
673
+ /**
674
+ * Schema-driven parameter snapshot (feat-20260523 M4-T05).
675
+ * Populated alongside materialShaderId. Maps param name to its
676
+ * runtime-resolved value: number for scalar params, number[] for
677
+ * vec/color params, string (GUID) for texture2d/sampler params.
678
+ */
679
+ readonly paramSnapshot?: Readonly<Record<string, number | number[] | string>> | undefined;
680
+ /** Effective MaterialAsset parameter contract used to lay out this snapshot. */
681
+ readonly materialParamSchema?: readonly ParamSchemaEntry[] | undefined;
682
+ /** Authored per-slot UV set and KHR texture transform metadata. */
683
+ readonly textureCoordinates?: ReadonlyMap<string, MaterialTextureCoordinates> | undefined;
684
+ /**
685
+ * User-region texture handles keyed by paramSchema field name
686
+ * (feat-20260621-learn-render-5-5-parallax M2 / w7). The SSOT carrier for
687
+ * EVERY texture the shader's `derive(paramSchema).textureFieldNames`
688
+ * declares — `baseColorTexture` / `metallicRoughnessTexture` /
689
+ * `normalTexture` for built-in standard-PBR, plus each custom field such as
690
+ * `heightTexture` (LO 5.5 parallax). The record stage iterates this map to
691
+ * assemble the user-region bind group per the per-shader BGL (w8), so a 4th
692
+ * (or Nth) texture flows end-to-end without a hardcoded field list.
693
+ *
694
+ * Populated by iterating `textureFieldNames`; absent keys mean the
695
+ * paramValue was missing / mis-typed (record falls back to default white).
696
+ * `emissiveTexture` / `occlusionTexture` are included here as ordinary
697
+ * Standard user-region fields; the production layout does not duplicate
698
+ * them in a lightmap injection region.
699
+ */
700
+ readonly textureHandles?: ReadonlyMap<string, Handle<'TextureAsset', 'shared'>> | undefined;
701
+ readonly textureSources?: ReadonlyMap<string, RenderTargetTextureSource> | undefined;
702
+ /**
703
+ * User-region texture field names whose paramValue resolved to a VideoAsset
704
+ * (kind `'video'`) rather than a static TextureAsset
705
+ * (feat-20260623-world-space-video-asset M4 / w14, D-5). The video GUID
706
+ * occupies the same texture2d values slot a static texture would (P4:
707
+ * one binding shape), but extract routes it here instead of `textureHandles`
708
+ * so the record stage pulls the current-frame view from the transient
709
+ * DynamicTextureStore (D-3) instead of `GpuResidencyCache.ensureResident`
710
+ * (which has no `video` arm; AC-08). Each entry also carries the resolved
711
+ * clip handle so the record stage can key the per-frame upload.
712
+ *
713
+ * Producer/consumer split (charter P5 / AC-07 gate): extract owns the
714
+ * asset->snapshot translation; record consumes this POD field only — it never
715
+ * reaches back into the MaterialAsset to learn a field is video-sourced.
716
+ */
717
+ readonly videoTextureFields?: ReadonlyMap<string, Handle<'VideoAsset', 'shared'>> | undefined;
718
+ /** Authored sampler handles keyed by their matching texture parameter. */
719
+ readonly samplerHandles?: ReadonlyMap<string, Handle<'SamplerAsset', 'shared'>> | undefined;
720
+ readonly baseColorTexture?: Handle<'TextureAsset', 'shared'> | undefined;
721
+ /**
722
+ * PBR metallic-roughness texture handle (present for PBR/sprite/skin
723
+ * shaders). Undefined for the default-unlit shader
724
+ * (materialShaderId === 'forgeax::default-unlit'). The record stage reads
725
+ * this to write GPU view at material bind-group binding 4, falling
726
+ * back to a 1x1 white placeholder when undefined.
727
+ *
728
+ * feat-20260522-learn-render-3-1-sponza-model-loading-with-multi-l M4:
729
+ * field added so the record stage can wire real metallic-roughness
730
+ * textures from Sponza glTF materials (M3 writes the handle into
731
+ * SchemaDrivenMaterialAsset values; M4 extract carries it through to the snapshot).
732
+ */
733
+ readonly metallicRoughnessTexture?: Handle<'TextureAsset', 'shared'> | undefined;
734
+ /**
735
+ * PBR tangent-space normal texture handle (present for PBR/sprite/skin
736
+ * shaders). Undefined for the default-unlit shader
737
+ * (materialShaderId === 'forgeax::default-unlit'). The record stage reads
738
+ * this to write GPU view at material bind-group binding 6, falling
739
+ * back to a (0.5,0.5,1.0) flat-normal placeholder when undefined.
740
+ *
741
+ * feat-20260522-learn-render-3-1-sponza-model-loading-with-multi-l M4:
742
+ * field added symmetrically with metallicRoughnessTexture so the record
743
+ * stage can wire real normal textures from Sponza glTF materials.
744
+ */
745
+ readonly normalTexture?: Handle<'TextureAsset', 'shared'> | undefined;
746
+ /** Scalar applied to tangent-space normal XY after the normal texture sample. */
747
+ readonly normalScale?: number | undefined;
748
+ readonly emissive?: readonly [number, number, number] | undefined;
749
+ readonly emissiveIntensity?: number | undefined;
750
+ readonly emissiveTexture?: Handle<'TextureAsset', 'shared'> | undefined;
751
+ readonly occlusionTexture?: Handle<'TextureAsset', 'shared'> | undefined;
752
+ readonly occlusionStrength?: number | undefined;
753
+ /**
754
+ * Transparent composition flag derived from the first pass's
755
+ * `renderState.blend` presence on the underlying
756
+ * {@link MaterialPass} (feat-20260626-collapse M2: blend
757
+ * presence is the SSOT after `MaterialPass.transparent` was
758
+ * dropped in M1).
759
+ *
760
+ * The record stage reads this to drive both the LDR split-pass
761
+ * decision and the premultiplied-alpha blend resolution on the
762
+ * generic materialShaderId pipeline path — shader-agnostic, decoupled
763
+ * from the legacy `shadingModel` discriminant (feat-20260625 M2 D-3,
764
+ * finalised in w15; `shadingModel` field removed in tweak-20260701 M1).
765
+ *
766
+ * Extract derives this from the first pass's `renderState.blend !==
767
+ * undefined` (post-feat-20260626-collapse: blend presence is the
768
+ * single SSOT for "this material is transparent on the geometry
769
+ * pipeline cache key"). Multi-pass materials whose mix of opaque +
770
+ * transparent passes need finer routing should split into separate
771
+ * MaterialAsset entries (the normal forgeax pattern).
772
+ *
773
+ * Type is `boolean | undefined` (derived): `undefined` means "no
774
+ * passes / unknown"; consumers must read `=== true` / `!== true` to
775
+ * stay correct under both populated and absent cases.
776
+ */
777
+ readonly transparent?: boolean | undefined;
778
+ }
779
+
780
+ export interface MaterialCacheChainIdentity {
781
+ readonly asset: MaterialAsset;
782
+ readonly parentGuid: string | undefined;
783
+ }
784
+
785
+ export interface MaterialSnapshotCacheEntry {
786
+ readonly snapshot: MaterialSnapshot;
787
+ readonly passes: readonly MaterialPass[];
788
+ /** Root/chain identities are present only on cross-frame-safe entries. */
789
+ readonly chain?: readonly MaterialCacheChainIdentity[];
790
+ /** AssetRegistry epoch at which the root/parent chain was last validated. */
791
+ readonly catalogEpoch?: number;
792
+ /** True only when every object reachable from the authored chain is frozen. */
793
+ readonly crossFrameSafe: boolean;
794
+ }
795
+
796
+ export type MaterialSnapshotCache = Map<number, MaterialSnapshotCacheEntry>;
797
+ export type MaterialSnapshotCachesByWorld = WeakMap<World, MaterialSnapshotCache>;
798
+
799
+ // === DispatchEntry — M3 / w26 single dispatch list (feat-20260526-material-asset-multipass-renderstate) ===
800
+ //
801
+ // Plan-strategy D-3: single dispatch list sorted by queue value,
802
+ // replacing the old three-bucket opaque/transparent/overlay dispatch.
803
+ // Each entry carries the per-pass render-state and entry-point
804
+ // data from the resolved MaterialPass so the record stage
805
+ // reads them without re-resolving the material.
806
+
807
+ export interface DispatchEntry {
808
+ readonly entityIndex: number;
809
+ readonly materialHandle: number;
810
+ readonly renderableIndex: number;
811
+ readonly passIndex: number;
812
+ readonly queue: number;
813
+ /**
814
+ * Signed i32 from the entity's {@link Layer} component value (default 0 for
815
+ * entities without a Layer). Primary sort key for the transparent-dispatch
816
+ * sort in {@link render-system.ts}: lower value = drawn first (behind).
817
+ */
818
+ readonly layer: number;
819
+ readonly tags: Record<string, string>;
820
+ readonly renderState: MaterialRenderState | undefined;
821
+ readonly defines: Record<string, string> | undefined;
822
+ readonly vertexEntry: string | undefined;
823
+ readonly fragmentEntry: string | undefined;
824
+ readonly materialShaderId: string | undefined;
825
+ readonly paramSnapshot: Readonly<Record<string, number | number[] | string>> | undefined;
826
+ /**
827
+ * Stencil reference value from {@link MaterialPass.stencilReference}
828
+ * (draw-call dynamic state). Folded during extract for per-draw consumption
829
+ * in the record stage. `undefined` when the pass does not set a reference
830
+ * value (record stage falls back to WebGPU default 0).
831
+ */
832
+ readonly stencilReference?: number;
833
+ }
834
+
835
+ export interface ExtractedFrame {
836
+ readonly cameras: CameraSnapshot[];
837
+ readonly auxiliaryCameras: readonly CameraSnapshot[];
838
+ readonly cubeCameras: readonly CubeCameraSnapshot[];
839
+ readonly reflectionProbes?: readonly ReflectionProbeFact[];
840
+ readonly lights: ExtractedLights;
841
+ /** Resource-owner environment facts selected once at the extract boundary. */
842
+ readonly environment: EnvironmentFrame | undefined;
843
+ /** False when the resource-owner world failed environment/fog selection. */
844
+ readonly environmentReady: boolean;
845
+ readonly volumetricFog?: ExtractedVolumetricFog;
846
+ readonly renderables: RenderableSnapshot[];
847
+ /**
848
+ * Single dispatch list sorted by queue value (ascending, stable sort).
849
+ * Replaces the old opaqueDispatch / transparentDispatch / overlayDispatch
850
+ * three-bucket model per plan-strategy D-3.
851
+ */
852
+ readonly dispatch: DispatchEntry[];
853
+ readonly skylight: SkylightSnapshot | undefined;
854
+ readonly skylightCount: number;
855
+ readonly lightProbes?: readonly LightProbeSnapshot[];
856
+ readonly skybox: SkyboxSnapshot | undefined;
857
+ readonly skyboxCount: number;
858
+ /** Resource-owner Fog facts selected once at the frame boundary. */
859
+ readonly fog: FogFrame | undefined;
860
+ readonly fogFailure?: FogSelectionFailure;
861
+ /**
862
+ * feat-20260528-frustum-culling M3 / w11: frustum culling statistics
863
+ * collected during the extract phase. `total` is the count of entities
864
+ * that reached the culling decision point; `culled` is the count of
865
+ * those that were removed from renderables by frustum culling.
866
+ */
867
+ readonly frustumStats: { readonly culled: number; readonly total: number };
868
+ /** Candidate entities rejected by author visibility before resource parsing. */
869
+ readonly visibilityStats: { readonly explicitlyHidden: number };
870
+ /**
871
+ * Per-frame post-process params snapshot collected from PostProcessParams
872
+ * entities (D-1: data-driven params channel). Maps shader id to the
873
+ * raw data bytes (Uint8Array = FieldValueType<'buffer'>). Last-one-wins
874
+ * when multiple entities bear the same shader id.
875
+ * Empty map when no PostProcessParams entities exist.
876
+ */
877
+ readonly postProcessParams: ReadonlyMap<string, Uint8Array>;
878
+ /** Visibility snapshots prepared for each contributing World. */
879
+ readonly visibilitySnapshots: readonly VisibilitySnapshot[];
880
+ /** World-labelled snapshots passed to generic RenderFeature extraction. */
881
+ readonly featureVisibilitySnapshots: readonly RenderFeatureWorldVisibilitySnapshot[];
882
+ /** Built-in hidden candidates, retained for host-side producer deduplication. */
883
+ readonly hiddenEntityReports: readonly RenderFeatureHiddenEntityReport[];
884
+ }
885
+
886
+ /**
887
+ * feat-20260612-skin-palette-per-frame-upload M2 / m2-6: narrow per-frame
888
+ * pipeline surface consumed by `extractFrame`. Today only `skinPaletteAllocator`
889
+ * crosses the seam (the allocator owns the per-frame palette buffer + cursor;
890
+ * extract calls `resetForFrame` at frame entry then `allocateSlice` +
891
+ * `writeJointPalette` per skinned entity). Kept narrow on purpose — extract
892
+ * does NOT see the rest of `PipelineState` to avoid a circular import via
893
+ * `render-system.ts`.
894
+ */
895
+ export interface ExtractPipelineSurface {
896
+ readonly skinPaletteAllocator: SkinPaletteAllocator | null;
897
+ }
898
+
899
+ /**
900
+ * bug-20260710-editor-cross-world-shadow: the camera-frustum subset of
901
+ * {@link CameraSnapshot} that the directional-CSM matrix builder consumes.
902
+ */
903
+ export interface CsmCameraData {
904
+ readonly world: Float32Array;
905
+ readonly fov: number;
906
+ readonly aspect: number;
907
+ readonly near: number;
908
+ readonly far: number;
909
+ readonly projection: 'perspective' | 'orthographic';
910
+ readonly orthoLeft: number;
911
+ readonly orthoRight: number;
912
+ readonly orthoBottom: number;
913
+ readonly orthoTop: number;
914
+ }
915
+
916
+ /**
917
+ * bug-20260710-editor-cross-world-shadow: the raw directional-shadow config a
918
+ * DirectionalLight carries, threaded onto {@link ExtractedLights} so the merge
919
+ * layer can recompute CSM matrices against the surfaced camera. Distinct from
920
+ * the *computed* outputs (lightViewProj / splitPlanes) also on ExtractedLights.
921
+ */
922
+ export interface DirectionalCsmConfig {
923
+ readonly cascadeCount: number;
924
+ readonly splitLambda: number;
925
+ readonly cascadeBlend: number;
926
+ readonly mapSize: number;
927
+ readonly shadowDistance: number;
928
+ readonly shadowFilter: number;
929
+ readonly shadowAngularRadius: number;
930
+ readonly maxPenumbraTexels: number;
931
+ }
932
+
933
+ /**
934
+ * bug-20260710-editor-cross-world-shadow: computed directional-CSM output —
935
+ * the per-cascade light-view-projection matrices plus the derived cascade
936
+ * metadata. Returned by {@link computeDirectionalCsm}; `undefined` when the
937
+ * config or camera is missing (caller leaves the fields undefined).
938
+ */
939
+ export interface DirectionalCsmResult {
940
+ readonly lightViewProj: Float32Array[];
941
+ readonly splitPlanes: Float32Array;
942
+ readonly cascadeCount: number;
943
+ readonly cascadeBlend: number;
944
+ readonly shadowMapSize: number;
945
+ readonly directionalShadowQuality: DirectionalShadowQuality;
946
+ }
947
+
948
+ /**
949
+ * feat-20260709-editor-world-partition M1 / w4 (AC-08, plan-strategy §2 D-3):
950
+ * the owner index that previously served BOTH cameras and singleton render
951
+ * resources (skylight / skybox / postProcessParams) is split into two
952
+ * independent indices. `cameraOwner` selects the world whose cameras are
953
+ * surfaced; `resourceOwner` selects the world whose singleton resources are
954
+ * surfaced. A single number is accepted as the backward-compatible legacy form
955
+ * where `cameraOwner === resourceOwner === owner` (single-world callers +
956
+ * frame-loop stay byte-identical; the hard `{ owner }` cutover lands in M2).
957
+ */
958
+ export interface ExtractFramesOwner {
959
+ readonly cameraOwner: number;
960
+ readonly resourceOwner: number;
961
+ }
962
+
963
+ export interface PreparedExtractContext {
964
+ readonly assets: AssetRegistry | null | undefined;
965
+ readonly pipelineState: ExtractPipelineSurface | null | undefined;
966
+ readonly materialSnapshotCache: MaterialSnapshotCache | undefined;
967
+ /** `undefined` keeps direct extractFrame's local Fog semantics; `null` means
968
+ * the frame owner already selected that no Fog is present for this world. */
969
+ readonly resourceOwnerFog: FogFrame | null | undefined;
970
+ readonly cull: 'self' | 'none' | 'external';
971
+ readonly cullCameras: readonly CameraSnapshot[] | undefined;
972
+ readonly hierarchy: SceneHierarchySnapshot;
973
+ readonly visibility: VisibilitySnapshot;
974
+ }