@forgeax/engine-render 0.1.28 → 0.1.30

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 (768) hide show
  1. package/README.md +856 -126
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +27 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  9. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  10. package/dist/assembly/factory.d.ts +3 -1
  11. package/dist/assembly/factory.d.ts.map +1 -1
  12. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  13. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  14. package/dist/assembly/host-contract.d.ts +14 -0
  15. package/dist/assembly/host-contract.d.ts.map +1 -1
  16. package/dist/assembly/material/assembly.d.ts +31 -1
  17. package/dist/assembly/material/assembly.d.ts.map +1 -1
  18. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  19. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  20. package/dist/assembly/material-shader-policy.d.ts +3 -1
  21. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  22. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  23. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  24. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  25. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  26. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  27. package/dist/assembly/recovery/renderer-recover.d.ts +7 -4
  28. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  32. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-helpers.d.ts +3 -0
  35. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  36. package/dist/assembly/renderer-inspection.d.ts +4 -0
  37. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  38. package/dist/assembly/shader-prewarm-policy.d.ts +7 -1
  39. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  40. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  41. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  42. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  43. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  44. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  45. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  49. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  50. package/dist/assembly/webgpu-ready.d.ts +7 -3
  51. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  52. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  53. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  54. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  55. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  56. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  57. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  58. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  59. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  60. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  61. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  62. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  63. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  64. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  65. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  66. package/dist/authoring.mjs +2 -2
  67. package/dist/capture/scene-projection.d.ts +41 -0
  68. package/dist/capture/scene-projection.d.ts.map +1 -0
  69. package/dist/{chunk-J52NMQKR.mjs → chunk-7MQ3XBSP.mjs} +1098 -844
  70. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  71. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  72. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  73. package/dist/{chunk-VSL23LZE.mjs → chunk-C3DDSXYK.mjs} +1188 -463
  74. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  75. package/dist/{chunk-IQMKJLNU.mjs → chunk-FUUO4UND.mjs} +443 -30
  76. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  77. package/dist/{chunk-J6KACNOH.mjs → chunk-JRBDO2KB.mjs} +617 -7
  78. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  79. package/dist/{chunk-GE3SDD72.mjs → chunk-MDQJPY3T.mjs} +20 -40
  80. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  81. package/dist/{chunk-MYJ5RPJO.mjs → chunk-NO4WZCAH.mjs} +3 -3
  82. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  83. package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
  84. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  85. package/dist/{chunk-MBU4ZVE7.mjs → chunk-PSEQ6QPH.mjs} +4655 -892
  86. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  87. package/dist/{chunk-JAASCMXA.mjs → chunk-S5UE2T5P.mjs} +289 -41
  88. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  89. package/dist/components/camera.d.ts +62 -2
  90. package/dist/components/camera.d.ts.map +1 -1
  91. package/dist/components/directional-light.d.ts +2 -2
  92. package/dist/components/dynamic-resolution.d.ts +15 -0
  93. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  94. package/dist/components/index.d.ts +2 -0
  95. package/dist/components/index.d.ts.map +1 -1
  96. package/dist/components/instances.d.ts +6 -20
  97. package/dist/components/instances.d.ts.map +1 -1
  98. package/dist/components/light-helpers.d.ts.map +1 -1
  99. package/dist/components/reflection-probe.d.ts +1 -0
  100. package/dist/components/reflection-probe.d.ts.map +1 -1
  101. package/dist/components/scene-instance.d.ts +2 -1
  102. package/dist/components/scene-instance.d.ts.map +1 -1
  103. package/dist/components/screen-space-reflection.d.ts +14 -0
  104. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  105. package/dist/components/skylight.d.ts +4 -1
  106. package/dist/components/skylight.d.ts.map +1 -1
  107. package/dist/construct-renderer.mjs +14809 -7570
  108. package/dist/construct-renderer.mjs.map +1 -1
  109. package/dist/device/device-scope.d.ts +2 -0
  110. package/dist/device/device-scope.d.ts.map +1 -1
  111. package/dist/device/gpu-residency.d.ts +3 -14
  112. package/dist/device/gpu-residency.d.ts.map +1 -1
  113. package/dist/dynamic-geometry.d.ts.map +1 -1
  114. package/dist/environment/background.d.ts +7 -0
  115. package/dist/environment/background.d.ts.map +1 -0
  116. package/dist/environment/ibl.d.ts +11 -0
  117. package/dist/environment/ibl.d.ts.map +1 -0
  118. package/dist/environment/storage.d.ts +14 -0
  119. package/dist/environment/storage.d.ts.map +1 -0
  120. package/dist/errors/gpu-driven.d.ts +6 -3
  121. package/dist/errors/gpu-driven.d.ts.map +1 -1
  122. package/dist/errors/render.d.ts +41 -4
  123. package/dist/errors/render.d.ts.map +1 -1
  124. package/dist/extract/camera.d.ts.map +1 -1
  125. package/dist/extract/contracts.d.ts +7 -0
  126. package/dist/extract/contracts.d.ts.map +1 -1
  127. package/dist/extract/gpu-driven.d.ts +50 -3
  128. package/dist/extract/gpu-driven.d.ts.map +1 -1
  129. package/dist/features/host.d.ts +23 -1
  130. package/dist/features/host.d.ts.map +1 -1
  131. package/dist/features/noise-texture.d.ts +17 -0
  132. package/dist/features/noise-texture.d.ts.map +1 -0
  133. package/dist/features/plan.d.ts +83 -2
  134. package/dist/features/plan.d.ts.map +1 -1
  135. package/dist/features/prepared-gpu-work.d.ts +37 -4
  136. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  137. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  138. package/dist/features/prepared-graphics.d.ts +5 -0
  139. package/dist/features/prepared-graphics.d.ts.map +1 -1
  140. package/dist/features/render-graph-compute.d.ts +5 -3
  141. package/dist/features/render-graph-compute.d.ts.map +1 -1
  142. package/dist/features/render-graph-contribution.d.ts +11 -3
  143. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  144. package/dist/features/render-graph-raster.d.ts +19 -3
  145. package/dist/features/render-graph-raster.d.ts.map +1 -1
  146. package/dist/features/types.d.ts +11 -0
  147. package/dist/features/types.d.ts.map +1 -1
  148. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  149. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  150. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  151. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  152. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  153. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  154. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  155. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  156. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  157. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  158. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  159. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  160. package/dist/gpu-driven/production-raster.d.ts +169 -27
  161. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  162. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  163. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  164. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  165. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  166. package/dist/gpu-resource.d.ts +5 -2
  167. package/dist/gpu-resource.d.ts.map +1 -1
  168. package/dist/gpu-scene-schema.d.ts +2 -8
  169. package/dist/gpu-scene-schema.d.ts.map +1 -1
  170. package/dist/gpu-scene.d.ts +14 -0
  171. package/dist/gpu-scene.d.ts.map +1 -1
  172. package/dist/gpu-texture-usage.d.ts +1 -0
  173. package/dist/gpu-texture-usage.d.ts.map +1 -1
  174. package/dist/hdrp-buffers.d.ts +9 -0
  175. package/dist/hdrp-buffers.d.ts.map +1 -1
  176. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  177. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  178. package/dist/ibl/frame-resources.d.ts +8 -0
  179. package/dist/ibl/frame-resources.d.ts.map +1 -0
  180. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  181. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  182. package/dist/index.d.ts +87 -75
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.mjs +10 -8
  185. package/dist/index.mjs.map +1 -1
  186. package/dist/inspection-types.d.ts +180 -1
  187. package/dist/inspection-types.d.ts.map +1 -1
  188. package/dist/instances-derived-bounds.d.ts +11 -0
  189. package/dist/instances-derived-bounds.d.ts.map +1 -1
  190. package/dist/instances.d.ts +89 -44
  191. package/dist/instances.d.ts.map +1 -1
  192. package/dist/internal.d.ts +3 -0
  193. package/dist/internal.d.ts.map +1 -1
  194. package/dist/internal.mjs +117 -9
  195. package/dist/internal.mjs.map +1 -1
  196. package/dist/lifecycle.d.ts +2 -1
  197. package/dist/lifecycle.d.ts.map +1 -1
  198. package/dist/material-row.d.ts +15 -0
  199. package/dist/material-row.d.ts.map +1 -0
  200. package/dist/materials.d.ts +15 -0
  201. package/dist/materials.d.ts.map +1 -1
  202. package/dist/pbr-pipeline.d.ts +23 -5
  203. package/dist/pbr-pipeline.d.ts.map +1 -1
  204. package/dist/pipeline/render-extent.d.ts +51 -0
  205. package/dist/pipeline/render-extent.d.ts.map +1 -0
  206. package/dist/pipeline/standard-build-context.d.ts +7 -0
  207. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  208. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  209. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  210. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  211. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  212. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  213. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  214. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  215. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  216. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  217. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  218. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  219. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  220. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  221. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  222. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  223. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  224. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  225. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  226. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  227. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  228. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  229. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  230. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  231. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  232. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  233. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  234. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  235. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  236. package/dist/pipeline/standard-output/types.d.ts +39 -0
  237. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  238. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  239. package/dist/pipeline/standard-post.d.ts +2 -2
  240. package/dist/pipeline/standard-post.d.ts.map +1 -1
  241. package/dist/pipeline/standard-profile.d.ts +2 -1
  242. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  243. package/dist/pipeline-builder.d.ts +5 -2
  244. package/dist/pipeline-builder.d.ts.map +1 -1
  245. package/dist/pipeline-spec-types.d.ts +4 -0
  246. package/dist/pipeline-spec-types.d.ts.map +1 -1
  247. package/dist/pipeline-spec.d.ts +1 -9
  248. package/dist/pipeline-spec.d.ts.map +1 -1
  249. package/dist/plugin.d.ts.map +1 -1
  250. package/dist/points-lines/standard-owner.d.ts +1 -1
  251. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  252. package/dist/post-process-errors.d.ts +9 -2
  253. package/dist/post-process-errors.d.ts.map +1 -1
  254. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  255. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  256. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  257. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  258. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  259. package/dist/record/frame-lighting.d.ts +3 -3
  260. package/dist/record/frame-lighting.d.ts.map +1 -1
  261. package/dist/record/frame-snapshot.d.ts +109 -13
  262. package/dist/record/frame-snapshot.d.ts.map +1 -1
  263. package/dist/record/frame-targets.d.ts.map +1 -1
  264. package/dist/record/frame.d.ts +41 -5
  265. package/dist/record/frame.d.ts.map +1 -1
  266. package/dist/record/main-pass-geometry.d.ts +13 -9
  267. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  268. package/dist/record/main-pass-material.d.ts +43 -3
  269. package/dist/record/main-pass-material.d.ts.map +1 -1
  270. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  271. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  272. package/dist/record/main-pass.d.ts +14 -2
  273. package/dist/record/main-pass.d.ts.map +1 -1
  274. package/dist/record/mesh-ssbo.d.ts +15 -6
  275. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  276. package/dist/record/prepared-material-bindings.d.ts +19 -0
  277. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  278. package/dist/record/recovery-pipeline.d.ts +1 -0
  279. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  280. package/dist/record/render-context.d.ts +101 -22
  281. package/dist/record/render-context.d.ts.map +1 -1
  282. package/dist/record/shadow-pass.d.ts +62 -7
  283. package/dist/record/shadow-pass.d.ts.map +1 -1
  284. package/dist/record/skybox-post-pass.d.ts +1 -1
  285. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  286. package/dist/record/typed-frame-graph.d.ts +39 -8
  287. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  288. package/dist/record/view-ubo.d.ts +1 -0
  289. package/dist/record/view-ubo.d.ts.map +1 -1
  290. package/dist/recovery/render-system-candidate.d.ts +10 -2
  291. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  292. package/dist/recovery/render-system-roots.d.ts +11 -0
  293. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  294. package/dist/recovery/types.d.ts +76 -0
  295. package/dist/recovery/types.d.ts.map +1 -0
  296. package/dist/reflection/background.d.ts +14 -0
  297. package/dist/reflection/background.d.ts.map +1 -0
  298. package/dist/reflection/filter.d.ts.map +1 -1
  299. package/dist/reflection/projection.d.ts +1 -0
  300. package/dist/reflection/projection.d.ts.map +1 -1
  301. package/dist/reflection/record-owner.d.ts +4 -4
  302. package/dist/reflection/record-owner.d.ts.map +1 -1
  303. package/dist/render-contract.d.ts +211 -53
  304. package/dist/render-contract.d.ts.map +1 -1
  305. package/dist/render-graph-primitives.d.ts +1 -0
  306. package/dist/render-graph-primitives.d.ts.map +1 -1
  307. package/dist/render-pipeline.d.ts +81 -6
  308. package/dist/render-pipeline.d.ts.map +1 -1
  309. package/dist/render-system-extract-tail.d.ts +15 -6
  310. package/dist/render-system-extract-tail.d.ts.map +1 -1
  311. package/dist/render-system-extract.d.ts +128 -41
  312. package/dist/render-system-extract.d.ts.map +1 -1
  313. package/dist/render-system-projections.d.ts +22 -0
  314. package/dist/render-system-projections.d.ts.map +1 -0
  315. package/dist/render-system.d.ts +27 -77
  316. package/dist/render-system.d.ts.map +1 -1
  317. package/dist/scene/render-scene-types.d.ts +14 -7
  318. package/dist/scene/render-scene-types.d.ts.map +1 -1
  319. package/dist/scene/render-scene.d.ts +31 -11
  320. package/dist/scene/render-scene.d.ts.map +1 -1
  321. package/dist/scene/shadow-visibility.d.ts +5 -0
  322. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  323. package/dist/ssao-config.d.ts +8 -6
  324. package/dist/ssao-config.d.ts.map +1 -1
  325. package/dist/ssr/admission.d.ts +70 -1
  326. package/dist/ssr/admission.d.ts.map +1 -1
  327. package/dist/ssr/compose.d.ts +13 -0
  328. package/dist/ssr/compose.d.ts.map +1 -0
  329. package/dist/ssr/errors.d.ts +35 -0
  330. package/dist/ssr/errors.d.ts.map +1 -1
  331. package/dist/ssr/graph.d.ts +60 -0
  332. package/dist/ssr/graph.d.ts.map +1 -0
  333. package/dist/ssr/history.d.ts +97 -0
  334. package/dist/ssr/history.d.ts.map +1 -0
  335. package/dist/ssr/hiz.d.ts +37 -0
  336. package/dist/ssr/hiz.d.ts.map +1 -0
  337. package/dist/ssr/inspection.d.ts +42 -0
  338. package/dist/ssr/inspection.d.ts.map +1 -0
  339. package/dist/ssr/resources.d.ts +58 -0
  340. package/dist/ssr/resources.d.ts.map +1 -0
  341. package/dist/ssr/temporal.d.ts +38 -0
  342. package/dist/ssr/temporal.d.ts.map +1 -0
  343. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  344. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  345. package/dist/systems/skin-palette-types.d.ts +15 -0
  346. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  347. package/dist/systems/transparent-dispatch.d.ts +9 -0
  348. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  349. package/dist/targets/material-source.d.ts +7 -0
  350. package/dist/targets/material-source.d.ts.map +1 -1
  351. package/dist/temporal/frame-coordinator.d.ts +7 -0
  352. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  353. package/dist/temporal/gpu.d.ts +8 -0
  354. package/dist/temporal/gpu.d.ts.map +1 -1
  355. package/dist/temporal/history.d.ts.map +1 -1
  356. package/dist/temporal/index.mjs +6 -6
  357. package/dist/temporal/inspection.d.ts.map +1 -1
  358. package/dist/temporal/standard-scene-data.d.ts +4 -2
  359. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  360. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  361. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  362. package/dist/temporal/temporal-view.d.ts +6 -0
  363. package/dist/temporal/temporal-view.d.ts.map +1 -1
  364. package/dist/temporal/view.d.ts +6 -0
  365. package/dist/temporal/view.d.ts.map +1 -1
  366. package/dist/typed-render-graph-primitives.d.ts +41 -1
  367. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  368. package/dist/typed-shadow-passes.d.ts +3 -1
  369. package/dist/typed-shadow-passes.d.ts.map +1 -1
  370. package/dist/volume/component.d.ts +1 -0
  371. package/dist/volume/component.d.ts.map +1 -1
  372. package/dist/volume/temporal.d.ts +6 -0
  373. package/dist/volume/temporal.d.ts.map +1 -1
  374. package/package.json +21 -20
  375. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  376. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  377. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  378. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  379. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  380. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  381. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  382. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  383. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  384. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  385. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  386. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  387. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  388. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  389. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  390. package/src/__tests__/factory-contract.integration.test.ts +231 -9
  391. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  392. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  393. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  394. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  395. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  396. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  397. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  398. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  399. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  400. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  401. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +307 -7
  402. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  403. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  404. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +261 -0
  405. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +346 -0
  406. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1422 -0
  407. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  408. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  409. package/src/__tests__/gpu-driven-production.integration.test.ts +1076 -106
  410. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  411. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  412. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  413. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  414. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  415. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  416. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  417. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  418. package/src/__tests__/gpu-driven-view.unit.test.ts +160 -52
  419. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  420. package/src/__tests__/gpu-pass-timing.browser.test.ts +20 -2
  421. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  422. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  423. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  424. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  425. package/src/__tests__/gpu-scene.unit.test.ts +613 -33
  426. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  427. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  428. package/src/__tests__/instances-store.unit.test.ts +242 -39
  429. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  430. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  431. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  432. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  433. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  434. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  435. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  436. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  437. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  438. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  439. package/src/__tests__/materials-standard-contract.unit.test.ts +57 -3
  440. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  441. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  442. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  443. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  444. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  445. package/src/__tests__/physical-clearcoat.integration.test.ts +42 -3
  446. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  447. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  448. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  449. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  450. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  451. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +251 -9
  452. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  453. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  454. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  455. package/src/__tests__/public-surface.test-d.ts +3 -0
  456. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  457. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +171 -0
  458. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  459. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  460. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  461. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  462. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -14
  463. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  464. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  465. package/src/__tests__/render-error-detail-ssot.test-d.ts +27 -1
  466. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  467. package/src/__tests__/render-extent.unit.test.ts +63 -0
  468. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  469. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  470. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  471. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  472. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  473. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  474. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  475. package/src/__tests__/render-scene-projection.unit.test.ts +915 -23
  476. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  477. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  478. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  479. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  480. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +233 -9
  481. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  482. package/src/__tests__/shader-manifest-fixture.ts +45 -0
  483. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  484. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  485. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  486. package/src/__tests__/skinned-shadow-caster.test.ts +125 -14
  487. package/src/__tests__/specular-environment-scale.dawn.test.ts +158 -0
  488. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  489. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  490. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  491. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  492. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  493. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  494. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  495. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +99 -0
  496. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +116 -0
  497. package/src/__tests__/ssr-gpu-dispatch.ts +951 -0
  498. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  499. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  500. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  501. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  502. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  503. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  504. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  505. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  506. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  507. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  508. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  509. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  510. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  511. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  512. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  513. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  514. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  515. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  516. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  517. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  518. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  519. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  520. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +84 -12
  521. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  522. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  523. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  524. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  525. package/src/__tests__/standard-output.browser.test.ts +15 -0
  526. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  527. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +275 -0
  528. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  529. package/src/__tests__/standard-profile-oracle.unit.test.ts +49 -0
  530. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  531. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  532. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  533. package/src/__tests__/taa-coverage-edge.dawn.test.ts +199 -0
  534. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  535. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +782 -0
  536. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  537. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  538. package/src/__tests__/taa-stability-feedback.ts +342 -0
  539. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  540. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  541. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  542. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  543. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  544. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  545. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  546. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  547. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  548. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  549. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  550. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  551. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  552. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  553. package/src/assembly/atmosphere-shader-prewarm.ts +39 -0
  554. package/src/assembly/device-feature-admission.ts +9 -4
  555. package/src/assembly/dynamic-geometry-host.ts +284 -163
  556. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  557. package/src/assembly/factory.ts +4 -0
  558. package/src/assembly/gpu-driven-owner.ts +29 -0
  559. package/src/assembly/host-contract.ts +19 -0
  560. package/src/assembly/material/assembly.ts +383 -1
  561. package/src/assembly/material/pipeline-helpers.ts +100 -0
  562. package/src/assembly/material-shader-policy.ts +110 -46
  563. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  564. package/src/assembly/recovery/failure-location.ts +62 -0
  565. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  566. package/src/assembly/recovery/renderer-recover.ts +16 -17
  567. package/src/assembly/renderer-facade.ts +34 -1
  568. package/src/assembly/renderer-feature-inspection.ts +13 -0
  569. package/src/assembly/renderer-frame-transaction.ts +63 -0
  570. package/src/assembly/renderer-helpers.ts +26 -0
  571. package/src/assembly/renderer-inspection.ts +6 -0
  572. package/src/assembly/shader-prewarm-policy.ts +46 -1
  573. package/src/assembly/skin-palette-owner.ts +21 -0
  574. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  575. package/src/assembly/webgpu-device-loss.ts +75 -0
  576. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  577. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  578. package/src/assembly/webgpu-ready.ts +161 -131
  579. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  580. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  581. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  582. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  583. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  584. package/src/assembly/webgpu-renderer.ts +744 -730
  585. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  586. package/src/capture/scene-projection.ts +37 -0
  587. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  588. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  589. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  590. package/src/components/camera.ts +287 -7
  591. package/src/components/directional-light.ts +3 -3
  592. package/src/components/dynamic-resolution.ts +67 -0
  593. package/src/components/index.ts +2 -0
  594. package/src/components/instances.ts +45 -18
  595. package/src/components/light-helpers.ts +6 -1
  596. package/src/components/reflection-probe.ts +1 -0
  597. package/src/components/scene-instance.ts +2 -1
  598. package/src/components/screen-space-reflection.ts +21 -0
  599. package/src/components/skylight.ts +4 -1
  600. package/src/components/sprite-animation.ts +2 -2
  601. package/src/components/sprite-instances.ts +1 -1
  602. package/src/device/device-scope.ts +13 -7
  603. package/src/device/gpu-residency.ts +45 -42
  604. package/src/dynamic-geometry.ts +13 -8
  605. package/src/environment/background.ts +281 -0
  606. package/src/environment/ibl.ts +211 -0
  607. package/src/environment/storage.ts +63 -0
  608. package/src/errors/gpu-driven.ts +49 -8
  609. package/src/errors/render.ts +91 -3
  610. package/src/extract/camera.ts +37 -1
  611. package/src/extract/contracts.ts +10 -0
  612. package/src/extract/gpu-driven.ts +240 -10
  613. package/src/features/host.ts +237 -19
  614. package/src/features/noise-texture.ts +91 -0
  615. package/src/features/plan.ts +553 -24
  616. package/src/features/prepared-gpu-work.ts +631 -49
  617. package/src/features/prepared-graphics-store.ts +31 -0
  618. package/src/features/prepared-graphics.ts +5 -0
  619. package/src/features/render-graph-compute.ts +41 -8
  620. package/src/features/render-graph-contribution.ts +141 -3
  621. package/src/features/render-graph-raster.ts +143 -30
  622. package/src/features/types.ts +11 -0
  623. package/src/fullscreen-post-process-pass.ts +3 -0
  624. package/src/gpu-driven/batch-topology.ts +452 -108
  625. package/src/gpu-driven/material-artifacts.ts +179 -0
  626. package/src/gpu-driven/material-bindings.ts +41 -0
  627. package/src/gpu-driven/pbr-program.ts +31 -0
  628. package/src/gpu-driven/prepared-draw.ts +42 -6
  629. package/src/gpu-driven/production-raster.ts +2806 -716
  630. package/src/gpu-driven/shadow-views.ts +539 -0
  631. package/src/gpu-driven/view-gpu.ts +188 -41
  632. package/src/gpu-resource.ts +21 -2
  633. package/src/gpu-scene-schema.ts +61 -11
  634. package/src/gpu-scene.ts +197 -99
  635. package/src/gpu-texture-usage.ts +1 -0
  636. package/src/hdrp-buffers.ts +141 -36
  637. package/src/ibl/IblPipelineCache.ts +5 -0
  638. package/src/ibl/frame-resources.ts +38 -0
  639. package/src/ibl/skylight-bind-group.ts +32 -21
  640. package/src/index.ts +194 -75
  641. package/src/inspection-types.ts +207 -1
  642. package/src/instances-derived-bounds.ts +258 -34
  643. package/src/instances.ts +459 -150
  644. package/src/internal.ts +22 -0
  645. package/src/lifecycle.ts +2 -0
  646. package/src/material-row.ts +194 -0
  647. package/src/materials.ts +44 -8
  648. package/src/pbr-pipeline.ts +172 -19
  649. package/src/pipeline/render-extent.ts +111 -0
  650. package/src/pipeline/standard-build-context.ts +7 -0
  651. package/src/pipeline/standard-forward-lane.ts +74 -29
  652. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  653. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  654. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  655. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  656. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  657. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  658. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  659. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  660. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  661. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  662. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  663. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  664. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  665. package/src/pipeline/standard-output/color-transform.ts +124 -0
  666. package/src/pipeline/standard-output/graph.ts +139 -0
  667. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  668. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  669. package/src/pipeline/standard-output/lut-state.ts +176 -0
  670. package/src/pipeline/standard-output/resources.ts +121 -0
  671. package/src/pipeline/standard-output/types.ts +58 -0
  672. package/src/pipeline/standard-pipeline.ts +232 -70
  673. package/src/pipeline/standard-post.ts +190 -27
  674. package/src/pipeline/standard-profile.ts +2 -1
  675. package/src/pipeline-builder.ts +28 -9
  676. package/src/pipeline-spec-types.ts +4 -0
  677. package/src/pipeline-spec.ts +37 -29
  678. package/src/plugin.ts +4 -0
  679. package/src/points-lines/standard-owner.ts +6 -14
  680. package/src/post-process-errors.ts +26 -18
  681. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  682. package/src/prepare/extended-lighting/resources.ts +3 -3
  683. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  684. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  685. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  686. package/src/record/__tests__/material-slot-plan.unit.test.ts +57 -0
  687. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  688. package/src/record/__tests__/recovery-pipeline.unit.test.ts +20 -1
  689. package/src/record/__tests__/sprite-material-abi.unit.test.ts +41 -6
  690. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  691. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  692. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  693. package/src/record/dynamic-geometry-consumption.ts +59 -0
  694. package/src/record/frame-lighting.ts +15 -12
  695. package/src/record/frame-snapshot.ts +146 -34
  696. package/src/record/frame-targets.ts +9 -0
  697. package/src/record/frame.ts +838 -170
  698. package/src/record/main-pass-geometry.ts +209 -103
  699. package/src/record/main-pass-material.ts +157 -40
  700. package/src/record/main-pass-sprite-draws.ts +16 -107
  701. package/src/record/main-pass.ts +141 -12
  702. package/src/record/material-uniforms.ts +1 -1
  703. package/src/record/mesh-ssbo.ts +59 -15
  704. package/src/record/prepared-material-bindings.ts +238 -0
  705. package/src/record/recovery-pipeline.ts +69 -90
  706. package/src/record/render-context.ts +123 -24
  707. package/src/record/shadow-pass.ts +1389 -230
  708. package/src/record/skybox-post-pass.ts +14 -3
  709. package/src/record/typed-frame-graph.ts +1064 -47
  710. package/src/record/view-ubo.ts +12 -1
  711. package/src/recovery/render-system-candidate.ts +135 -68
  712. package/src/recovery/render-system-roots.ts +113 -0
  713. package/src/recovery/types.ts +77 -0
  714. package/src/reflection/background.ts +151 -0
  715. package/src/reflection/filter.ts +3 -0
  716. package/src/reflection/projection.ts +16 -6
  717. package/src/reflection/record-owner.ts +308 -140
  718. package/src/render-contract.ts +237 -49
  719. package/src/render-graph-primitives.ts +34 -5
  720. package/src/render-pipeline.ts +90 -2
  721. package/src/render-system-extract-tail.ts +431 -162
  722. package/src/render-system-extract.ts +478 -119
  723. package/src/render-system-projections.ts +241 -0
  724. package/src/render-system.ts +715 -828
  725. package/src/scene/render-scene-types.ts +13 -4
  726. package/src/scene/render-scene.ts +577 -355
  727. package/src/scene/shadow-visibility.ts +21 -0
  728. package/src/ssao-config.ts +25 -8
  729. package/src/ssr/admission.ts +380 -14
  730. package/src/ssr/compose.ts +144 -0
  731. package/src/ssr/errors.ts +48 -0
  732. package/src/ssr/graph.ts +797 -0
  733. package/src/ssr/history.ts +436 -0
  734. package/src/ssr/hiz.ts +124 -0
  735. package/src/ssr/inspection.ts +124 -0
  736. package/src/ssr/resources.ts +202 -0
  737. package/src/ssr/temporal.ts +164 -0
  738. package/src/systems/skin-palette-allocator.ts +495 -148
  739. package/src/systems/skin-palette-types.ts +17 -0
  740. package/src/systems/transparent-dispatch.ts +90 -0
  741. package/src/targets/material-source.ts +34 -0
  742. package/src/temporal/coverage.ts +1 -1
  743. package/src/temporal/frame-coordinator.ts +23 -2
  744. package/src/temporal/gpu.ts +79 -12
  745. package/src/temporal/history.ts +3 -1
  746. package/src/temporal/inspection.ts +2 -1
  747. package/src/temporal/standard-scene-data.ts +10 -2
  748. package/src/temporal/target-coverage-attachment.ts +72 -0
  749. package/src/temporal/temporal-view.ts +11 -2
  750. package/src/temporal/view.ts +12 -2
  751. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +219 -139
  752. package/src/typed-render-graph-primitives.ts +304 -74
  753. package/src/typed-shadow-passes.ts +122 -12
  754. package/src/volume/component.ts +1 -0
  755. package/src/volume/passes.ts +3 -3
  756. package/src/volume/temporal.ts +10 -0
  757. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  758. package/dist/chunk-GF523LHF.mjs.map +0 -1
  759. package/dist/chunk-IQMKJLNU.mjs.map +0 -1
  760. package/dist/chunk-J52NMQKR.mjs.map +0 -1
  761. package/dist/chunk-J6KACNOH.mjs.map +0 -1
  762. package/dist/chunk-JAASCMXA.mjs.map +0 -1
  763. package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
  764. package/dist/chunk-MYJ5RPJO.mjs.map +0 -1
  765. package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
  766. package/dist/chunk-VSL23LZE.mjs.map +0 -1
  767. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  768. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -5,14 +5,12 @@ import {
5
5
  } from '@forgeax/engine-assets-runtime';
6
6
  import type { EntityHandle, World } from '@forgeax/engine-ecs';
7
7
  import {
8
- InstanceTransformsStrideMismatchError,
9
8
  routeWorldError,
10
9
  SpawnLightInvalidBoundsError,
11
10
  SpriteInstancesCountMismatchError,
12
11
  SpriteInstancesMutuallyExclusiveWithInstancesError,
13
12
  SpriteInstancesRequiresSpriteShaderError,
14
13
  } from '@forgeax/engine-ecs/projection';
15
- import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
16
14
  import { box3, frustum, type Mat4, mat4, type Vec3, vec3 } from '@forgeax/engine-math';
17
15
  import { AssetGuid } from '@forgeax/engine-pack/guid';
18
16
  import type { MaterialCookProgramContext } from '@forgeax/engine-pack/material-cook';
@@ -39,6 +37,7 @@ import {
39
37
  ASSET_ERROR_HINTS,
40
38
  AssetError,
41
39
  derive,
40
+ err,
42
41
  handleSlot,
43
42
  materialValuesToLinearRuntime,
44
43
  toShared,
@@ -81,16 +80,23 @@ import {
81
80
  import { selectEnvironment } from './environment/frame';
82
81
  import { MaterialSkinAttrMissingError, SkinMaterialMismatchError } from './errors/render';
83
82
  import type { EnvironmentCandidate, EnvironmentFrame } from './extract/environment';
84
- import { buildGpuDrivenDraws, resolvePreparedGpuDrivenDraw } from './extract/gpu-driven';
83
+ import {
84
+ buildGpuDrivenDraws,
85
+ gpuDrivenShadowDrawKey,
86
+ gpuDrivenSourceDrawItemIndex,
87
+ } from './extract/gpu-driven';
85
88
  import type { VisibilitySnapshot } from './extract/visibility';
86
89
  import type {
87
90
  RenderFeatureHiddenEntityReport,
88
91
  RenderFeatureWorldVisibilitySnapshot,
89
92
  } from './features/types';
90
93
  import { ensureGlyphMeshMaterialSlots } from './glyph-text-layout-system';
91
- import type { GpuDrivenGeometryReceipt } from './gpu-driven/prepared-draw';
92
- import type { InstanceProjectionStore } from './instances';
93
- import { deriveInstancesUnionBounds, fingerprintNumericArray } from './instances-derived-bounds';
94
+ import {
95
+ InstanceCollectionError,
96
+ type InstanceCollectionId,
97
+ type InstanceCollectionStore,
98
+ } from './instances';
99
+ import { deriveInstancesUnionBounds } from './instances-derived-bounds';
94
100
  import {
95
101
  type MeshMaterialBindingDiagnostic,
96
102
  type MeshMaterialBindingSource,
@@ -101,6 +107,7 @@ import { expandPointsLinesBounds } from './points-lines/bounds';
101
107
  import type { PointsLinesRetainedSnapshot, PointsLinesStyle } from './points-lines/snapshot';
102
108
  import { COOKIE_SLICE_CAPACITY, IES_SLICE_CAPACITY } from './prepare/extended-lighting/resources';
103
109
  import { prepareCookieProjection } from './prepare/extended-lighting/spot-modifiers';
110
+ import { worldEntityKey } from './record/frame-snapshot';
104
111
  import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID } from './render-contract';
105
112
  import type {
106
113
  CsmCameraData,
@@ -116,12 +123,15 @@ import type {
116
123
  MaterialSnapshot,
117
124
  MaterialSnapshotCache,
118
125
  MaterialSnapshotCachesByWorld,
126
+ MaterialTextureSourceCache,
127
+ MaterialTextureSourceStats,
119
128
  MorphSnapshot,
120
129
  PointLightSnapshot,
121
130
  PointShadowSnapshot,
122
131
  PreparedExtractContext,
123
132
  RectAreaDirectLightSnapshot,
124
133
  RenderableSnapshot,
134
+ ShadowCasterMembership,
125
135
  SkyboxSnapshot,
126
136
  SkylightSnapshot,
127
137
  SpotLightSnapshot,
@@ -134,6 +144,8 @@ import {
134
144
  BUILTIN_USER_REGION_TEXTURE_FIELDS,
135
145
  buildPointShadowMatrices,
136
146
  buildRectAreaWorldFrame,
147
+ collectAuthoredMaterialSamplerFields,
148
+ collectAuthoredMaterialTextureFields,
137
149
  collectCubeCameraSnapshots,
138
150
  collectMaterialTextureCoordinates,
139
151
  collectMaterialTextureSamplers,
@@ -150,8 +162,11 @@ import {
150
162
  materialNormalScale,
151
163
  materialParamSchemaForMaterial,
152
164
  materialProgramKeysForMaterial,
165
+ materialSceneIndexProgramKeysForMaterial,
166
+ materialStandardTextureMask,
153
167
  materialTextureFields,
154
168
  materialTextureRef,
169
+ materialTextureSourceFields,
155
170
  pipelineRenderState,
156
171
  prepareExtractContext,
157
172
  pssmSplit,
@@ -163,12 +178,19 @@ import {
163
178
  Severity,
164
179
  selectCameraRoles,
165
180
  selectFogFrame,
181
+ shadowCasterCpuReason,
166
182
  sortDispatchByQueue,
167
183
  storeMaterialSnapshot,
168
184
  tonemapParams,
169
185
  } from './render-system-extract';
186
+ import { buildShadowFrusta } from './scene/shadow-visibility';
170
187
  import { SHADOW_ATLAS_DEFAULT_LAYERS } from './shadow-atlas';
171
- import type { SkinPaletteSlice } from './systems/skin-palette-types';
188
+ import type { SkinPaletteReceipt } from './systems/skin-palette-types';
189
+
190
+ function skinPaletteIdentity(world: World, entity: number): string {
191
+ return `skin:${world.identity}:${entity}`;
192
+ }
193
+
172
194
  export function extractFrames(
173
195
  worlds: readonly World[],
174
196
  owner: number | ExtractFramesOwner,
@@ -178,13 +200,24 @@ export function extractFrames(
178
200
  options: {
179
201
  readonly materialContext?: MaterialCookProgramContext;
180
202
  readonly cull?: 'normal' | 'none';
181
- readonly renderables?: 'full' | 'none';
182
- readonly renderableEntitiesByWorld?: readonly (ReadonlySet<number> | undefined)[];
203
+ readonly renderables?:
204
+ | 'full'
205
+ | 'none'
206
+ | {
207
+ readonly kind: 'partial';
208
+ readonly entitiesByWorld: readonly (ReadonlySet<number> | undefined)[];
209
+ };
183
210
  readonly retainHidden?: boolean;
184
211
  readonly getMaterialShaderArtifact?: (
185
212
  materialShaderId: string,
213
+ request?: {
214
+ readonly vertexColorAvailable?: boolean;
215
+ readonly deformation?: 'rigid' | 'skin';
216
+ readonly pass?: 'forward' | 'shadow' | 'depth';
217
+ readonly address?: 'direct' | 'scene-index';
218
+ },
186
219
  ) => MaterialShaderArtifact | undefined;
187
- readonly instanceCollections?: InstanceProjectionStore;
220
+ readonly instanceCollections?: InstanceCollectionStore;
188
221
  } = {},
189
222
  ): ExtractedFrame {
190
223
  // w4: normalize the owner argument. A bare number is the legacy single-owner
@@ -193,6 +226,12 @@ export function extractFrames(
193
226
  // single-owner behaviour (w1 contract combination 2).
194
227
  const cameraOwner = typeof owner === 'number' ? owner : owner.cameraOwner;
195
228
  const resourceOwner = typeof owner === 'number' ? owner : owner.resourceOwner;
229
+ const cameraEntityKey = typeof owner === 'number' ? undefined : owner.cameraEntityKey;
230
+ const renderableRequest = options.renderables ?? 'full';
231
+ const renderableMode = typeof renderableRequest === 'object' ? 'full' : renderableRequest;
232
+ const partialEntitiesByWorld =
233
+ typeof renderableRequest === 'object' ? renderableRequest.entitiesByWorld : undefined;
234
+ const retainHidden = options.retainHidden ?? typeof renderableRequest === 'object';
196
235
 
197
236
  // ── D-2: frame-level side effects live here ────────────────────────────
198
237
  //
@@ -201,7 +240,14 @@ export function extractFrames(
201
240
  // extract runs, so sequential per-world allocation yields non-overlapping
202
241
  // palette slices (AC-08).
203
242
  const skinPaletteAllocator = pipelineState?.skinPaletteAllocator ?? null;
204
- if (skinPaletteAllocator !== null) {
243
+ // A partial request is still normalized to the producer's full renderable
244
+ // query, but it is not a full allocator reconciliation. beginFrame/endFrame
245
+ // mark every persistent identity not visited by this selected subset as
246
+ // detached; doing that here would release untouched palettes. Only the
247
+ // explicit full request is allowed to reconcile the identity set.
248
+ const reconcileSkinFrame = renderableRequest === 'full';
249
+ if (skinPaletteAllocator !== null && reconcileSkinFrame) {
250
+ skinPaletteAllocator.beginFrame();
205
251
  skinPaletteAllocator.resetForFrame();
206
252
  }
207
253
 
@@ -237,6 +283,13 @@ export function extractFrames(
237
283
  const world = worlds[wi];
238
284
  if (world === undefined || failedWorlds.has(world)) continue;
239
285
  try {
286
+ if (skinPaletteAllocator !== null && partialEntitiesByWorld !== undefined) {
287
+ for (const entityKey of partialEntitiesByWorld[wi] ?? []) {
288
+ if (!world.hasComponent(entityKey as EntityHandle, Skin)) {
289
+ skinPaletteAllocator.releasePersistentSlice(skinPaletteIdentity(world, entityKey));
290
+ }
291
+ }
292
+ }
240
293
  const isCameraOwner = wi === cameraOwner;
241
294
  const cameraOwnerFrame = framesByWorld.get(cameraOwner);
242
295
  const prepared = prepareExtractContext(world, {
@@ -258,11 +311,13 @@ export function extractFrames(
258
311
  ? {}
259
312
  : { materialContext: options.materialContext }),
260
313
  cull: options.cull === 'none' ? 'none' : isCameraOwner ? 'self' : 'external',
261
- renderables: options.renderables ?? 'full',
262
- ...(options.renderableEntitiesByWorld?.[wi] === undefined
314
+ renderables: renderableMode,
315
+ ...(isCameraOwner && cameraEntityKey !== undefined ? { cameraEntityKey } : {}),
316
+ ...(partialEntitiesByWorld?.[wi] === undefined
263
317
  ? {}
264
- : { renderableEntities: options.renderableEntitiesByWorld[wi] }),
265
- retainHidden: options.retainHidden ?? false,
318
+ : { renderableEntities: partialEntitiesByWorld[wi] }),
319
+ retainHidden,
320
+ worldId: wi,
266
321
  ...(options.getMaterialShaderArtifact === undefined
267
322
  ? {}
268
323
  : { getMaterialShaderArtifact: options.getMaterialShaderArtifact }),
@@ -287,6 +342,13 @@ export function extractFrames(
287
342
  }
288
343
  }
289
344
 
345
+ // Reconcile persistent palette identities from the extracted producer
346
+ // projection. Identities absent after a detach are fence-retired by the
347
+ // allocator; surviving identities keep their stable slices.
348
+ if (skinPaletteAllocator !== null && reconcileSkinFrame) {
349
+ skinPaletteAllocator.endFrame();
350
+ }
351
+
290
352
  // Restore the caller's world order after the camera-owner-first extraction.
291
353
  for (let wi = 0; wi < worlds.length; wi++) {
292
354
  const frame = framesByWorld.get(wi);
@@ -300,6 +362,9 @@ export function extractFrames(
300
362
  // AC-04: renderables — concat by worlds[] order, stamp worldId.
301
363
  const renderables: RenderableSnapshot[] = [];
302
364
  const dispatchEntries: DispatchEntry[] = [];
365
+ const shadowCasterEntityKeys = new Set<number>();
366
+ const shadowCasterDrawKeys = new Set<string>();
367
+ const shadowCasterMembership = new Map<string, ShadowCasterMembership>();
303
368
  const visibilitySnapshots: VisibilitySnapshot[] = [];
304
369
  const featureVisibilitySnapshots: RenderFeatureWorldVisibilitySnapshot[] = [];
305
370
  const hiddenEntityReports: RenderFeatureHiddenEntityReport[] = [];
@@ -330,6 +395,18 @@ export function extractFrames(
330
395
  for (const d of f.dispatch) {
331
396
  dispatchEntries.push({ ...d, renderableIndex: (d.renderableIndex ?? 0) + base });
332
397
  }
398
+ for (const key of f.shadowCasterEntityKeys) shadowCasterEntityKeys.add(key);
399
+ for (const key of f.shadowCasterDrawKeys) shadowCasterDrawKeys.add(key);
400
+ for (const membership of f.shadowCasterMembership ?? []) {
401
+ const rebased = { ...membership, renderableIndex: membership.renderableIndex + base };
402
+ const key = gpuDrivenShadowDrawKey(
403
+ rebased.worldEntity,
404
+ rebased.materialHandle,
405
+ rebased.drawItemIndex,
406
+ rebased.passIndex,
407
+ );
408
+ shadowCasterMembership.set(key, rebased);
409
+ }
333
410
  }
334
411
 
335
412
  // Stable sort dispatch by queue value.
@@ -359,11 +436,14 @@ export function extractFrames(
359
436
  // camera may live in different worlds (editor super-composite).
360
437
  let directionalCsmConfig: DirectionalCsmConfig | undefined;
361
438
  let directionalCsmDirection: Vec3 | undefined;
362
- for (const f of succeededFrames) {
363
- for (const p of f.lights.point) point.push(p);
364
- for (const s of f.lights.spot) spot.push(s);
439
+ for (let fi = 0; fi < succeededFrames.length; fi += 1) {
440
+ const f = succeededFrames[fi];
441
+ const wId = succeededIndices[fi] ?? 0;
442
+ if (f === undefined) continue;
443
+ for (const p of f.lights.point) point.push({ ...p, worldId: wId });
444
+ for (const s of f.lights.spot) spot.push({ ...s, worldId: wId });
365
445
  for (const r of f.lights.rect) rect.push(r);
366
- for (const ps of f.lights.pointShadow) pointShadow.push(ps);
446
+ for (const ps of f.lights.pointShadow) pointShadow.push({ ...ps, worldId: wId });
367
447
  if (directional === undefined && f.lights.directional !== undefined) {
368
448
  directional = f.lights.directional;
369
449
  // Carry CSM shadow fields from the first-hit directional's world.
@@ -393,9 +473,10 @@ export function extractFrames(
393
473
  if (succeededIndices[fi] === cameraOwner) cameraOwnerFrame = succeededFrames[fi];
394
474
  if (succeededIndices[fi] === resourceOwner) resourceOwnerFrame = succeededFrames[fi];
395
475
  }
396
- const cameras = cameraOwnerFrame !== undefined ? [...cameraOwnerFrame.cameras] : [];
476
+ const cameras =
477
+ cameraOwnerFrame?.cameras.map((camera) => ({ ...camera, worldId: cameraOwner })) ?? [];
397
478
  const auxiliaryCameras =
398
- cameraOwnerFrame !== undefined ? [...cameraOwnerFrame.auxiliaryCameras] : [];
479
+ cameraOwnerFrame?.auxiliaryCameras.map((camera) => ({ ...camera, worldId: cameraOwner })) ?? [];
399
480
  const cubeCameras = cameraOwnerFrame !== undefined ? [...cameraOwnerFrame.cubeCameras] : [];
400
481
 
401
482
  // bug-20260710-editor-cross-world-shadow: RECOMPUTE directional CSM matrices
@@ -460,6 +541,7 @@ export function extractFrames(
460
541
  directionalCsmConfig,
461
542
  directionalCsmDirection,
462
543
  };
544
+
463
545
  const volumetricFog = resourceOwnerFrame?.volumetricFog;
464
546
  const skylight = resourceOwnerFrame?.skylight;
465
547
  const skylightCount = resourceOwnerFrame?.skylightCount ?? 0;
@@ -468,7 +550,10 @@ export function extractFrames(
468
550
  const fog = resourceOwnerFrame?.fog;
469
551
  const fogFailure = resourceOwnerFrame?.fogFailure;
470
552
  const environment = resourceOwnerFrame?.environment;
471
- const lightProbes = succeededFrames.flatMap((frame) => frame.lightProbes ?? []);
553
+ const lightProbes = succeededFrames.flatMap((frame, index) => {
554
+ const worldId = succeededIndices[index] ?? 0;
555
+ return (frame.lightProbes ?? []).map((probe) => ({ ...probe, worldId }));
556
+ });
472
557
  // User-authored PostProcessParams entities are singleton scene resources, so
473
558
  // they come from the resourceOwner world (holistic snapshot selection).
474
559
  const postProcessParams = new Map(resourceOwnerFrame?.postProcessParams);
@@ -507,35 +592,30 @@ export function extractFrames(
507
592
  const visibilityStats = {
508
593
  explicitlyHidden: succeededFrames.reduce((s, f) => s + f.visibilityStats.explicitlyHidden, 0),
509
594
  };
595
+ const materialTextureSources: MaterialTextureSourceStats = {
596
+ sourceFieldsVisited: 0,
597
+ numericSharedRefProbes: 0,
598
+ sourceCacheHits: 0,
599
+ sourceCacheMisses: 0,
600
+ producerRoutes: {},
601
+ };
602
+ for (const frame of succeededFrames) {
603
+ const stats = frame.materialTextureSources;
604
+ if (stats === undefined) continue;
605
+ materialTextureSources.sourceFieldsVisited += stats.sourceFieldsVisited;
606
+ materialTextureSources.numericSharedRefProbes += stats.numericSharedRefProbes;
607
+ materialTextureSources.sourceCacheHits += stats.sourceCacheHits;
608
+ materialTextureSources.sourceCacheMisses += stats.sourceCacheMisses;
609
+ for (const [route, count] of Object.entries(stats.producerRoutes)) {
610
+ materialTextureSources.producerRoutes[route] =
611
+ (materialTextureSources.producerRoutes[route] ?? 0) + count;
612
+ }
613
+ }
510
614
  const reflectionProbes = succeededFrames.flatMap((f, index) => {
511
615
  const worldId = succeededIndices[index] ?? 0;
512
616
  return (f.reflectionProbes ?? []).map((probe) => ({ ...probe, worldId }));
513
617
  });
514
618
 
515
- if (options.renderables !== 'none' && options.renderableEntitiesByWorld === undefined) {
516
- options.instanceCollections?.retain(
517
- new Set(
518
- renderables.flatMap((row) =>
519
- row.instances?.collectionId === undefined ? [] : [row.instances.collectionId],
520
- ),
521
- ),
522
- );
523
- if (
524
- skinPaletteAllocator !== null &&
525
- typeof skinPaletteAllocator.retainSliceKeys === 'function'
526
- ) {
527
- skinPaletteAllocator.retainSliceKeys(
528
- new Set(
529
- renderables.flatMap((row) =>
530
- row.skin === undefined
531
- ? []
532
- : [`${worlds[row.worldId]?.identity ?? row.worldId}:${row.entityKey}`],
533
- ),
534
- ),
535
- );
536
- }
537
- }
538
-
539
619
  return {
540
620
  cameras,
541
621
  auxiliaryCameras,
@@ -547,6 +627,11 @@ export function extractFrames(
547
627
  : { volumetricFog: { ...volumetricFog, worldId: resourceOwner } }),
548
628
  renderables,
549
629
  dispatch: dispatchEntries,
630
+ shadowCasterEntityKeys,
631
+ shadowCasterDrawKeys,
632
+ ...(shadowCasterMembership.size === 0
633
+ ? {}
634
+ : { shadowCasterMembership: [...shadowCasterMembership.values()] }),
550
635
  skylight,
551
636
  skylightCount,
552
637
  lightProbes,
@@ -558,6 +643,7 @@ export function extractFrames(
558
643
  environmentReady: resourceOwnerFrame !== undefined && environment !== undefined,
559
644
  frustumStats,
560
645
  visibilityStats,
646
+ materialTextureSources,
561
647
  postProcessParams,
562
648
  visibilitySnapshots,
563
649
  featureVisibilitySnapshots,
@@ -603,8 +689,8 @@ function hasFiniteOrderedLocalAabb(aabb: Float32Array | undefined): aabb is Floa
603
689
  return minX <= maxX && minY <= maxY && minZ <= maxZ;
604
690
  }
605
691
 
606
- function morphSnapshotFor(
607
- mesh: MeshAsset,
692
+ export function morphSnapshotFor(
693
+ mesh: Pick<MeshAsset, 'vertices' | 'morphTargets'>,
608
694
  weights: ArrayLike<number> | undefined,
609
695
  ): MorphSnapshot | undefined {
610
696
  const targets = mesh.morphTargets;
@@ -630,6 +716,9 @@ function morphSnapshotFor(
630
716
  if (!Number.isFinite(weight)) return undefined;
631
717
  copied[index] = weight;
632
718
  }
719
+ // Zero weights are the source vertex stream exactly. An authored but idle
720
+ // morph target must not disable skin scene-index admission or dispatch work.
721
+ if (copied.every((weight) => weight === 0)) return undefined;
633
722
  return { weights: copied, targetCount: targets.length };
634
723
  }
635
724
 
@@ -656,6 +745,14 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
656
745
  const fogFailure = fogState(world).failure;
657
746
  const visibility = context.visibility.hasAnyHiddenIntent ? context.visibility : undefined;
658
747
  const skinPaletteAllocator = pipelineState?.skinPaletteAllocator ?? null;
748
+ const materialTextureSourceStats: MaterialTextureSourceStats = {
749
+ sourceFieldsVisited: 0,
750
+ numericSharedRefProbes: 0,
751
+ sourceCacheHits: 0,
752
+ sourceCacheMisses: 0,
753
+ producerRoutes: {},
754
+ };
755
+ const materialTextureSourceCache: MaterialTextureSourceCache = new Map();
659
756
 
660
757
  const directionalLightQuery = world.query({ read: [DirectionalLight] }).unwrap();
661
758
 
@@ -673,7 +770,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
673
770
  const worldInternal = createWorldInternalView(world);
674
771
  let volumetricFog = extractVolumeSnapshot(world, assets, worldInternal);
675
772
 
676
- const cameraRoles = selectCameraRoles(world);
773
+ const cameraRoles = selectCameraRoles(world, context.cameraEntityKey);
677
774
  const cameras = [...cameraRoles.display];
678
775
  const auxiliaryCameras = cameraRoles.auxiliary;
679
776
  const cubeCameras = collectCubeCameraSnapshots(world);
@@ -784,6 +881,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
784
881
  pointSnapshots.push({
785
882
  kind: 'point',
786
883
  entity: entityId,
884
+ worldId: context.worldId,
787
885
  position,
788
886
  color: vec3.create(
789
887
  (p.color[0] ?? 1) * intensity,
@@ -979,6 +1077,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
979
1077
  spotSnapshots.push({
980
1078
  kind: 'spot',
981
1079
  entity: row.entity,
1080
+ worldId: context.worldId,
982
1081
  // D-6: position reflects world transform; direction stays sourced
983
1082
  // from SpotLight.direction (NOT rotated by the parent).
984
1083
  position,
@@ -1274,10 +1373,13 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1274
1373
  }
1275
1374
  pointShadowSnapshots.push({
1276
1375
  entity: row.entity,
1376
+ worldId: context.worldId,
1277
1377
  position: lightPos,
1278
1378
  mapSize,
1279
1379
  nearPlane,
1280
1380
  farPlane,
1381
+ depthBias: ps.depthBias,
1382
+ normalBias: ps.normalBias,
1281
1383
  shadowAtlasLayer: layer,
1282
1384
  shadowMatrices: packed,
1283
1385
  });
@@ -1329,6 +1431,12 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1329
1431
  directionalCsmDirection,
1330
1432
  };
1331
1433
 
1434
+ // A caster may be outside the display camera while still contributing to a
1435
+ // light's shadow map. Keep the light-space visibility projection alongside
1436
+ // camera culling so the direct extraction path and persistent composition
1437
+ // retain the same shadow-only rule.
1438
+ const shadowFrusta = cullMode === 'none' ? [] : buildShadowFrusta(lights);
1439
+
1332
1440
  // feat-20260520-skylight-ibl-cubemap M4 / t26+t27: query Skylight entities.
1333
1441
  // First archetype hit wins (mirrors DirectionalLight pattern); multi-Skylight
1334
1442
  // warn in record stage (t27) uses skylightCount.
@@ -1384,6 +1492,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1384
1492
  const transform = row.get(GlobalTransform);
1385
1493
  lightProbes.push({
1386
1494
  identity: String(row.entity),
1495
+ worldId: context.worldId,
1387
1496
  position: [transform.world[12] ?? 0, transform.world[13] ?? 0, transform.world[14] ?? 0],
1388
1497
  radius: probe.radius,
1389
1498
  irradiance: new Float32Array(probe.irradiance),
@@ -1459,22 +1568,27 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1459
1568
  directionalDirection[1] ?? 0,
1460
1569
  directionalDirection[2] ?? 0,
1461
1570
  );
1571
+ const sunIntensity = directional?.intensity ?? 0;
1572
+ const sunColor =
1573
+ sunIntensity > 0 && directional !== undefined
1574
+ ? ([
1575
+ (directional.color[0] ?? 0) / sunIntensity,
1576
+ (directional.color[1] ?? 0) / sunIntensity,
1577
+ (directional.color[2] ?? 0) / sunIntensity,
1578
+ ] as [number, number, number])
1579
+ : ([0, 0, 0] as [number, number, number]);
1462
1580
  const sun =
1463
- directional === undefined || directionalLength <= 1e-6
1581
+ directional === undefined || directional.entity === undefined || directionalLength <= 1e-6
1464
1582
  ? []
1465
1583
  : [
1466
1584
  {
1467
- entityKey: 0,
1585
+ entityKey: directional.entity,
1468
1586
  direction: [
1469
1587
  -(directionalDirection?.[0] ?? 0) / directionalLength,
1470
1588
  -(directionalDirection?.[1] ?? 0) / directionalLength,
1471
1589
  -(directionalDirection?.[2] ?? 0) / directionalLength,
1472
1590
  ] as [number, number, number],
1473
- color: [
1474
- directional.color[0] ?? 0,
1475
- directional.color[1] ?? 0,
1476
- directional.color[2] ?? 0,
1477
- ] as [number, number, number],
1591
+ color: sunColor,
1478
1592
  intensity: directional.intensity,
1479
1593
  },
1480
1594
  ];
@@ -1561,18 +1675,26 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1561
1675
  // (plan-strategy D-3). Entries built per-entity per-pass inside the
1562
1676
  // archetype walk, then sorted by queue at the end.
1563
1677
  let dispatch: DispatchEntry[] = [];
1678
+ const shadowMembershipEntries: ShadowCasterMembership[] = [];
1564
1679
  // Keep the derived material snapshot and its resolved passes local to this
1565
1680
  // extraction. Shared handles are immutable inputs for the frame, while
1566
1681
  // dispatch entries still need to be rebuilt for each entity.
1567
1682
  const materialSnapshotCache: MaterialSnapshotCache = new Map();
1683
+ // A collection can be associated with more than one entity. Snapshot its
1684
+ // renderer-owned bytes once per extracted frame so culling and every
1685
+ // submission lane consume the same detached revision without repeat copies.
1686
+ const instanceSnapshotCache = new Map<
1687
+ InstanceCollectionId,
1688
+ ReturnType<InstanceCollectionStore['snapshot']>
1689
+ >();
1568
1690
  const skinnedMaterialSnapshotCache: MaterialSnapshotCache = new Map();
1569
1691
  // tweak-20260611 M1: MeshRenderer renderable archetype walk routes
1570
1692
  // through one World-owned Query. K-2 sniffing scheme B
1571
1693
  // (`row.get(X) !== undefined` edge sniff) replaces the prior
1572
1694
  // `arch.components.some` row-internal back-door. K-3 invariant: the
1573
1695
  // variable-length array reads (`MeshRenderer.materials`, SpriteInstances
1574
- // arrays) still flow through `_getArrayView`; explicit Instances bytes also come
1575
- // from World, before projection into renderer-owned snapshots.
1696
+ // arrays) still flow through `_getArrayView`; explicit Instances bytes come
1697
+ // from the renderer-owned collection store.
1576
1698
  //
1577
1699
  // archVersion remains the content fingerprint for SpriteInstances' managed
1578
1700
  // arrays; explicit Instances use the collection revision below and never
@@ -1643,7 +1765,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1643
1765
  // are not materialised merely to answer a boolean question.
1644
1766
  const hasTransform = row.has(Transform);
1645
1767
  const meshFilter = row.get(MeshFilter);
1646
- const hasInstances = row.has(Instances);
1768
+ const instancesData = row.get(Instances);
1769
+ const hasInstances = instancesData !== undefined;
1647
1770
  const skin = row.get(Skin);
1648
1771
  const morphWeightsView = worldInternal._getArrayView(row.entity, MorphWeights, 'weights');
1649
1772
  const hasMeshFilter = meshFilter !== undefined;
@@ -1760,9 +1883,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1760
1883
  () => 'renderer-override',
1761
1884
  );
1762
1885
  let materialBindingDiagnostics: MeshMaterialBindingDiagnostic[] = [];
1763
- let gpuDrivenSubmeshes: readonly MeshAsset['submeshes'][number][] = [];
1764
- let gpuDrivenIndexed = false;
1765
- let gpuDrivenGeometry: GpuDrivenGeometryReceipt | undefined;
1886
+ let gpuDrivenMesh: MeshAsset | undefined;
1766
1887
 
1767
1888
  // Resolve instance overrides against mesh-owned slot defaults once.
1768
1889
  const fAssetHandleVal = fAssetHandle;
@@ -1777,19 +1898,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
1777
1898
  if (meshRes.ok && meshRes.value.kind === 'mesh') {
1778
1899
  const meshAsset = meshRes.value as MeshAsset;
1779
1900
  const guid = (meshRes.value as { guid?: string }).guid ?? '<no-guid>';
1780
- gpuDrivenSubmeshes = meshAsset.submeshes;
1781
- gpuDrivenIndexed = meshAsset.indices !== undefined;
1782
- const layoutProjection = deriveVertexLayoutProjection(meshAsset.attributes);
1783
- gpuDrivenGeometry = {
1784
- identity: `${guid}:${layoutProjection.digest}`,
1785
- vertexInputs: layoutProjection.attributes.map((attribute) => ({
1786
- semantic: attribute.key,
1787
- location: attribute.shaderLocation,
1788
- format: attribute.format,
1789
- })),
1790
- topology: meshAsset.submeshes[0]?.topology ?? 'triangle-list',
1791
- indexed: gpuDrivenIndexed,
1792
- };
1901
+ gpuDrivenMesh = meshAsset;
1793
1902
  // extractFrames is also a public read path and can run before the
1794
1903
  // Renderer.draw pre-render stage. GlyphText proves the derived mesh
1795
1904
  // owns exactly one Default slot; arbitrary meshes still fail closed
@@ -2039,6 +2148,11 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2039
2148
  assets,
2040
2149
  materialContext,
2041
2150
  );
2151
+ const materialSceneIndexProgramKeys = materialSceneIndexProgramKeysForMaterial(
2152
+ asset,
2153
+ assets,
2154
+ materialContext,
2155
+ );
2042
2156
  const authoredFirstPassShader = runtimeMaterialShaderIdForMaterial(
2043
2157
  allPasses,
2044
2158
  undefined,
@@ -2241,6 +2355,16 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2241
2355
  ? assets.materialShaderTextureFieldNames(firstPassShader)
2242
2356
  : undefined,
2243
2357
  ) ?? BUILTIN_USER_REGION_TEXTURE_FIELDS;
2358
+ const authoredTextureFields = collectAuthoredMaterialTextureFields(
2359
+ resolved.values,
2360
+ firstPassShader,
2361
+ materialParamSchema.length > 0 ? materialParamSchema : undefined,
2362
+ assets,
2363
+ );
2364
+ const authoredSamplerFields = collectAuthoredMaterialSamplerFields(
2365
+ resolved.values,
2366
+ authoredTextureFields,
2367
+ );
2244
2368
  const textureHandles = new Map<string, Handle<'TextureAsset', 'shared'>>();
2245
2369
  const videoTextureFields = new Map<string, Handle<'VideoAsset', 'shared'>>();
2246
2370
  for (const field of userRegionFields) {
@@ -2274,7 +2398,15 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2274
2398
  pv.occlusionTexture,
2275
2399
  );
2276
2400
  const textureCoordinates = collectMaterialTextureCoordinates(pv);
2277
- const textureSources = collectMaterialTextureSources(pv, world);
2401
+ const textureSources = collectMaterialTextureSources(
2402
+ pv,
2403
+ world,
2404
+ materialTextureSourceFields(
2405
+ materialParamSchema.length > 0 ? materialParamSchema : undefined,
2406
+ ),
2407
+ materialTextureSourceStats,
2408
+ materialTextureSourceCache,
2409
+ );
2278
2410
  const emissivePv = pv.emissive as readonly number[] | undefined;
2279
2411
  // feat-20260625 M2 / w6: first-pass transparency flag folds into
2280
2412
  // MaterialSnapshot.transparent so the record stage can drive the
@@ -2366,12 +2498,20 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2366
2498
  normalScale: normalScalePv,
2367
2499
  materialShaderId: firstPassShader,
2368
2500
  materialProgramKeys,
2501
+ materialSceneIndexProgramKeys,
2369
2502
  materialHandle: handleRaw,
2370
2503
  renderState: pipelineRenderState(allPasses[0]?.renderState),
2371
2504
  paramSnapshot: paramSnap,
2372
2505
  ...(materialParamSchema.length > 0 && { materialParamSchema }),
2506
+ standardTextureMask: materialStandardTextureMask(
2507
+ resolved.parameters,
2508
+ firstPassShader,
2509
+ pv,
2510
+ ),
2373
2511
  ...(textureCoordinates.size > 0 && { textureCoordinates }),
2512
+ ...(authoredTextureFields === undefined ? {} : { authoredTextureFields }),
2374
2513
  ...(samplerHandles.size > 0 && { samplerHandles }),
2514
+ ...(authoredSamplerFields === undefined ? {} : { authoredSamplerFields }),
2375
2515
  ...(textureHandles.size > 0 && { textureHandles }),
2376
2516
  ...(textureSources.size > 0 && { textureSources }),
2377
2517
  ...(videoTextureFields.size > 0 && { videoTextureFields }),
@@ -2497,7 +2637,13 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2497
2637
  // T-21 placeholder ({0,0} discriminator-only sentinel) with full
2498
2638
  // resolve / validate / write chain (D-9 reset already fired at
2499
2639
  // extractFrame entry; per-entity allocate + writeJointPalette here).
2500
- let skinSlice: SkinPaletteSlice | undefined;
2640
+ let skinSlice: SkinPaletteReceipt | undefined;
2641
+ const skinIdentity = hasSkin ? skinPaletteIdentity(world, entity) : undefined;
2642
+ const releaseSkinIdentity = (): void => {
2643
+ if (skinIdentity !== undefined) {
2644
+ skinPaletteAllocator?.releasePersistentSlice(skinIdentity);
2645
+ }
2646
+ };
2501
2647
  if (hasSkin) {
2502
2648
  const skeletonHandleRaw = skinSkeletonView;
2503
2649
  if (
@@ -2512,7 +2658,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2512
2658
  severity: Severity.Error,
2513
2659
  systemName: 'RenderSystem.extract (skin-instances-coexist)',
2514
2660
  });
2515
-
2661
+ releaseSkinIdentity();
2516
2662
  continue;
2517
2663
  }
2518
2664
  // (a) Resolve skeleton asset; on failure -> skeleton-resolve-failed.
@@ -2523,13 +2669,17 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2523
2669
  severity: Severity.Error,
2524
2670
  systemName: 'RenderSystem.extract (skeleton-resolve-failed)',
2525
2671
  });
2672
+ releaseSkinIdentity();
2526
2673
  continue;
2527
2674
  }
2528
2675
  const skeleton = skeletonRes.value;
2529
2676
  // (b) Reuse the Skin row already read for its skeleton handle;
2530
2677
  // the old path repeated a second whole-row world.get here.
2531
2678
  const skinJoints = skin?.joints;
2532
- if (skinJoints === undefined) continue;
2679
+ if (skinJoints === undefined) {
2680
+ releaseSkinIdentity();
2681
+ continue;
2682
+ }
2533
2683
  const jointsLength = skinJoints.length;
2534
2684
  if (jointsLength !== skeleton.jointCount) {
2535
2685
  worldInternal._routeError(
@@ -2539,6 +2689,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2539
2689
  systemName: 'RenderSystem.extract (joint-count-mismatch)',
2540
2690
  },
2541
2691
  );
2692
+ releaseSkinIdentity();
2542
2693
  continue;
2543
2694
  }
2544
2695
  // (c) Resolve only each joint's GlobalTransform.world column. The
@@ -2569,6 +2720,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2569
2720
  severity: Severity.Error,
2570
2721
  systemName: 'RenderSystem.extract (joint-entity-dangling)',
2571
2722
  });
2723
+ releaseSkinIdentity();
2572
2724
  continue;
2573
2725
  }
2574
2726
  // (d) Slice the IBM flat Float32Array into per-joint Float32Arrays.
@@ -2578,29 +2730,25 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2578
2730
  for (let jIdx = 0; jIdx < skeleton.jointCount; jIdx++) {
2579
2731
  ibms[jIdx] = ibmFlat.subarray(jIdx * 16, jIdx * 16 + 16);
2580
2732
  }
2581
- // (e) Allocate slice + write palette via the allocator (D-9 reset
2582
- // already fired at extractFrame entry). When the pipelineState
2583
- // surface is absent (test fixtures that pass undefined) the
2584
- // hasSkin segment is skipped silently bind-pose equivalent.
2733
+ // (e) Reuse the persistent producer-owned slice for this stable
2734
+ // world/entity identity. Missing producer bounds remain explicit:
2735
+ // the receipt carries no invented bind-pose AABB and the shadow
2736
+ // admission lane can route the caster to CPU.
2585
2737
  if (skinPaletteAllocator !== null) {
2586
- // Keep the narrow extraction seam compatible with older test or
2587
- // host-owned allocator doubles while the real renderer uses the
2588
- // stable-key path. The fallback is frame-local and therefore
2589
- // cannot affect production allocators that implement the new
2590
- // method.
2591
- const slice =
2592
- typeof skinPaletteAllocator.allocateSliceFor === 'function'
2593
- ? skinPaletteAllocator.allocateSliceFor(
2594
- `${world.identity}:${entity}`,
2595
- skeleton.jointCount,
2596
- )
2597
- : skinPaletteAllocator.allocateSlice(skeleton.jointCount);
2598
- skinPaletteAllocator.writeJointPalette(slice, ibms, jointWorlds);
2599
- skinSlice = {
2600
- jointCount: slice.jointCount,
2601
- byteOffset: slice.byteOffset,
2602
- buffer: slice.buffer,
2603
- };
2738
+ const identity = skinPaletteIdentity(world, entity);
2739
+ const generation = (skeletonHandleRaw >>> 0) ^ skeleton.jointCount;
2740
+ const bounds = hasFiniteOrderedLocalAabb(skeleton.bounds)
2741
+ ? new Float32Array(skeleton.bounds)
2742
+ : undefined;
2743
+ skinPaletteAllocator.observePersistentJoints(identity, ibms, jointWorlds);
2744
+ const receipt = skinPaletteAllocator.allocatePersistentSlice({
2745
+ identity,
2746
+ generation: generation >>> 0,
2747
+ jointCount: skeleton.jointCount,
2748
+ ...(bounds === undefined ? {} : { bounds }),
2749
+ });
2750
+ skinPaletteAllocator.writePersistentJointPalette(receipt, ibms, jointWorlds);
2751
+ skinSlice = receipt;
2604
2752
  }
2605
2753
  }
2606
2754
  }
@@ -2609,9 +2757,12 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2609
2757
  // projection. Do not publish a renderable or its staged dispatch when
2610
2758
  // palette extraction was unavailable; the record stage must never
2611
2759
  // reinterpret a skinned vertex stream through an ordinary mesh group.
2612
- if (materialSnap.materialShaderId === 'forgeax::pbr-skin' && skinSlice === undefined) {
2613
- pendingDispatch.length = 0;
2614
- continue;
2760
+ if (skinSlice === undefined && hasSkin) {
2761
+ releaseSkinIdentity();
2762
+ if (materialSnap.materialShaderId === 'forgeax::pbr-skin') {
2763
+ pendingDispatch.length = 0;
2764
+ continue;
2765
+ }
2615
2766
  }
2616
2767
 
2617
2768
  // feat-20260601 D-3: read the resolved world mat4 (propagateTransforms
@@ -2622,7 +2773,10 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2622
2773
  // tweak-20260611 M1 / K-3: `_getArrayView` call survives untouched;
2623
2774
  // only the `entity` source switched to `bundle.Entity.self[i]`.
2624
2775
  const worldView = worldInternal._getArrayView(entity, GlobalTransform, 'world');
2625
- if (worldView === undefined) continue;
2776
+ if (worldView === undefined) {
2777
+ releaseSkinIdentity();
2778
+ continue;
2779
+ }
2626
2780
  const worldMat = new Float32Array(worldView);
2627
2781
  const transformSnap: TransformSnapshot = { world: worldMat };
2628
2782
  // feat-20260608 M5 amend / w11-a: per-submesh `materials[]` array
@@ -2654,6 +2808,8 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2654
2808
  ...context.materialContext,
2655
2809
  geometry: hasSkin ? 'skinned' : context.materialContext.geometry,
2656
2810
  },
2811
+ materialTextureSourceStats,
2812
+ materialTextureSourceCache,
2657
2813
  ),
2658
2814
  );
2659
2815
  }
@@ -2778,7 +2934,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2778
2934
  lods = meshAsset.lods;
2779
2935
  lodHysteresis = meshAsset.lodHysteresis;
2780
2936
  morph = morphSnapshotFor(meshAsset, morphWeightsView);
2781
- const meshAabb = meshAsset.aabb;
2937
+ const meshAabb = skinSlice?.bounds ?? meshAsset.aabb;
2782
2938
  // Morph targets can expand the authored bounds. Keep the
2783
2939
  // specialized lane conservative until a target-aware bounds
2784
2940
  // projection is available; a false-positive draw is preferable
@@ -2805,7 +2961,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2805
2961
  pointsLinesComponent === undefined
2806
2962
  ? undefined
2807
2963
  : ({
2808
- worldId: 0,
2964
+ worldId: context.worldId,
2809
2965
  entityKey: entity,
2810
2966
  component: pointsLinesComponent,
2811
2967
  meshHandle: assetHandleRaw,
@@ -2828,30 +2984,48 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2828
2984
  // make the cull and draw disagree within one frame).
2829
2985
  let instancesSnap: InstancesSnapshot | undefined;
2830
2986
  if (hasInstances) {
2831
- const transforms =
2832
- worldInternal._getArrayView(entity, Instances, 'transforms') ?? new Float32Array();
2833
- if (transforms.length % 16 !== 0) {
2834
- worldInternal._routeError(
2835
- new InstanceTransformsStrideMismatchError(transforms.length),
2836
- {
2837
- severity: Severity.Error,
2838
- systemName: 'RenderSystem.extract (Instances stride)',
2839
- },
2840
- );
2987
+ const collectionId = instancesData?.collectionId as InstanceCollectionId | undefined;
2988
+ let collectionResult =
2989
+ collectionId !== undefined ? instanceSnapshotCache.get(collectionId) : undefined;
2990
+ if (collectionResult === undefined) {
2991
+ collectionResult =
2992
+ collectionId !== undefined && collectionId > 0 && instanceCollections !== undefined
2993
+ ? instanceCollections.snapshot(collectionId)
2994
+ : err(
2995
+ new InstanceCollectionError(
2996
+ 'instance-collection-invalid',
2997
+ 'Instances.collectionId references a live renderer-owned collection',
2998
+ 'create the collection through renderer.instances before attaching Instances',
2999
+ {
3000
+ operation: 'inspect',
3001
+ expected: 'a positive collectionId with a live renderer owner',
3002
+ actual: Number(collectionId ?? 0),
3003
+ ...(collectionId === undefined ? {} : { collectionId }),
3004
+ },
3005
+ ),
3006
+ );
3007
+ if (collectionId !== undefined)
3008
+ instanceSnapshotCache.set(collectionId, collectionResult);
3009
+ }
3010
+ if (collectionResult === undefined) continue;
3011
+ if (!collectionResult.ok) {
3012
+ worldInternal._routeError(collectionResult.error, {
3013
+ severity: Severity.Error,
3014
+ systemName: 'RenderSystem.extract (Instances collection)',
3015
+ });
2841
3016
  continue;
2842
3017
  }
2843
- const projected = instanceCollections?.project(world, entity, transforms);
2844
3018
  instancesSnap = {
2845
- transforms: projected?.transforms ?? new Float32Array(transforms),
2846
- instanceCount: transforms.length / 16,
3019
+ transforms: collectionResult.value.transforms,
3020
+ instanceCount: collectionResult.value.count,
3021
+ collectionId: collectionResult.value.collectionId,
3022
+ revision: collectionResult.value.revision,
3023
+ capacity: collectionResult.value.capacity,
3024
+ dirtyRanges: collectionResult.value.dirtyRanges,
2847
3025
  cacheKey: entity,
2848
- archVersion: projected === undefined ? fingerprintNumericArray(transforms) : 0,
2849
- ...(projected === undefined
2850
- ? {}
2851
- : {
2852
- collectionId: projected.collectionId,
2853
- revision: projected.revision,
2854
- }),
3026
+ // Explicit collection revisions supersede ECS archetype content
3027
+ // hashes; retain zero as the legacy sprite-only field value.
3028
+ archVersion: 0,
2855
3029
  };
2856
3030
  }
2857
3031
 
@@ -2865,7 +3039,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2865
3039
  materials: materialsArr,
2866
3040
  materialBindingSources,
2867
3041
  materialBindingDiagnostics,
2868
- worldId: 0,
3042
+ worldId: context.worldId,
2869
3043
  entityKey: entity,
2870
3044
  ...(authorVisible ? {} : { authorVisible: false }),
2871
3045
  ...(skinSlice !== undefined ? { skin: skinSlice } : {}),
@@ -2878,34 +3052,27 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2878
3052
  ...(pointsLines !== undefined ? { pointsLines } : {}),
2879
3053
  };
2880
3054
  const gpuDrivenDraws = buildGpuDrivenDraws({
2881
- submeshes: gpuDrivenSubmeshes,
2882
- indexed: gpuDrivenIndexed,
3055
+ mesh: gpuDrivenMesh,
2883
3056
  materials: materialsArr,
2884
3057
  fallbackMaterial: materialSnap,
2885
- ...(gpuDrivenGeometry === undefined || getMaterialShaderArtifact === undefined
3058
+ baseSnapshot: baseRenderable,
3059
+ ...(getMaterialShaderArtifact === undefined ? {} : { getMaterialShaderArtifact }),
3060
+ ...(lods === undefined
2886
3061
  ? {}
2887
3062
  : {
2888
- prepare(draw, drawMaterial) {
2889
- const materialShaderId = drawMaterial.materialShaderId;
2890
- if (materialShaderId === undefined) return undefined;
2891
- const artifact = getMaterialShaderArtifact(materialShaderId);
2892
- if (artifact?.receipt === undefined) return undefined;
2893
- const geometry: GpuDrivenGeometryReceipt = {
2894
- ...gpuDrivenGeometry,
2895
- topology: draw.topology,
2896
- indexed: draw.kind === 'indexed',
2897
- };
2898
- const result = resolvePreparedGpuDrivenDraw({
2899
- snapshot: { ...baseRenderable, material: drawMaterial },
2900
- artifact,
2901
- geometry,
2902
- generation: artifact.receipt.generation,
2903
- draw,
2904
- });
2905
- return result.ok ? result.value : undefined;
2906
- },
3063
+ lodMeshes: lods.map((lod) => {
3064
+ const lower = assets?.lookup<Asset>(lod.mesh);
3065
+ return lower?.kind === 'mesh' ? lower : undefined;
3066
+ }),
2907
3067
  }),
2908
3068
  });
3069
+ for (const draw of gpuDrivenDraws) {
3070
+ if (draw.preparationError === undefined) continue;
3071
+ worldInternal._routeError(draw.preparationError, {
3072
+ severity: Severity.Error,
3073
+ systemName: `RenderSystem.extract (gpu-driven-preparation:${draw.preparationError.code})`,
3074
+ });
3075
+ }
2909
3076
  const renderable =
2910
3077
  morph === undefined && gpuDrivenDraws.length > 0
2911
3078
  ? { ...baseRenderable, gpuDrivenDraws }
@@ -2975,13 +3142,86 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2975
3142
  }
2976
3143
  if (!visible) {
2977
3144
  frustumCulled += 1;
2978
- continue;
3145
+ const shadowVisible =
3146
+ shadowFrusta.length > 0 &&
3147
+ pendingDispatch.some((entry) => entry.tags.LightMode === 'ShadowCaster') &&
3148
+ shadowFrusta.some((lightPlanes) =>
3149
+ frustum.intersectsBox(lightPlanes, worldAabb as box3.Box3Like),
3150
+ );
3151
+ if (!shadowVisible) continue;
3152
+ // Shadow-only renderables stay in the detached snapshot for the
3153
+ // depth passes, but must not leak their forward/transparent
3154
+ // dispatch entries into the main camera submission.
3155
+ for (let i = pendingDispatch.length - 1; i >= 0; i -= 1) {
3156
+ if (pendingDispatch[i]?.tags.LightMode !== 'ShadowCaster') {
3157
+ pendingDispatch.splice(i, 1);
3158
+ }
3159
+ }
2979
3160
  }
2980
3161
  }
2981
3162
  }
2982
3163
 
3164
+ const localShadowMembershipEntries: ShadowCasterMembership[] = [];
3165
+ if (gpuDrivenMesh !== undefined) {
3166
+ const worldEntity = worldEntityKey(context.worldId, entity);
3167
+ for (const [drawItemIndex, submesh] of gpuDrivenMesh.submeshes.entries()) {
3168
+ if (submesh.topology !== 'triangle-list' && submesh.topology !== 'triangle-strip') {
3169
+ continue;
3170
+ }
3171
+ const material = materialsArr[submesh.materialSlot] ?? materialSnap;
3172
+ const materialHandle = material.materialHandle ?? -1;
3173
+ const shadowEntries = pendingDispatch.filter(
3174
+ (entry) =>
3175
+ entry.tags.LightMode === 'ShadowCaster' && entry.materialHandle === materialHandle,
3176
+ );
3177
+ const draw = renderable.gpuDrivenDraws?.find(
3178
+ (candidate, compactIndex) =>
3179
+ gpuDrivenSourceDrawItemIndex(candidate, compactIndex) === drawItemIndex,
3180
+ );
3181
+ const cpuReason = shadowCasterCpuReason(
3182
+ material,
3183
+ draw,
3184
+ shadowEntries,
3185
+ morph,
3186
+ skinSlice,
3187
+ );
3188
+ for (const entry of shadowEntries) {
3189
+ const membership: ShadowCasterMembership = {
3190
+ worldEntity,
3191
+ renderableIndex: renderables.length,
3192
+ drawItemIndex,
3193
+ materialHandle,
3194
+ passIndex: entry.passIndex,
3195
+ ...(entry.materialShaderId === undefined
3196
+ ? {}
3197
+ : { materialShaderId: entry.materialShaderId }),
3198
+ ...(entry.vertexEntry === undefined ? {} : { vertexEntry: entry.vertexEntry }),
3199
+ ...(entry.fragmentEntry === undefined
3200
+ ? {}
3201
+ : { fragmentEntry: entry.fragmentEntry }),
3202
+ ...(entry.renderState === undefined ? {} : { renderState: entry.renderState }),
3203
+ ...(cpuReason === undefined ? {} : { cpuReason }),
3204
+ gpuDrivenEligible: cpuReason === undefined,
3205
+ };
3206
+ shadowMembershipEntries.push(membership);
3207
+ localShadowMembershipEntries.push(membership);
3208
+ }
3209
+ }
3210
+ }
3211
+ const shadowCasterPasses = localShadowMembershipEntries.map((membership) => ({
3212
+ drawItemIndex: membership.drawItemIndex,
3213
+ materialHandle: membership.materialHandle,
3214
+ passIndex: membership.passIndex,
3215
+ ...(membership.materialShaderId === undefined
3216
+ ? {}
3217
+ : { materialShaderId: membership.materialShaderId }),
3218
+ ...(membership.renderState === undefined ? {} : { renderState: membership.renderState }),
3219
+ ...(membership.cpuReason === undefined ? {} : { cpuReason: membership.cpuReason }),
3220
+ }));
3221
+ const renderableWithShadowPasses =
3222
+ shadowCasterPasses.length === 0 ? renderable : { ...renderable, shadowCasterPasses };
2983
3223
  flushPendingDispatch(pendingDispatch);
2984
- renderables.push(renderable);
3224
+ renderables.push(renderableWithShadowPasses);
2985
3225
  }
2986
3226
 
2987
3227
  // feat-20260520-2d-sprite-layer-mvp M-3 / w22 + w25: finalise the
@@ -2998,6 +3238,28 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
2998
3238
  // M3 / w26: sort dispatch entries by queue (ascending, stable sort)
2999
3239
  // per plan-strategy D-3.
3000
3240
  dispatch = sortDispatchByQueue(dispatch);
3241
+ const shadowCasterEntityKeys = new Set<number>();
3242
+ const shadowCasterDrawKeys = new Set<string>();
3243
+ const shadowCasterMembership = new Map<string, ShadowCasterMembership>();
3244
+ for (const entry of dispatch) {
3245
+ if (entry.tags.LightMode !== 'ShadowCaster') continue;
3246
+ const renderable = renderables[entry.renderableIndex];
3247
+ if (renderable !== undefined) {
3248
+ const worldEntity = worldEntityKey(renderable.worldId, renderable.entityKey);
3249
+ shadowCasterEntityKeys.add(worldEntity);
3250
+ }
3251
+ }
3252
+ for (const membership of shadowMembershipEntries) {
3253
+ const key = gpuDrivenShadowDrawKey(
3254
+ membership.worldEntity,
3255
+ membership.materialHandle,
3256
+ membership.drawItemIndex,
3257
+ membership.passIndex,
3258
+ );
3259
+ shadowCasterDrawKeys.add(key);
3260
+ shadowCasterMembership.set(key, membership);
3261
+ shadowCasterEntityKeys.add(membership.worldEntity);
3262
+ }
3001
3263
 
3002
3264
  // D-1: collect PostProcessParams entities into Map<shaderId, Uint8Array>.
3003
3265
  // Last-one-wins when multiple entities bear the same shader id (mirrors
@@ -3041,6 +3303,11 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
3041
3303
  ...(volumetricFog === undefined ? {} : { volumetricFog }),
3042
3304
  renderables,
3043
3305
  dispatch,
3306
+ shadowCasterEntityKeys,
3307
+ shadowCasterDrawKeys,
3308
+ ...(shadowCasterMembership.size === 0
3309
+ ? {}
3310
+ : { shadowCasterMembership: [...shadowCasterMembership.values()] }),
3044
3311
  skylight,
3045
3312
  skylightCount,
3046
3313
  lightProbes,
@@ -3050,6 +3317,7 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
3050
3317
  ...(fogFailure === undefined ? {} : { fogFailure }),
3051
3318
  frustumStats: { culled: frustumCulled, total: frustumTotal },
3052
3319
  visibilityStats: { explicitlyHidden: explicitlyHidden.size },
3320
+ materialTextureSources: materialTextureSourceStats,
3053
3321
  postProcessParams,
3054
3322
  visibilitySnapshots: [context.visibility],
3055
3323
  featureVisibilitySnapshots: [{ world, snapshot: context.visibility }],
@@ -3057,17 +3325,18 @@ export function extractFrame(world: World, context: PreparedExtractContext): Ext
3057
3325
  };
3058
3326
  }
3059
3327
 
3328
+ /** Immutable author-independent default; extraction retains its producer identity. */
3329
+ const DEFAULT_MATERIAL_SNAPSHOT: MaterialSnapshot = Object.freeze({
3330
+ baseColor: vec3.create(0.5, 0.5, 0.5),
3331
+ metallic: 0,
3332
+ roughness: 1,
3333
+ materialHandle: 0,
3334
+ });
3335
+
3060
3336
  export function defaultMaterialSnapshot(materialHandle = 0): MaterialSnapshot {
3061
- // Mid-grey unlit fallback (D-Q7 case B + extract-stage missing-spec),
3062
- // matching the pre-w6 visual outcome where the record stage's force-cast
3063
- // read of `firstMaterial.baseColorTexture` returned undefined and the
3064
- // unlit fallback shader was selected.
3065
- return {
3066
- baseColor: vec3.create(0.5, 0.5, 0.5),
3067
- metallic: 0,
3068
- roughness: 1,
3069
- materialHandle,
3070
- };
3337
+ return materialHandle === 0
3338
+ ? DEFAULT_MATERIAL_SNAPSHOT
3339
+ : { ...DEFAULT_MATERIAL_SNAPSHOT, materialHandle };
3071
3340
  }
3072
3341
 
3073
3342
  function identityProjection(): Float32Array {