@forgeax/engine-render 0.1.27 → 0.1.29

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 (655) hide show
  1. package/README.md +842 -124
  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/dynamic-geometry-host.d.ts +52 -0
  5. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -0
  6. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  7. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +3 -1
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  11. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  12. package/dist/assembly/host-contract.d.ts +19 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +7 -0
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material-shader-policy.d.ts +3 -1
  17. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  18. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  19. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  20. package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
  21. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  22. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  23. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  24. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  25. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  26. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  27. package/dist/assembly/renderer-helpers.d.ts +3 -0
  28. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  29. package/dist/assembly/renderer-inspection.d.ts +4 -0
  30. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  31. package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
  32. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  33. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  34. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  35. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  36. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  37. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  38. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  41. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  42. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +7 -3
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  46. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  47. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  48. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  49. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  50. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  51. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  52. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  53. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  54. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  55. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  56. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  57. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  58. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  59. package/dist/authoring.mjs +3 -3
  60. package/dist/{chunk-ADHHVYLW.mjs → chunk-33XZFTQU.mjs} +245 -39
  61. package/dist/chunk-33XZFTQU.mjs.map +1 -0
  62. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  63. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  64. package/dist/{chunk-KM2NOX2I.mjs → chunk-BQVQOQJH.mjs} +958 -254
  65. package/dist/chunk-BQVQOQJH.mjs.map +1 -0
  66. package/dist/{chunk-HKXTW355.mjs → chunk-BTWH7BP4.mjs} +386 -17
  67. package/dist/chunk-BTWH7BP4.mjs.map +1 -0
  68. package/dist/{chunk-TMIASV2N.mjs → chunk-FUODTTIA.mjs} +3934 -676
  69. package/dist/chunk-FUODTTIA.mjs.map +1 -0
  70. package/dist/{chunk-FJ6P52EE.mjs → chunk-ILQ5MEZF.mjs} +3 -17
  71. package/dist/chunk-ILQ5MEZF.mjs.map +1 -0
  72. package/dist/{chunk-E34VL5VI.mjs → chunk-JQTSEI3Z.mjs} +3 -3
  73. package/dist/{chunk-E34VL5VI.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
  74. package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
  75. package/dist/chunk-NICXSHAT.mjs.map +1 -0
  76. package/dist/{chunk-ZZ4YQ474.mjs → chunk-NRNXBLIJ.mjs} +577 -7
  77. package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
  78. package/dist/{chunk-JDWARUOI.mjs → chunk-PA5DRJNI.mjs} +17 -3
  79. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  80. package/dist/{chunk-XDP6XE5V.mjs → chunk-S4DNKQYQ.mjs} +1118 -446
  81. package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
  82. package/dist/components/camera.d.ts +62 -2
  83. package/dist/components/camera.d.ts.map +1 -1
  84. package/dist/components/index.d.ts +1 -0
  85. package/dist/components/index.d.ts.map +1 -1
  86. package/dist/components/instances.d.ts +6 -20
  87. package/dist/components/instances.d.ts.map +1 -1
  88. package/dist/components/scene-instance.d.ts +2 -1
  89. package/dist/components/scene-instance.d.ts.map +1 -1
  90. package/dist/components/screen-space-reflection.d.ts +14 -0
  91. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  92. package/dist/construct-renderer.mjs +13805 -7186
  93. package/dist/construct-renderer.mjs.map +1 -1
  94. package/dist/device/gpu-residency.d.ts +11 -17
  95. package/dist/device/gpu-residency.d.ts.map +1 -1
  96. package/dist/device/mesh-residency-lifetime.d.ts +21 -0
  97. package/dist/device/mesh-residency-lifetime.d.ts.map +1 -0
  98. package/dist/dynamic-geometry.d.ts +125 -0
  99. package/dist/dynamic-geometry.d.ts.map +1 -0
  100. package/dist/environment/background.d.ts +6 -0
  101. package/dist/environment/background.d.ts.map +1 -0
  102. package/dist/errors/gpu-driven.d.ts +6 -3
  103. package/dist/errors/gpu-driven.d.ts.map +1 -1
  104. package/dist/errors/render.d.ts +7 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/extract/camera.d.ts.map +1 -1
  107. package/dist/extract/gpu-driven.d.ts +33 -3
  108. package/dist/extract/gpu-driven.d.ts.map +1 -1
  109. package/dist/features/host.d.ts +23 -1
  110. package/dist/features/host.d.ts.map +1 -1
  111. package/dist/features/noise-texture.d.ts +17 -0
  112. package/dist/features/noise-texture.d.ts.map +1 -0
  113. package/dist/features/plan.d.ts +83 -2
  114. package/dist/features/plan.d.ts.map +1 -1
  115. package/dist/features/prepared-gpu-work.d.ts +37 -4
  116. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  117. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  118. package/dist/features/prepared-graphics.d.ts +5 -0
  119. package/dist/features/prepared-graphics.d.ts.map +1 -1
  120. package/dist/features/render-graph-compute.d.ts +5 -3
  121. package/dist/features/render-graph-compute.d.ts.map +1 -1
  122. package/dist/features/render-graph-contribution.d.ts +11 -3
  123. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  124. package/dist/features/render-graph-raster.d.ts +19 -3
  125. package/dist/features/render-graph-raster.d.ts.map +1 -1
  126. package/dist/features/types.d.ts +11 -0
  127. package/dist/features/types.d.ts.map +1 -1
  128. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  129. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  130. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  131. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  132. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  133. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  134. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  135. package/dist/gpu-driven/production-raster.d.ts +144 -23
  136. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  137. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  138. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  139. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  140. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  141. package/dist/gpu-scene-schema.d.ts +2 -8
  142. package/dist/gpu-scene-schema.d.ts.map +1 -1
  143. package/dist/gpu-scene.d.ts +14 -0
  144. package/dist/gpu-scene.d.ts.map +1 -1
  145. package/dist/gpu-texture-usage.d.ts +1 -0
  146. package/dist/gpu-texture-usage.d.ts.map +1 -1
  147. package/dist/hdrp-buffers.d.ts +6 -0
  148. package/dist/hdrp-buffers.d.ts.map +1 -1
  149. package/dist/ibl/frame-resources.d.ts +8 -0
  150. package/dist/ibl/frame-resources.d.ts.map +1 -0
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +21 -8
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +8 -7
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +164 -0
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instances-derived-bounds.d.ts +11 -0
  159. package/dist/instances-derived-bounds.d.ts.map +1 -1
  160. package/dist/instances.d.ts +89 -44
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.d.ts +3 -0
  163. package/dist/internal.d.ts.map +1 -1
  164. package/dist/internal.mjs +118 -10
  165. package/dist/internal.mjs.map +1 -1
  166. package/dist/lifecycle.d.ts +2 -1
  167. package/dist/lifecycle.d.ts.map +1 -1
  168. package/dist/material-row.d.ts +5 -0
  169. package/dist/material-row.d.ts.map +1 -0
  170. package/dist/materials.d.ts +15 -0
  171. package/dist/materials.d.ts.map +1 -1
  172. package/dist/pbr-pipeline.d.ts +21 -5
  173. package/dist/pbr-pipeline.d.ts.map +1 -1
  174. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  175. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  176. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  177. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  178. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  179. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  180. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  181. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  182. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  183. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  184. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  185. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  186. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  187. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  188. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  189. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  190. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  191. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  192. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  193. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  194. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  195. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  196. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  197. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  198. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  199. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  200. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  201. package/dist/pipeline/standard-output/types.d.ts +39 -0
  202. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  203. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  204. package/dist/pipeline/standard-post.d.ts +2 -2
  205. package/dist/pipeline/standard-post.d.ts.map +1 -1
  206. package/dist/pipeline-builder.d.ts +2 -1
  207. package/dist/pipeline-builder.d.ts.map +1 -1
  208. package/dist/pipeline-spec-types.d.ts +4 -0
  209. package/dist/pipeline-spec-types.d.ts.map +1 -1
  210. package/dist/pipeline-spec.d.ts +1 -9
  211. package/dist/pipeline-spec.d.ts.map +1 -1
  212. package/dist/points-lines/standard-owner.d.ts +1 -1
  213. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  214. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  215. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  216. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  217. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  218. package/dist/record/frame-lighting.d.ts +3 -3
  219. package/dist/record/frame-lighting.d.ts.map +1 -1
  220. package/dist/record/frame-snapshot.d.ts +106 -5
  221. package/dist/record/frame-snapshot.d.ts.map +1 -1
  222. package/dist/record/frame-targets.d.ts.map +1 -1
  223. package/dist/record/frame.d.ts +39 -4
  224. package/dist/record/frame.d.ts.map +1 -1
  225. package/dist/record/main-pass-geometry.d.ts +7 -8
  226. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  227. package/dist/record/main-pass-material.d.ts +38 -1
  228. package/dist/record/main-pass-material.d.ts.map +1 -1
  229. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  230. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  231. package/dist/record/main-pass.d.ts +12 -2
  232. package/dist/record/main-pass.d.ts.map +1 -1
  233. package/dist/record/mesh-ssbo.d.ts +15 -6
  234. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  235. package/dist/record/prepared-material-bindings.d.ts +19 -0
  236. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  237. package/dist/record/recovery-pipeline.d.ts +2 -9
  238. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  239. package/dist/record/render-context.d.ts +76 -26
  240. package/dist/record/render-context.d.ts.map +1 -1
  241. package/dist/record/shadow-pass.d.ts +62 -7
  242. package/dist/record/shadow-pass.d.ts.map +1 -1
  243. package/dist/record/skybox-post-pass.d.ts +1 -1
  244. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  245. package/dist/record/typed-frame-graph.d.ts +35 -7
  246. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  247. package/dist/record/view-ubo.d.ts +1 -0
  248. package/dist/record/view-ubo.d.ts.map +1 -1
  249. package/dist/recovery/render-system-candidate.d.ts +10 -2
  250. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  251. package/dist/recovery/render-system-roots.d.ts +11 -0
  252. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  253. package/dist/recovery/types.d.ts +76 -0
  254. package/dist/recovery/types.d.ts.map +1 -0
  255. package/dist/reflection/record-owner.d.ts +0 -2
  256. package/dist/reflection/record-owner.d.ts.map +1 -1
  257. package/dist/render-contract.d.ts +185 -30
  258. package/dist/render-contract.d.ts.map +1 -1
  259. package/dist/render-graph-primitives.d.ts +1 -0
  260. package/dist/render-graph-primitives.d.ts.map +1 -1
  261. package/dist/render-pipeline.d.ts +64 -5
  262. package/dist/render-pipeline.d.ts.map +1 -1
  263. package/dist/render-system-extract-tail.d.ts +7 -5
  264. package/dist/render-system-extract-tail.d.ts.map +1 -1
  265. package/dist/render-system-extract.d.ts +101 -41
  266. package/dist/render-system-extract.d.ts.map +1 -1
  267. package/dist/render-system-projections.d.ts +22 -0
  268. package/dist/render-system-projections.d.ts.map +1 -0
  269. package/dist/render-system.d.ts +34 -77
  270. package/dist/render-system.d.ts.map +1 -1
  271. package/dist/scene/render-scene-types.d.ts +14 -7
  272. package/dist/scene/render-scene-types.d.ts.map +1 -1
  273. package/dist/scene/render-scene.d.ts +29 -11
  274. package/dist/scene/render-scene.d.ts.map +1 -1
  275. package/dist/scene/shadow-visibility.d.ts +5 -0
  276. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  277. package/dist/ssr/admission.d.ts +70 -1
  278. package/dist/ssr/admission.d.ts.map +1 -1
  279. package/dist/ssr/compose.d.ts +13 -0
  280. package/dist/ssr/compose.d.ts.map +1 -0
  281. package/dist/ssr/errors.d.ts +35 -0
  282. package/dist/ssr/errors.d.ts.map +1 -1
  283. package/dist/ssr/graph.d.ts +60 -0
  284. package/dist/ssr/graph.d.ts.map +1 -0
  285. package/dist/ssr/history.d.ts +97 -0
  286. package/dist/ssr/history.d.ts.map +1 -0
  287. package/dist/ssr/hiz.d.ts +37 -0
  288. package/dist/ssr/hiz.d.ts.map +1 -0
  289. package/dist/ssr/inspection.d.ts +42 -0
  290. package/dist/ssr/inspection.d.ts.map +1 -0
  291. package/dist/ssr/resources.d.ts +58 -0
  292. package/dist/ssr/resources.d.ts.map +1 -0
  293. package/dist/ssr/temporal.d.ts +38 -0
  294. package/dist/ssr/temporal.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  296. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  297. package/dist/systems/skin-palette-types.d.ts +15 -0
  298. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  299. package/dist/systems/transparent-dispatch.d.ts +9 -0
  300. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  301. package/dist/targets/material-source.d.ts +7 -0
  302. package/dist/targets/material-source.d.ts.map +1 -1
  303. package/dist/temporal/frame-coordinator.d.ts +7 -0
  304. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  305. package/dist/temporal/gpu.d.ts +8 -0
  306. package/dist/temporal/gpu.d.ts.map +1 -1
  307. package/dist/temporal/history.d.ts.map +1 -1
  308. package/dist/temporal/index.mjs +6 -6
  309. package/dist/temporal/inspection.d.ts.map +1 -1
  310. package/dist/temporal/standard-scene-data.d.ts +2 -1
  311. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  312. package/dist/temporal/temporal-view.d.ts +2 -0
  313. package/dist/temporal/temporal-view.d.ts.map +1 -1
  314. package/dist/typed-render-graph-primitives.d.ts +35 -1
  315. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  316. package/dist/typed-shadow-passes.d.ts +3 -1
  317. package/dist/typed-shadow-passes.d.ts.map +1 -1
  318. package/dist/volume/temporal.d.ts +6 -0
  319. package/dist/volume/temporal.d.ts.map +1 -1
  320. package/package.json +21 -20
  321. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  322. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  323. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  324. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  325. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  326. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  327. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  328. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  329. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  330. package/src/__tests__/dynamic-geometry-host.unit.test.ts +1123 -0
  331. package/src/__tests__/dynamic-geometry.unit.test.ts +233 -0
  332. package/src/__tests__/factory-contract.integration.test.ts +73 -22
  333. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  334. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  335. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  336. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  337. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  338. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  339. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  340. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  341. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  342. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
  343. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  344. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  345. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
  346. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
  347. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
  348. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  349. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  350. package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
  351. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  352. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  353. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  354. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  355. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  356. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  357. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  358. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  359. package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
  360. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
  361. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  362. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  363. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  364. package/src/__tests__/gpu-scene.unit.test.ts +559 -33
  365. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  366. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  367. package/src/__tests__/instances-store.unit.test.ts +242 -39
  368. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  369. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  370. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  371. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  372. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  373. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  374. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  375. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  376. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  377. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  378. package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
  379. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  380. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +53 -0
  381. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  382. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  383. package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
  384. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  385. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  386. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  387. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  388. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
  389. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  390. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  391. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  392. package/src/__tests__/public-surface.test-d.ts +3 -0
  393. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  394. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
  395. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
  396. package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
  397. package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
  398. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  399. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  400. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  401. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  402. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  403. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  404. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  405. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  406. package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
  407. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  408. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  409. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  410. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  411. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +61 -1
  412. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  413. package/src/__tests__/shader-manifest-fixture.ts +39 -0
  414. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  415. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  416. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  417. package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
  418. package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
  419. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  420. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  421. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  422. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  423. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
  424. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
  425. package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
  426. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  427. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  428. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  429. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  430. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  431. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  432. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  433. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  434. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  435. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  436. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  437. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  438. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  439. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  440. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  441. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  442. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  443. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  444. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  445. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  446. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  447. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  448. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
  449. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  450. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  451. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  452. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  453. package/src/__tests__/standard-output.browser.test.ts +15 -0
  454. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  455. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
  456. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  457. package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
  458. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  459. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  460. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  461. package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
  462. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  463. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
  464. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  465. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  466. package/src/__tests__/taa-stability-feedback.ts +341 -0
  467. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  468. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  469. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  470. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  471. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  472. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  473. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  474. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  475. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  476. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  477. package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
  478. package/src/assembly/dynamic-geometry-host.ts +887 -0
  479. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  480. package/src/assembly/factory.ts +4 -0
  481. package/src/assembly/gpu-driven-owner.ts +29 -0
  482. package/src/assembly/host-contract.ts +36 -0
  483. package/src/assembly/material/assembly.ts +38 -0
  484. package/src/assembly/material-shader-policy.ts +71 -28
  485. package/src/assembly/recovery/failure-location.ts +62 -0
  486. package/src/assembly/recovery/renderer-recover.ts +19 -17
  487. package/src/assembly/renderer-facade.ts +29 -0
  488. package/src/assembly/renderer-feature-inspection.ts +13 -0
  489. package/src/assembly/renderer-frame-transaction.ts +63 -0
  490. package/src/assembly/renderer-helpers.ts +26 -0
  491. package/src/assembly/renderer-inspection.ts +6 -0
  492. package/src/assembly/shader-prewarm-policy.ts +32 -0
  493. package/src/assembly/skin-palette-owner.ts +21 -0
  494. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  495. package/src/assembly/webgpu-device-loss.ts +75 -0
  496. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  497. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  498. package/src/assembly/webgpu-ready.ts +142 -121
  499. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  500. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  501. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  502. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  503. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  504. package/src/assembly/webgpu-renderer.ts +675 -614
  505. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  506. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  507. package/src/components/camera.ts +287 -7
  508. package/src/components/index.ts +1 -0
  509. package/src/components/instances.ts +45 -18
  510. package/src/components/scene-instance.ts +2 -1
  511. package/src/components/screen-space-reflection.ts +21 -0
  512. package/src/components/sprite-animation.ts +3 -3
  513. package/src/components/sprite-instances.ts +1 -1
  514. package/src/device/gpu-residency.ts +96 -93
  515. package/src/device/mesh-residency-lifetime.ts +73 -0
  516. package/src/dynamic-geometry.ts +736 -0
  517. package/src/environment/background.ts +263 -0
  518. package/src/errors/gpu-driven.ts +39 -5
  519. package/src/errors/render.ts +27 -3
  520. package/src/extract/camera.ts +26 -1
  521. package/src/extract/gpu-driven.ts +185 -10
  522. package/src/features/host.ts +237 -19
  523. package/src/features/noise-texture.ts +91 -0
  524. package/src/features/plan.ts +553 -24
  525. package/src/features/prepared-gpu-work.ts +631 -49
  526. package/src/features/prepared-graphics-store.ts +31 -0
  527. package/src/features/prepared-graphics.ts +5 -0
  528. package/src/features/render-graph-compute.ts +41 -8
  529. package/src/features/render-graph-contribution.ts +141 -3
  530. package/src/features/render-graph-raster.ts +143 -30
  531. package/src/features/types.ts +11 -0
  532. package/src/fullscreen-post-process-pass.ts +3 -0
  533. package/src/gpu-driven/batch-topology.ts +424 -102
  534. package/src/gpu-driven/pbr-program.ts +31 -0
  535. package/src/gpu-driven/prepared-draw.ts +29 -4
  536. package/src/gpu-driven/production-raster.ts +2267 -694
  537. package/src/gpu-driven/shadow-views.ts +539 -0
  538. package/src/gpu-driven/view-gpu.ts +188 -41
  539. package/src/gpu-scene-schema.ts +52 -11
  540. package/src/gpu-scene.ts +186 -99
  541. package/src/gpu-texture-usage.ts +1 -0
  542. package/src/hdrp-buffers.ts +72 -36
  543. package/src/ibl/frame-resources.ts +38 -0
  544. package/src/ibl/skylight-bind-group.ts +5 -4
  545. package/src/index.ts +125 -1
  546. package/src/inspection-types.ts +191 -0
  547. package/src/instances-derived-bounds.ts +258 -34
  548. package/src/instances.ts +459 -150
  549. package/src/internal.ts +22 -0
  550. package/src/lifecycle.ts +2 -0
  551. package/src/material-row.ts +145 -0
  552. package/src/materials.ts +44 -8
  553. package/src/pbr-pipeline.ts +159 -17
  554. package/src/pipeline/standard-forward-lane.ts +52 -24
  555. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  556. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  557. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  558. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  559. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  560. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  561. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  562. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  563. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  564. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  565. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  566. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  567. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  568. package/src/pipeline/standard-output/color-transform.ts +124 -0
  569. package/src/pipeline/standard-output/graph.ts +139 -0
  570. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  571. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  572. package/src/pipeline/standard-output/lut-state.ts +176 -0
  573. package/src/pipeline/standard-output/resources.ts +121 -0
  574. package/src/pipeline/standard-output/types.ts +58 -0
  575. package/src/pipeline/standard-pipeline.ts +192 -59
  576. package/src/pipeline/standard-post.ts +186 -27
  577. package/src/pipeline-builder.ts +16 -6
  578. package/src/pipeline-spec-types.ts +4 -0
  579. package/src/pipeline-spec.ts +37 -29
  580. package/src/points-lines/standard-owner.ts +6 -14
  581. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  582. package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
  583. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  584. package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
  585. package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
  586. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  587. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  588. package/src/record/dynamic-geometry-consumption.ts +59 -0
  589. package/src/record/frame-lighting.ts +12 -11
  590. package/src/record/frame-snapshot.ts +133 -23
  591. package/src/record/frame-targets.ts +9 -0
  592. package/src/record/frame.ts +727 -133
  593. package/src/record/main-pass-geometry.ts +162 -98
  594. package/src/record/main-pass-material.ts +115 -26
  595. package/src/record/main-pass-sprite-draws.ts +18 -107
  596. package/src/record/main-pass.ts +78 -8
  597. package/src/record/material-uniforms.ts +1 -1
  598. package/src/record/mesh-ssbo.ts +59 -15
  599. package/src/record/prepared-material-bindings.ts +234 -0
  600. package/src/record/recovery-pipeline.ts +59 -136
  601. package/src/record/render-context.ts +92 -22
  602. package/src/record/shadow-pass.ts +1231 -209
  603. package/src/record/skybox-post-pass.ts +14 -3
  604. package/src/record/typed-frame-graph.ts +1006 -53
  605. package/src/record/view-ubo.ts +11 -0
  606. package/src/recovery/render-system-candidate.ts +90 -66
  607. package/src/recovery/render-system-roots.ts +113 -0
  608. package/src/recovery/types.ts +77 -0
  609. package/src/reflection/record-owner.ts +26 -54
  610. package/src/render-contract.ts +219 -25
  611. package/src/render-graph-primitives.ts +6 -2
  612. package/src/render-pipeline.ts +70 -1
  613. package/src/render-system-extract-tail.ts +409 -160
  614. package/src/render-system-extract.ts +376 -102
  615. package/src/render-system-projections.ts +241 -0
  616. package/src/render-system.ts +692 -791
  617. package/src/scene/render-scene-types.ts +13 -4
  618. package/src/scene/render-scene.ts +569 -355
  619. package/src/scene/shadow-visibility.ts +21 -0
  620. package/src/ssr/admission.ts +380 -14
  621. package/src/ssr/compose.ts +144 -0
  622. package/src/ssr/errors.ts +48 -0
  623. package/src/ssr/graph.ts +777 -0
  624. package/src/ssr/history.ts +436 -0
  625. package/src/ssr/hiz.ts +124 -0
  626. package/src/ssr/inspection.ts +124 -0
  627. package/src/ssr/resources.ts +202 -0
  628. package/src/ssr/temporal.ts +164 -0
  629. package/src/systems/skin-palette-allocator.ts +495 -148
  630. package/src/systems/skin-palette-types.ts +17 -0
  631. package/src/systems/transparent-dispatch.ts +90 -0
  632. package/src/targets/material-source.ts +34 -0
  633. package/src/temporal/coverage.ts +1 -1
  634. package/src/temporal/frame-coordinator.ts +23 -2
  635. package/src/temporal/gpu.ts +74 -12
  636. package/src/temporal/history.ts +3 -1
  637. package/src/temporal/inspection.ts +2 -1
  638. package/src/temporal/standard-scene-data.ts +3 -1
  639. package/src/temporal/temporal-view.ts +3 -0
  640. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
  641. package/src/typed-render-graph-primitives.ts +266 -74
  642. package/src/typed-shadow-passes.ts +122 -12
  643. package/src/volume/temporal.ts +10 -0
  644. package/dist/chunk-ADHHVYLW.mjs.map +0 -1
  645. package/dist/chunk-FJ6P52EE.mjs.map +0 -1
  646. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  647. package/dist/chunk-GF523LHF.mjs.map +0 -1
  648. package/dist/chunk-HKXTW355.mjs.map +0 -1
  649. package/dist/chunk-JDWARUOI.mjs.map +0 -1
  650. package/dist/chunk-KM2NOX2I.mjs.map +0 -1
  651. package/dist/chunk-TMIASV2N.mjs.map +0 -1
  652. package/dist/chunk-XDP6XE5V.mjs.map +0 -1
  653. package/dist/chunk-ZZ4YQ474.mjs.map +0 -1
  654. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  655. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -1,20 +1,172 @@
1
- import { GlyphText, selectActiveCameraIndex, getActiveCamera } from './chunk-FJ6P52EE.mjs';
2
- import { MeshRenderer, MeshFilter, DirectionalLight, validateDirectionalLightData, PointLight, computeInvRangeSquared, SpotLight, degToCos, RectAreaLight, validateRectAreaLightData, directionalShadowQualityFromF32, PointLightShadow, Skylight, LightProbe, validateLightProbeData, SkyboxBackground, Atmosphere, Instances, Layer, Points, Lines, SortKey, resolveMeshMaterialBindings, pointShapeFromU32, PostProcessParams, CubeCamera, cubeCameraUpdateIntentFromF32, ReflectionProbe, reflectionProbeUpdateIntentFromF32, tonemapToU32, resolveVisibility, Fog, VolumetricFog, resolveSelectedVolumetricLight, extractVolumetricFog, MotionBlur, Camera, bloomEnabledFromF32, antialiasFromF32, tonemapFromF32, cameraProjectionFromF32 } from './chunk-ADHHVYLW.mjs';
3
- import { SpriteRegionOverride, SpriteInstances } from './chunk-JDWARUOI.mjs';
4
- import { PROBE_BLEND_RECORD_CAPACITY, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_COPY_DST, IES_SLICE_CAPACITY, COOKIE_SLICE_CAPACITY, isStandardPbrSkinMaterialShader, selectPasses, resolveRenderTargetMaterialSource, PROBE_BLEND_RECORD_BYTE_SIZE, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, COOKIE_SLICE_SIZE, isCanonicalStandardPbrMaterialShader, isStandardPbrMaterialShader } from './chunk-HKXTW355.mjs';
5
- import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, SHADOW_ATLAS_DEFAULT_LAYERS, SkinMaterialMismatchError, MaterialSkinAttrMissingError, ShadowInvalidConfigError, EnvironmentSourceConflictError, FogCardinalityError, AtmosphereInvalidParameterError } from './chunk-ZZ4YQ474.mjs';
6
- import { err, ok, RhiError } from '@forgeax/engine-rhi';
1
+ import { GlyphText } from './chunk-ILQ5MEZF.mjs';
2
+ import { MeshRenderer, MeshFilter, DirectionalLight, validateDirectionalLightData, PointLight, computeInvRangeSquared, SpotLight, degToCos, RectAreaLight, validateRectAreaLightData, directionalShadowQualityFromF32, PointLightShadow, Skylight, LightProbe, validateLightProbeData, SkyboxBackground, Atmosphere, Instances, Layer, Points, Lines, SortKey, resolveMeshMaterialBindings, pointShapeFromU32, PostProcessParams, buildCubeCameraFaceViews, CubeCamera, cubeCameraUpdateIntentFromF32, ReflectionProbe, reflectionProbeUpdateIntentFromF32, tonemapToU32, resolveVisibility, Fog, VolumetricFog, resolveSelectedVolumetricLight, extractVolumetricFog, MotionBlur, ScreenSpaceReflection, Camera, CAMERA_EXPOSURE_MODE_MANUAL, cameraExposureFromColumns, bloomEnabledFromF32, antialiasFromF32, tonemapFromF32, cameraProjectionFromF32 } from './chunk-33XZFTQU.mjs';
3
+ import { SpriteRegionOverride, SpriteInstances, selectActiveCameraIndex, getActiveCamera } from './chunk-PA5DRJNI.mjs';
4
+ import { PROBE_BLEND_RECORD_CAPACITY, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_VERTEX, GPU_BUFFER_USAGE_COPY_DST, gpuDrivenShadowDrawKey, IES_SLICE_CAPACITY, COOKIE_SLICE_CAPACITY, isStandardPbrSkinMaterialShader, buildGpuDrivenDraws, worldEntityKey, gpuDrivenSourceDrawItemIndex, selectPasses, resolveRenderTargetMaterialSource, isCanonicalStandardPbrMaterialShader, PROBE_BLEND_RECORD_BYTE_SIZE, GPU_BUFFER_USAGE_UNIFORM, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_COPY_SRC, COOKIE_SLICE_SIZE, isStandardPbrMaterialShader } from './chunk-BTWH7BP4.mjs';
5
+ import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, SHADOW_ATLAS_DEFAULT_LAYERS, SkinMaterialMismatchError, MaterialSkinAttrMissingError, InstanceCollectionError, ShadowInvalidConfigError, EnvironmentSourceConflictError, FogCardinalityError, GPU_TEXTURE_USAGE_COPY_SRC, GPU_TEXTURE_USAGE_COPY_DST, GPU_TEXTURE_USAGE_TEXTURE_BINDING, GPU_TEXTURE_USAGE_STORAGE_BINDING, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, AtmosphereInvalidParameterError } from './chunk-NRNXBLIJ.mjs';
6
+ import { R_MIN, ok, err, TextError, toShared, handleSlot, AssetError, ASSET_ERROR_HINTS, materialValuesToLinearRuntime, derive, unpackSlot, materialGuidText } from '@forgeax/engine-types';
7
+ import { err as err$1, ok as ok$1, RhiError } from '@forgeax/engine-rhi';
7
8
  import { resolveAssetHandle, walkMaterialPassesOverSharedRefs, selectMaterialPassProgram, materialParametersToParamSchema as materialParametersToParamSchema$1 } from '@forgeax/engine-assets-runtime';
8
- import { SpawnLightInvalidBoundsError, routeWorldError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, SpriteInstancesCountMismatchError, InstanceTransformsStrideMismatchError, readRenderArrayView } from '@forgeax/engine-ecs/projection';
9
+ import { SpawnLightInvalidBoundsError, routeWorldError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, SpriteInstancesCountMismatchError, readRenderArrayView } from '@forgeax/engine-ecs/projection';
9
10
  import { vec3, mat4, frustum, box3 } from '@forgeax/engine-math';
10
11
  import { AssetGuid } from '@forgeax/engine-pack/guid';
11
12
  import { Transform, GlobalTransform, MorphWeights } from '@forgeax/engine-scene';
12
- import { STANDARD_PIPELINE_PARAM_SCHEMA, DEFAULT_STANDARD_SURFACE_MODULE } from '@forgeax/engine-shader';
13
- import { R_MIN, err as err$1, ok as ok$1, TextError, toShared, handleSlot, AssetError, ASSET_ERROR_HINTS, materialValuesToLinearRuntime, derive, unpackSlot, materialGuidText } from '@forgeax/engine-types';
14
- import { PROCEDURAL_FLOATS_PER_VERTEX, deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
13
+ import { standardTextureMask, DEFAULT_STANDARD_PBR_PARAM_SCHEMA, STANDARD_PIPELINE_PARAM_SCHEMA, DEFAULT_STANDARD_SURFACE_MODULE } from '@forgeax/engine-shader';
15
14
  import { Skin, SkinInstancesCoexistForbiddenError, SkeletonResolveFailedError, JointCountMismatchError, JointEntityDanglingError } from '@forgeax/engine-skinning';
15
+ import { PROCEDURAL_FLOATS_PER_VERTEX } from '@forgeax/engine-geometry';
16
16
  import { resetFontConcurrency, trackFontConcurrency, layoutGlyphText, conservativeCubeAabb, bakeGlyphMesh } from '@forgeax/engine-graphics-extras';
17
17
 
18
+ // src/ssr/hiz.ts
19
+ var SSR_HIZ_FORMAT = "r32float";
20
+ function validExtent(extent) {
21
+ return Number.isInteger(extent.width) && Number.isInteger(extent.height) && extent.width > 0 && extent.height > 0;
22
+ }
23
+ function requireExtent(extent) {
24
+ if (!validExtent(extent)) {
25
+ throw new RangeError("SSR Hi-Z extent must contain positive integer width and height");
26
+ }
27
+ }
28
+ function nextSsrHiZMipExtent(extent) {
29
+ requireExtent(extent);
30
+ return {
31
+ width: Math.max(1, Math.floor(extent.width / 2)),
32
+ height: Math.max(1, Math.floor(extent.height / 2))
33
+ };
34
+ }
35
+ function buildSsrHiZPlan(extent) {
36
+ requireExtent(extent);
37
+ const levels = [];
38
+ let current = { width: extent.width, height: extent.height };
39
+ let level = 0;
40
+ while (true) {
41
+ levels.push({ level, ...current });
42
+ if (current.width === 1 && current.height === 1) break;
43
+ current = nextSsrHiZMipExtent(current);
44
+ level += 1;
45
+ }
46
+ return Object.freeze({
47
+ extent: Object.freeze({ width: extent.width, height: extent.height }),
48
+ format: SSR_HIZ_FORMAT,
49
+ mipLevelCount: levels.length,
50
+ levels: Object.freeze(levels.map((entry) => Object.freeze(entry))),
51
+ graphSize: Object.freeze({ width: extent.width, height: extent.height })
52
+ });
53
+ }
54
+
55
+ // src/ssr/resources.ts
56
+ var SSR_TRACE_FORMAT = "rgba16float";
57
+ var SSR_R32FLOAT_BYTES_PER_PIXEL = 4;
58
+ var SSR_RGBA16FLOAT_BYTES_PER_PIXEL = 8;
59
+ var SSR_TEMPORAL_PARAMS_BYTES = 32;
60
+ var SSR_SPATIAL_MEMORY_BUDGET_BYTES = 45088768;
61
+ function halfExtent(extent) {
62
+ return {
63
+ width: Math.max(1, Math.floor(extent.width / 2)),
64
+ height: Math.max(1, Math.floor(extent.height / 2))
65
+ };
66
+ }
67
+ function byteCount(width, height, bytesPerPixel) {
68
+ const bytes = width * height * bytesPerPixel;
69
+ if (!Number.isSafeInteger(bytes)) {
70
+ throw new RangeError("SSR spatial descriptor byte count exceeds safe integer range");
71
+ }
72
+ return bytes;
73
+ }
74
+ function estimateSsrSpatialMemory(extent, options = {}) {
75
+ const half = halfExtent(extent);
76
+ const plan = buildSsrHiZPlan(half);
77
+ const temporal = options.temporal !== false;
78
+ const hizBytes = plan.levels.reduce(
79
+ (sum, level) => sum + byteCount(level.width, level.height, SSR_R32FLOAT_BYTES_PER_PIXEL),
80
+ 0
81
+ );
82
+ const traceBytes = byteCount(half.width, half.height, SSR_RGBA16FLOAT_BYTES_PER_PIXEL);
83
+ const hitReactivityBytes = byteCount(half.width, half.height, SSR_R32FLOAT_BYTES_PER_PIXEL);
84
+ const resolvedBytes = temporal ? plan.levels.reduce(
85
+ (sum, level) => sum + byteCount(level.width, level.height, SSR_RGBA16FLOAT_BYTES_PER_PIXEL),
86
+ 0
87
+ ) : 0;
88
+ const historyBytes = temporal ? half.width * half.height * 12 * 2 : 0;
89
+ const temporalParamsBytes = temporal ? SSR_TEMPORAL_PARAMS_BYTES : 0;
90
+ const fallbackInputBytes = byteCount(
91
+ extent.width,
92
+ extent.height,
93
+ SSR_RGBA16FLOAT_BYTES_PER_PIXEL
94
+ );
95
+ const ssrOwnedBytes = hizBytes + traceBytes + hitReactivityBytes + resolvedBytes + historyBytes + temporalParamsBytes + fallbackInputBytes;
96
+ return Object.freeze({
97
+ width: extent.width,
98
+ height: extent.height,
99
+ halfWidth: half.width,
100
+ halfHeight: half.height,
101
+ hizBytes,
102
+ traceBytes,
103
+ hitReactivityBytes,
104
+ resolvedBytes,
105
+ historyBytes,
106
+ temporalParamsBytes,
107
+ fallbackInputBytes,
108
+ ssrOwnedBytes,
109
+ budgetBytes: SSR_SPATIAL_MEMORY_BUDGET_BYTES,
110
+ withinBudget: ssrOwnedBytes <= SSR_SPATIAL_MEMORY_BUDGET_BYTES
111
+ });
112
+ }
113
+ function texture(graph, label, format, extent) {
114
+ const created = graph.createTexture(label, {
115
+ format,
116
+ size: { width: extent.width, height: extent.height },
117
+ domain: "linear-hdr"
118
+ });
119
+ if (!created.ok) return created;
120
+ const view = graph.view(created.value, { label: `${label}.view`, dimension: "2d" });
121
+ if (!view.ok) return view;
122
+ return ok({
123
+ texture: created.value,
124
+ view: view.value,
125
+ width: extent.width,
126
+ height: extent.height,
127
+ format
128
+ });
129
+ }
130
+ function createSsrHiZResources(graph, extent) {
131
+ const plan = buildSsrHiZPlan(halfExtent(extent));
132
+ const created = graph.createTexture("ssr-hiz", {
133
+ format: SSR_HIZ_FORMAT,
134
+ size: plan.graphSize,
135
+ mipLevelCount: plan.mipLevelCount
136
+ });
137
+ if (!created.ok) return created;
138
+ const levels = [];
139
+ for (const entry of plan.levels) {
140
+ const view = graph.view(created.value, {
141
+ label: `ssr-hiz.mip-${entry.level}.view`,
142
+ dimension: "2d",
143
+ baseMipLevel: entry.level,
144
+ mipLevelCount: 1
145
+ });
146
+ if (!view.ok) return view;
147
+ levels.push(view.value);
148
+ }
149
+ return ok({ plan, texture: created.value, levels: Object.freeze(levels) });
150
+ }
151
+ function createSsrSpatialResources(graph, extent) {
152
+ const hiz = createSsrHiZResources(graph, extent);
153
+ if (!hiz.ok) return hiz;
154
+ const traceExtent = halfExtent(extent);
155
+ const trace = texture(graph, "ssr-trace", SSR_TRACE_FORMAT, traceExtent);
156
+ if (!trace.ok) return trace;
157
+ const hitTexture = graph.createTexture("ssr-hit-reactivity", {
158
+ format: "r32float",
159
+ size: traceExtent
160
+ });
161
+ if (!hitTexture.ok) return hitTexture;
162
+ const hitReactivity = graph.view(hitTexture.value, {
163
+ label: "ssr-hit-reactivity.view",
164
+ dimension: "2d"
165
+ });
166
+ if (!hitReactivity.ok) return hitReactivity;
167
+ return ok({ hiz: hiz.value, trace: trace.value, hitReactivity: hitReactivity.value });
168
+ }
169
+
18
170
  // src/inspection-types.ts
19
171
  function projectLightInspection(input) {
20
172
  return Object.freeze({
@@ -87,6 +239,293 @@ function projectExtendedLightingInspection(state) {
87
239
  uploadBytes: state.descriptorBytes
88
240
  });
89
241
  }
242
+ var SSR_HISTORY_FORMAT = "rgba16float";
243
+ var HISTORY_USAGE = GPU_TEXTURE_USAGE_COPY_SRC | GPU_TEXTURE_USAGE_COPY_DST | GPU_TEXTURE_USAGE_TEXTURE_BINDING | GPU_TEXTURE_USAGE_STORAGE_BINDING | GPU_TEXTURE_USAGE_RENDER_ATTACHMENT;
244
+ function positiveDimension(value, field) {
245
+ if (!Number.isSafeInteger(value) || value <= 0) {
246
+ throw new RangeError(`${field} must be a positive safe integer.`);
247
+ }
248
+ return value;
249
+ }
250
+ function createResources(device, scope, width, height) {
251
+ const halfWidth = Math.max(1, Math.floor(width / 2));
252
+ const halfHeight = Math.max(1, Math.floor(height / 2));
253
+ const descriptor = {
254
+ label: "ssr-history-rgba16float",
255
+ size: { width: halfWidth, height: halfHeight, depthOrArrayLayers: 1 },
256
+ format: SSR_HISTORY_FORMAT,
257
+ usage: HISTORY_USAGE,
258
+ mipLevelCount: 1,
259
+ sampleCount: 1,
260
+ dimension: "2d",
261
+ viewFormats: void 0,
262
+ textureBindingViewDimension: void 0
263
+ };
264
+ const childScope = scope.createChild(`${scope.owner}:ssr-history`);
265
+ const slots = [];
266
+ for (const index of [0, 1]) {
267
+ const texture2 = device.createTexture({
268
+ ...descriptor,
269
+ label: `ssr-history-rgba16float-${index}`
270
+ });
271
+ if (!texture2.ok) {
272
+ childScope.abandon();
273
+ return texture2;
274
+ }
275
+ childScope._adopt("texture", texture2.value, (value) => {
276
+ device.destroyTexture(value);
277
+ });
278
+ const view = device.createTextureView(texture2.value, {
279
+ label: `ssr-history-rgba16float-${index}.view`,
280
+ dimension: "2d",
281
+ baseMipLevel: 0,
282
+ mipLevelCount: 1,
283
+ baseArrayLayer: 0,
284
+ arrayLayerCount: 1
285
+ });
286
+ if (!view.ok) {
287
+ childScope.abandon();
288
+ return view;
289
+ }
290
+ const surfaceTexture = device.createTexture({
291
+ ...descriptor,
292
+ label: `ssr-history-surface-${index}`,
293
+ format: "rgba8unorm"
294
+ });
295
+ if (!surfaceTexture.ok) {
296
+ childScope.abandon();
297
+ return surfaceTexture;
298
+ }
299
+ childScope._adopt("texture", surfaceTexture.value, (value) => {
300
+ device.destroyTexture(value);
301
+ });
302
+ const surfaceView = device.createTextureView(surfaceTexture.value, { dimension: "2d" });
303
+ if (!surfaceView.ok) {
304
+ childScope.abandon();
305
+ return surfaceView;
306
+ }
307
+ slots.push({
308
+ texture: texture2.value,
309
+ view: view.value,
310
+ surfaceTexture: surfaceTexture.value,
311
+ surfaceView: surfaceView.value
312
+ });
313
+ }
314
+ const params = device.createBuffer({
315
+ label: "ssr-temporal-params",
316
+ size: 32,
317
+ usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
318
+ mappedAtCreation: false
319
+ });
320
+ if (!params.ok) {
321
+ childScope.abandon();
322
+ return params;
323
+ }
324
+ childScope._adopt("buffer", params.value, (value) => {
325
+ device.destroyBuffer(value);
326
+ });
327
+ const cleared = device.queue.writeBuffer(params.value, 0, new Uint8Array(32));
328
+ if (!cleared.ok) {
329
+ childScope.abandon();
330
+ return cleared;
331
+ }
332
+ return ok({
333
+ width,
334
+ height,
335
+ halfWidth,
336
+ halfHeight,
337
+ bytes: halfWidth * halfHeight * 12 * 2,
338
+ descriptor,
339
+ slots,
340
+ paramsBuffer: params.value,
341
+ childScope
342
+ });
343
+ }
344
+ function failure(code, expected, hint, detail) {
345
+ return { code, expected, hint, ...{} };
346
+ }
347
+ var SsrHistoryOwner = class _SsrHistoryOwner {
348
+ constructor(device, scope, resources) {
349
+ this.device = device;
350
+ this.scope = scope;
351
+ this.activeResources = resources;
352
+ }
353
+ device;
354
+ scope;
355
+ activeResources;
356
+ retiringResources = /* @__PURE__ */ new Set();
357
+ retirementFencePending = false;
358
+ activeCandidate;
359
+ readIndex = 0;
360
+ valid = false;
361
+ state = "first-frame";
362
+ resetReason = "first-enable";
363
+ lastFailure;
364
+ resetCount = 0;
365
+ static create(input) {
366
+ const width = positiveDimension(input.width, "width");
367
+ const height = positiveDimension(input.height, "height");
368
+ const resources = createResources(input.device, input.scope, width, height);
369
+ return resources.ok ? ok(new _SsrHistoryOwner(input.device, input.scope, resources.value)) : resources;
370
+ }
371
+ get resources() {
372
+ if (this.activeResources === void 0) throw new Error("SSR history resources are retired.");
373
+ return this.activeResources;
374
+ }
375
+ beginFrame() {
376
+ if (this.activeResources === void 0 || this.state === "retired" || this.state === "disposed") {
377
+ return err(
378
+ failure(
379
+ "ssr-history-retired",
380
+ "SSR history resources are active",
381
+ "recreate the renderer-owned SSR history after device recovery"
382
+ )
383
+ );
384
+ }
385
+ if (this.activeCandidate !== void 0) {
386
+ return err(
387
+ failure(
388
+ "ssr-history-active",
389
+ "one SSR history candidate is active",
390
+ "commit or abort the active SSR history candidate before beginning another"
391
+ )
392
+ );
393
+ }
394
+ const writeSlot = this.valid ? this.readIndex === 0 ? 1 : 0 : 0;
395
+ const candidate = Object.freeze({
396
+ readSlot: this.valid ? this.readIndex : null,
397
+ writeSlot,
398
+ historyValid: this.valid && this.resetReason === void 0
399
+ });
400
+ this.activeCandidate = candidate;
401
+ this.state = this.valid ? "stable" : this.state === "aborted" ? "aborted" : "first-frame";
402
+ this.lastFailure = void 0;
403
+ return ok(candidate);
404
+ }
405
+ commitFrame(candidate) {
406
+ if (this.activeCandidate !== candidate) {
407
+ return err(
408
+ failure(
409
+ "ssr-history-not-active",
410
+ "commit the candidate returned by beginFrame",
411
+ "keep one candidate from beginFrame until the shared queue submit succeeds"
412
+ )
413
+ );
414
+ }
415
+ this.readIndex = candidate.writeSlot;
416
+ this.valid = true;
417
+ this.activeCandidate = void 0;
418
+ this.state = "stable";
419
+ this.resetReason = void 0;
420
+ this.lastFailure = void 0;
421
+ return ok(void 0);
422
+ }
423
+ abortFrame(candidate, stage) {
424
+ if (this.activeCandidate !== candidate) return;
425
+ this.activeCandidate = void 0;
426
+ this.state = "aborted";
427
+ this.lastFailure = stage;
428
+ }
429
+ reset(reason) {
430
+ this.activeCandidate = void 0;
431
+ this.valid = false;
432
+ this.readIndex = 0;
433
+ this.resetReason = reason;
434
+ this.lastFailure = void 0;
435
+ this.resetCount += 1;
436
+ if (this.activeResources !== void 0) this.state = "reset";
437
+ }
438
+ resize(width, height) {
439
+ const next = createResources(
440
+ this.device,
441
+ this.scope,
442
+ positiveDimension(width, "width"),
443
+ positiveDimension(height, "height")
444
+ );
445
+ if (!next.ok) return next;
446
+ if (this.activeResources !== void 0) this.retiringResources.add(this.activeResources);
447
+ this.activeResources = next.value;
448
+ this.activeCandidate = void 0;
449
+ this.valid = false;
450
+ this.readIndex = 0;
451
+ this.resetReason = "resize";
452
+ this.lastFailure = void 0;
453
+ this.resetCount += 1;
454
+ this.state = "reset";
455
+ return ok(void 0);
456
+ }
457
+ /** Retire pending allocations after the queue's already-submitted work. */
458
+ retireAfterFence(queue, onFailure) {
459
+ if (this.retirementFencePending) return;
460
+ if (this.retiringResources.size === 0 && this.activeResources !== void 0) {
461
+ this.retiringResources.add(this.activeResources);
462
+ this.activeCandidate = void 0;
463
+ this.valid = false;
464
+ this.state = "retiring";
465
+ }
466
+ const pending = [...this.retiringResources];
467
+ for (const resources of pending) resources.childScope.beginRetire();
468
+ if (pending.length === 0) return;
469
+ this.retirementFencePending = true;
470
+ const finish = () => {
471
+ this.retirementFencePending = false;
472
+ for (const resources of pending) {
473
+ this.retiringResources.delete(resources);
474
+ resources.childScope.retire();
475
+ if (this.activeResources === resources) this.activeResources = void 0;
476
+ }
477
+ if (this.activeResources === void 0 && this.retiringResources.size === 0) {
478
+ this.state = "retired";
479
+ }
480
+ if (this.retiringResources.size > 0) this.retireAfterFence(queue, onFailure);
481
+ };
482
+ void queue.onSubmittedWorkDone().then(finish, (cause) => {
483
+ onFailure(cause);
484
+ finish();
485
+ });
486
+ }
487
+ retire() {
488
+ this.retirementFencePending = false;
489
+ this.activeCandidate = void 0;
490
+ if (this.activeResources !== void 0) {
491
+ this.activeResources.childScope.retire();
492
+ this.activeResources = void 0;
493
+ }
494
+ for (const resources of this.retiringResources) resources.childScope.retire();
495
+ this.retiringResources.clear();
496
+ this.valid = false;
497
+ this.state = "retired";
498
+ }
499
+ dispose() {
500
+ if (this.state === "disposed") return;
501
+ this.retire();
502
+ this.state = "disposed";
503
+ }
504
+ inspect() {
505
+ const active = this.activeResources;
506
+ return Object.freeze({
507
+ state: this.state,
508
+ width: active?.width ?? 0,
509
+ height: active?.height ?? 0,
510
+ halfWidth: active?.halfWidth ?? 0,
511
+ halfHeight: active?.halfHeight ?? 0,
512
+ format: SSR_HISTORY_FORMAT,
513
+ historyCount: active === void 0 ? 0 : 2,
514
+ historyValid: this.valid,
515
+ readSlot: active === void 0 ? null : this.valid ? this.readIndex : null,
516
+ writeSlot: active === void 0 ? 0 : this.valid ? this.readIndex === 0 ? 1 : 0 : 0,
517
+ activeBytes: active?.bytes ?? 0,
518
+ candidateBytes: 0,
519
+ retiringBytes: [...this.retiringResources].filter((entry) => entry !== active).reduce((sum, entry) => sum + entry.bytes, 0),
520
+ resetCount: this.resetCount,
521
+ resetReason: this.resetReason,
522
+ lastFailure: this.lastFailure
523
+ });
524
+ }
525
+ };
526
+ function createSsrHistoryOwner(input) {
527
+ return SsrHistoryOwner.create(input);
528
+ }
90
529
 
91
530
  // src/scene/visibility/occlusion-query-pool.ts
92
531
  var OCCLUSION_QUERY_PAGE_COUNT = 3;
@@ -229,7 +668,7 @@ function createOcclusionQueryResources(device, pageIndex) {
229
668
  device.destroyQuerySet(querySet.value);
230
669
  return stagingBuffer;
231
670
  }
232
- return ok({
671
+ return ok$1({
233
672
  pageIndex,
234
673
  querySet: querySet.value,
235
674
  resolveBuffer: resolveBuffer.value,
@@ -238,7 +677,7 @@ function createOcclusionQueryResources(device, pageIndex) {
238
677
  }
239
678
  function recordOcclusionResolve(encoder, resources, firstQuery, queryCount) {
240
679
  if (!Number.isSafeInteger(firstQuery) || !Number.isSafeInteger(queryCount) || firstQuery < 0 || queryCount <= 0 || firstQuery + queryCount > OCCLUSION_QUERY_PAGE_INDEX_LIMIT) {
241
- return err(
680
+ return err$1(
242
681
  new RhiError({
243
682
  code: "webgpu-runtime-error",
244
683
  expected: "query range stays within one 4096-index page",
@@ -255,7 +694,7 @@ function recordOcclusionResolve(encoder, resources, firstQuery, queryCount) {
255
694
  );
256
695
  if (!resolved.ok) return resolved;
257
696
  encoder.copyBufferToBuffer(resources.resolveBuffer, resources.stagingBuffer, queryCount * 8);
258
- return ok(void 0);
697
+ return ok$1(void 0);
259
698
  }
260
699
 
261
700
  // src/scene/visibility/types.ts
@@ -310,19 +749,19 @@ var OcclusionRenderRuntime = class {
310
749
  },
311
750
  encodeProxyBounds: (pass) => {
312
751
  const pending = runtime.pendingFrame;
313
- return pending === void 0 ? err(runtimeError("the current RenderSystem frame owns the occlusion candidate")) : runtime.encodeProxyBounds(pass, pending);
752
+ return pending === void 0 ? err$1(runtimeError("the current RenderSystem frame owns the occlusion candidate")) : runtime.encodeProxyBounds(pass, pending);
314
753
  },
315
754
  beginCandidate: (pass) => {
316
755
  const pending = runtime.pendingFrame;
317
756
  if (pending === void 0 || pending.endedCount >= pending.reservations.length) {
318
- return err(runtimeError("the current RenderSystem frame owns the occlusion candidate"));
757
+ return err$1(runtimeError("the current RenderSystem frame owns the occlusion candidate"));
319
758
  }
320
759
  return pass.beginOcclusionQuery(pending.reservations[pending.endedCount]?.queryIndex ?? 0);
321
760
  },
322
761
  endCandidate: (pass) => {
323
762
  const pending = runtime.pendingFrame;
324
763
  if (pending === void 0 || pending.endedCount >= pending.reservations.length) {
325
- return err(runtimeError("the current RenderSystem frame owns the occlusion candidate"));
764
+ return err$1(runtimeError("the current RenderSystem frame owns the occlusion candidate"));
326
765
  }
327
766
  const ended = pass.endOcclusionQuery();
328
767
  if (ended.ok) pending.endedCount += 1;
@@ -331,7 +770,7 @@ var OcclusionRenderRuntime = class {
331
770
  recordResolve: (encoder) => {
332
771
  const pending = runtime.pendingFrame;
333
772
  if (pending === void 0 || pending.endedCount !== pending.reservations.length) {
334
- return err(runtimeError("the real geometry pass must end its occlusion query first"));
773
+ return err$1(runtimeError("the real geometry pass must end its occlusion query first"));
335
774
  }
336
775
  return recordOcclusionResolve(
337
776
  encoder,
@@ -665,7 +1104,7 @@ var OcclusionRenderRuntime = class {
665
1104
  }
666
1105
  encodeProxyBounds(pass, pending) {
667
1106
  if (pending.proxyFloatCount === 0) {
668
- return err(runtimeError("every occlusion candidate needs conservative proxy geometry"));
1107
+ return err$1(runtimeError("every occlusion candidate needs conservative proxy geometry"));
669
1108
  }
670
1109
  const pipeline = this.ensureProxyPipeline(pending.sampleCount);
671
1110
  if (pipeline === void 0) {
@@ -676,11 +1115,11 @@ var OcclusionRenderRuntime = class {
676
1115
  if (!ended.ok) return ended;
677
1116
  }
678
1117
  pending.endedCount = pending.reservations.length;
679
- return ok(void 0);
1118
+ return ok$1(void 0);
680
1119
  }
681
1120
  const buffer = this.ensureProxyBuffer(pending.proxyFloatCount * Float32Array.BYTES_PER_ELEMENT);
682
1121
  if (buffer === void 0) {
683
- return err(runtimeError("the backend must allocate the bounded proxy geometry buffer"));
1122
+ return err$1(runtimeError("the backend must allocate the bounded proxy geometry buffer"));
684
1123
  }
685
1124
  const uploaded = this.device.queue.writeBuffer(
686
1125
  buffer,
@@ -702,7 +1141,7 @@ var OcclusionRenderRuntime = class {
702
1141
  vertexOffset += vertices.length;
703
1142
  }
704
1143
  pending.endedCount = pending.reservations.length;
705
- return ok(void 0);
1144
+ return ok$1(void 0);
706
1145
  }
707
1146
  ensureProxyBuffer(byteLength) {
708
1147
  if (this.proxyBuffer !== void 0) return this.proxyBuffer;
@@ -909,27 +1348,27 @@ function freezeFog(candidate) {
909
1348
  }
910
1349
  function selectEnvironment(input) {
911
1350
  if (input.environments.length > 1) {
912
- return err$1(
1351
+ return err(
913
1352
  new EnvironmentSourceConflictError(
914
1353
  [...input.environments].sort((left, right) => left.entityKey - right.entityKey).map(({ kind, entityKey, sourceKey }) => ({ kind, entityKey, sourceKey }))
915
1354
  )
916
1355
  );
917
1356
  }
918
- if (input.fogs.length > 1) return err$1(new FogCardinalityError(input.fogs.length));
1357
+ if (input.fogs.length > 1) return err(new FogCardinalityError(input.fogs.length));
919
1358
  const selectedFog = input.fogs[0];
920
1359
  if (selectedFog !== void 0) {
921
1360
  const issue = validateFogParameters(selectedFog);
922
1361
  if (issue !== void 0) {
923
- return err$1(new EnvironmentSelectionParameterError(issue.field, issue.value, issue.expected));
1362
+ return err(new EnvironmentSelectionParameterError(issue.field, issue.value, issue.expected));
924
1363
  }
925
1364
  }
926
1365
  const selected = input.environments[0];
927
1366
  if (selected?.kind === "atmosphere") {
928
1367
  const invalid = validateAtmosphereParameters(selected.atmosphere);
929
- if (invalid !== void 0) return err$1(invalid);
1368
+ if (invalid !== void 0) return err(invalid);
930
1369
  }
931
1370
  if (selected?.kind === "atmosphere" && input.suns.length !== 1) {
932
- return err$1(new SunCardinalityError(input.suns.length));
1371
+ return err(new SunCardinalityError(input.suns.length));
933
1372
  }
934
1373
  const source = selected === void 0 ? { kind: "none" } : selected.kind === "atmosphere" ? {
935
1374
  kind: "atmosphere",
@@ -957,7 +1396,7 @@ function selectEnvironment(input) {
957
1396
  sun
958
1397
  };
959
1398
  Object.defineProperty(result, "lane", { value: input.lane, enumerable: false });
960
- return ok$1(Object.freeze(result));
1399
+ return ok(Object.freeze(result));
961
1400
  }
962
1401
 
963
1402
  // src/extract/directional-shadow-projection.ts
@@ -988,208 +1427,6 @@ function projectDirectionalShadow(fits, mapSize, shadowFilter, shadowAngularRadi
988
1427
  }
989
1428
  return { splitPlanes, directionalShadowQuality };
990
1429
  }
991
-
992
- // src/errors/gpu-driven.ts
993
- var ERROR_POLICY = {
994
- "missing-material-receipt": {
995
- expected: "a producer-owned Standard PBR material receipt is present",
996
- hint: "cook and load the Standard PBR artifact, then retry preparation"
997
- },
998
- "missing-uv": {
999
- expected: "the geometry exposes every UV set named by the material receipt",
1000
- hint: "repair the geometry UV semantic or route the draw to the CPU semantic lane"
1001
- },
1002
- "reflection-mismatch": {
1003
- expected: "the loaded reflection receipt matches the artifact layout identity",
1004
- hint: "rebuild the material artifact and reflection from one source, then retry"
1005
- },
1006
- "vertex-input-mismatch": {
1007
- expected: "geometry vertex semantics match the material reflection receipt",
1008
- hint: "repair the geometry vertex semantic layout or route the draw to the CPU lane"
1009
- },
1010
- "alpha-mask-mismatch": {
1011
- expected: "the Alpha Mask cutoff is present in the material receipt",
1012
- hint: "declare alphaCutoff in the Standard PBR material schema and recook it"
1013
- },
1014
- "resource-not-ready": {
1015
- expected: "all material resource slots have resolved handles",
1016
- hint: "resolve the declared texture and sampler resources before recording"
1017
- },
1018
- "stale-generation": {
1019
- expected: "receipt and prepared inputs belong to the requested generation",
1020
- hint: "discard stale GPU facts, rebuild the producer receipt, and retry the same draw"
1021
- },
1022
- "skin-receipt-mismatch": {
1023
- expected: "skinned geometry has a current palette address receipt",
1024
- hint: "rebuild the Skin palette receipt for this generation before recording"
1025
- }
1026
- };
1027
- var GpuDrivenPreparationError = class extends Error {
1028
- code;
1029
- expected;
1030
- hint;
1031
- detail;
1032
- constructor(code, detail) {
1033
- const policy = ERROR_POLICY[code];
1034
- super(`[GpuDrivenPreparationError ${code}] ${policy.expected}`);
1035
- this.name = "GpuDrivenPreparationError";
1036
- this.code = code;
1037
- this.expected = policy.expected;
1038
- this.hint = policy.hint;
1039
- this.detail = detail;
1040
- }
1041
- };
1042
-
1043
- // src/gpu-driven/prepared-draw.ts
1044
- function failure(code, detail) {
1045
- return { ok: false, error: new GpuDrivenPreparationError(code, detail) };
1046
- }
1047
- function sameVertexInputs(expected, actual) {
1048
- return expected.length === actual.length && expected.every(
1049
- (input, index) => input.semantic === actual[index]?.semantic && input.location === actual[index]?.location && input.format === actual[index]?.format
1050
- );
1051
- }
1052
- function hasMaterialResources(snapshot, receipt) {
1053
- const textures = snapshot.material.textureHandles;
1054
- const samplers = snapshot.material.samplerHandles;
1055
- return receipt.resourceSlots.every((slot) => {
1056
- const handles = slot.kind === "texture" ? textures : samplers;
1057
- return handles?.has(slot.parameter) === true;
1058
- });
1059
- }
1060
- function prepareGpuDrivenDraw(input) {
1061
- const receipt = input.artifact.receipt;
1062
- if (receipt === void 0) {
1063
- return failure("missing-material-receipt", {
1064
- reason: "material-receipt-missing",
1065
- owner: "material",
1066
- expected: "MaterialShaderArtifact.receipt"
1067
- });
1068
- }
1069
- if (receipt.generation !== input.generation) {
1070
- return failure("stale-generation", {
1071
- reason: "generation-stale",
1072
- owner: "generation",
1073
- expectedGeneration: input.generation,
1074
- actualGeneration: receipt.generation
1075
- });
1076
- }
1077
- if (receipt.reflection.layoutIdentity !== input.artifact.layoutIdentity) {
1078
- return failure("reflection-mismatch", {
1079
- reason: "reflection-receipt-mismatch",
1080
- owner: "material",
1081
- expected: input.artifact.layoutIdentity,
1082
- actual: receipt.reflection.layoutIdentity
1083
- });
1084
- }
1085
- if (receipt.uvSets.some((uv) => uv.set > 0) && input.geometry.vertexInputs.length < 3) {
1086
- return failure("missing-uv", {
1087
- reason: "uv-set-missing",
1088
- owner: "geometry",
1089
- expected: `${receipt.uvSets.length} material UV sets`,
1090
- actual: `${input.geometry.vertexInputs.filter((vertex) => vertex.semantic.startsWith("uv")).length} geometry UV sets`
1091
- });
1092
- }
1093
- if (!sameVertexInputs(receipt.vertexInputs, input.geometry.vertexInputs)) {
1094
- return failure("vertex-input-mismatch", {
1095
- reason: "vertex-semantic-mismatch",
1096
- owner: "geometry",
1097
- expected: receipt.vertexInputs.map((input2) => input2.semantic).join(","),
1098
- actual: input.geometry.vertexInputs.map((input2) => input2.semantic).join(",")
1099
- });
1100
- }
1101
- if (receipt.alphaMask.cutoff.length === 0) {
1102
- return failure("alpha-mask-mismatch", {
1103
- reason: "alpha-mask-receipt-missing",
1104
- owner: "material",
1105
- expected: "alphaMask.cutoff"
1106
- });
1107
- }
1108
- if (!hasMaterialResources(input.snapshot, receipt)) {
1109
- return failure("resource-not-ready", {
1110
- reason: "material-resource-missing",
1111
- owner: "material",
1112
- expected: receipt.resourceSlots.map((slot) => slot.parameter).join(",")
1113
- });
1114
- }
1115
- const deformation = input.snapshot.skin === void 0 ? "rigid" : "skin";
1116
- if (deformation === "skin") {
1117
- if (input.skinReceipt === void 0 || receipt.skinPaletteAddress === void 0) {
1118
- return failure("skin-receipt-mismatch", {
1119
- reason: "skin-address-missing",
1120
- owner: "skin",
1121
- expected: "skinPaletteAddress and skinReceipt"
1122
- });
1123
- }
1124
- if (input.skinReceipt.generation !== input.generation || input.skinReceipt.group !== receipt.skinPaletteAddress.group || input.skinReceipt.binding !== receipt.skinPaletteAddress.binding) {
1125
- return failure("skin-receipt-mismatch", {
1126
- reason: "skin-address-missing",
1127
- owner: "skin",
1128
- expected: `${receipt.skinPaletteAddress.group}:${receipt.skinPaletteAddress.binding}@${input.generation}`,
1129
- actual: `${input.skinReceipt.group}:${input.skinReceipt.binding}@${input.skinReceipt.generation}`
1130
- });
1131
- }
1132
- }
1133
- return {
1134
- ok: true,
1135
- value: {
1136
- identity: {
1137
- material: input.artifact.material,
1138
- geometry: input.geometry.identity,
1139
- deformation
1140
- },
1141
- receiptGeneration: receipt.generation,
1142
- directEntry: receipt.directEntry,
1143
- sceneIndexEntry: receipt.sceneIndexEntry,
1144
- materialRow: receipt.materialRow,
1145
- resourceSlots: receipt.resourceSlots,
1146
- uvSets: receipt.uvSets,
1147
- vertexInputs: receipt.vertexInputs,
1148
- alphaMask: receipt.alphaMask,
1149
- skinPaletteAddress: receipt.skinPaletteAddress,
1150
- topology: input.draw.topology,
1151
- indexed: input.draw.kind === "indexed",
1152
- first: input.draw.first,
1153
- count: input.draw.count,
1154
- baseVertex: input.draw.baseVertex
1155
- }
1156
- };
1157
- }
1158
-
1159
- // src/extract/gpu-driven.ts
1160
- function resolvePreparedGpuDrivenDraw(input) {
1161
- return prepareGpuDrivenDraw(input);
1162
- }
1163
- function gpuDrivenMaterialResourceClass(material) {
1164
- const textures = [...material.textureHandles?.entries() ?? []].map(([name, handle]) => [name, Number(handle)]).sort(([left], [right]) => left.localeCompare(right));
1165
- const samplers = [...material.samplerHandles?.entries() ?? []].map(([name, handle]) => [name, Number(handle)]).sort(([left], [right]) => left.localeCompare(right));
1166
- return JSON.stringify({
1167
- textures,
1168
- samplers,
1169
- video: [...material.videoTextureFields?.keys() ?? []].sort()
1170
- });
1171
- }
1172
- function buildGpuDrivenDraws(input) {
1173
- let nonIndexedFirst = 0;
1174
- return input.submeshes.flatMap((submesh) => {
1175
- const drawMaterial = input.materials[submesh.materialSlot] ?? input.fallbackMaterial;
1176
- const first = input.indexed ? submesh.indexOffset : nonIndexedFirst;
1177
- nonIndexedFirst += submesh.vertexCount;
1178
- if (drawMaterial.transparent === true) return [];
1179
- const draw = {
1180
- kind: input.indexed ? "indexed" : "non-indexed",
1181
- first,
1182
- count: input.indexed ? submesh.indexCount : submesh.vertexCount,
1183
- baseVertex: 0,
1184
- materialSlot: submesh.materialSlot,
1185
- topology: submesh.topology,
1186
- pipelineClass: `${drawMaterial.materialShaderId ?? "forgeax::default-unlit"}|${submesh.topology}|${JSON.stringify(drawMaterial.renderState ?? null)}`,
1187
- materialResourceClass: gpuDrivenMaterialResourceClass(drawMaterial)
1188
- };
1189
- const prepared = input.prepare?.(draw, drawMaterial);
1190
- return [prepared === void 0 ? draw : { ...draw, prepared }];
1191
- });
1192
- }
1193
1430
  var bakeCache = /* @__PURE__ */ new WeakMap();
1194
1431
  var materialCache = /* @__PURE__ */ new WeakMap();
1195
1432
  var liveGlyphSlots = /* @__PURE__ */ new WeakMap();
@@ -1252,8 +1489,8 @@ function glyphTextLayoutSystem(world, gpuStore) {
1252
1489
  const error = processEntity(world, gpuStore, entity);
1253
1490
  if (error !== null && firstError === null) firstError = error;
1254
1491
  }
1255
- if (firstError !== null) return err$1(firstError);
1256
- return ok$1(void 0);
1492
+ if (firstError !== null) return err(firstError);
1493
+ return ok(void 0);
1257
1494
  }
1258
1495
  function collectGlyphEntities(world) {
1259
1496
  const entities = [];
@@ -1421,13 +1658,15 @@ function signatureOf(gt) {
1421
1658
  function asFontHandle(raw) {
1422
1659
  return toShared(raw);
1423
1660
  }
1661
+
1662
+ // src/instances-derived-bounds.ts
1663
+ var fingerprintScalar = new Float32Array(1);
1664
+ var fingerprintBits = new Uint32Array(fingerprintScalar.buffer);
1424
1665
  function fingerprintNumericArray(values) {
1425
1666
  let hash = 2166136261;
1426
- const scalar = new Float32Array(1);
1427
- const bits = new Uint32Array(scalar.buffer);
1428
1667
  for (let index = 0; index < values.length; index += 1) {
1429
- scalar[0] = Number(values[index]);
1430
- hash = Math.imul(hash ^ (bits[0] ?? 0), 16777619) >>> 0;
1668
+ fingerprintScalar[0] = Number(values[index]);
1669
+ hash = Math.imul(hash ^ (fingerprintBits[0] ?? 0), 16777619) >>> 0;
1431
1670
  }
1432
1671
  return hash >>> 0;
1433
1672
  }
@@ -1448,14 +1687,128 @@ function finiteMatrix(matrix) {
1448
1687
  }
1449
1688
  return true;
1450
1689
  }
1451
- function includeBox(out, candidate) {
1452
- for (const x of [candidate[0], candidate[3]]) {
1453
- for (const y of [candidate[1], candidate[4]]) {
1454
- for (const z of [candidate[2], candidate[5]]) {
1455
- box3.expandByPoint(out, [x, y, z]);
1456
- }
1457
- }
1690
+ function multiplyMat4(out, left, right, rightOffset = 0) {
1691
+ for (let column = 0; column < 4; column += 1) {
1692
+ const rightColumn = rightOffset + column * 4;
1693
+ const right0 = Number(right[rightColumn] ?? 0);
1694
+ const right1 = Number(right[rightColumn + 1] ?? 0);
1695
+ const right2 = Number(right[rightColumn + 2] ?? 0);
1696
+ const right3 = Number(right[rightColumn + 3] ?? 0);
1697
+ const outOffset = column * 4;
1698
+ out[outOffset] = Number(left[0] ?? 0) * right0 + Number(left[4] ?? 0) * right1 + Number(left[8] ?? 0) * right2 + Number(left[12] ?? 0) * right3;
1699
+ out[outOffset + 1] = Number(left[1] ?? 0) * right0 + Number(left[5] ?? 0) * right1 + Number(left[9] ?? 0) * right2 + Number(left[13] ?? 0) * right3;
1700
+ out[outOffset + 2] = Number(left[2] ?? 0) * right0 + Number(left[6] ?? 0) * right1 + Number(left[10] ?? 0) * right2 + Number(left[14] ?? 0) * right3;
1701
+ out[outOffset + 3] = Number(left[3] ?? 0) * right0 + Number(left[7] ?? 0) * right1 + Number(left[11] ?? 0) * right2 + Number(left[15] ?? 0) * right3;
1702
+ }
1703
+ }
1704
+ function finiteMatrixAt(values, offset) {
1705
+ if (values.length - offset < 16) return false;
1706
+ for (let index = 0; index < 16; index += 1) {
1707
+ if (!Number.isFinite(values[offset + index])) return false;
1708
+ }
1709
+ return true;
1710
+ }
1711
+ function isAffine(matrix) {
1712
+ return matrix[3] === 0 && matrix[7] === 0 && matrix[11] === 0 && matrix[15] === 1;
1713
+ }
1714
+ function includeBox(out, candidate, initialized) {
1715
+ const minX = candidate[0];
1716
+ const minY = candidate[1];
1717
+ const minZ = candidate[2];
1718
+ const maxX = candidate[3];
1719
+ const maxY = candidate[4];
1720
+ const maxZ = candidate[5];
1721
+ if (!initialized) {
1722
+ out[0] = minX;
1723
+ out[1] = minY;
1724
+ out[2] = minZ;
1725
+ out[3] = maxX;
1726
+ out[4] = maxY;
1727
+ out[5] = maxZ;
1728
+ return true;
1458
1729
  }
1730
+ if (minX < (out[0] ?? Number.POSITIVE_INFINITY)) out[0] = minX;
1731
+ if (minY < (out[1] ?? Number.POSITIVE_INFINITY)) out[1] = minY;
1732
+ if (minZ < (out[2] ?? Number.POSITIVE_INFINITY)) out[2] = minZ;
1733
+ if (maxX > (out[3] ?? Number.NEGATIVE_INFINITY)) out[3] = maxX;
1734
+ if (maxY > (out[4] ?? Number.NEGATIVE_INFINITY)) out[4] = maxY;
1735
+ if (maxZ > (out[5] ?? Number.NEGATIVE_INFINITY)) out[5] = maxZ;
1736
+ return true;
1737
+ }
1738
+ function transformAabb(out, local, matrix) {
1739
+ const minX = local[0];
1740
+ const minY = local[1];
1741
+ const minZ = local[2];
1742
+ const maxX = local[3];
1743
+ const maxY = local[4];
1744
+ const maxZ = local[5];
1745
+ const centerX = (minX + maxX) * 0.5;
1746
+ const centerY = (minY + maxY) * 0.5;
1747
+ const centerZ = (minZ + maxZ) * 0.5;
1748
+ const extentX = (maxX - minX) * 0.5;
1749
+ const extentY = (maxY - minY) * 0.5;
1750
+ const extentZ = (maxZ - minZ) * 0.5;
1751
+ if (isAffine(matrix)) {
1752
+ const centerWorldX = matrix[0] * centerX + matrix[4] * centerY + matrix[8] * centerZ + matrix[12];
1753
+ const centerWorldY = matrix[1] * centerX + matrix[5] * centerY + matrix[9] * centerZ + matrix[13];
1754
+ const centerWorldZ = matrix[2] * centerX + matrix[6] * centerY + matrix[10] * centerZ + matrix[14];
1755
+ const extentWorldX = Math.abs(matrix[0]) * extentX + Math.abs(matrix[4]) * extentY + Math.abs(matrix[8]) * extentZ;
1756
+ const extentWorldY = Math.abs(matrix[1]) * extentX + Math.abs(matrix[5]) * extentY + Math.abs(matrix[9]) * extentZ;
1757
+ const extentWorldZ = Math.abs(matrix[2]) * extentX + Math.abs(matrix[6]) * extentY + Math.abs(matrix[10]) * extentZ;
1758
+ out[0] = centerWorldX - extentWorldX;
1759
+ out[1] = centerWorldY - extentWorldY;
1760
+ out[2] = centerWorldZ - extentWorldZ;
1761
+ out[3] = centerWorldX + extentWorldX;
1762
+ out[4] = centerWorldY + extentWorldY;
1763
+ out[5] = centerWorldZ + extentWorldZ;
1764
+ return finiteAabb(out);
1765
+ }
1766
+ let minimumW = Number.POSITIVE_INFINITY;
1767
+ let maximumW = Number.NEGATIVE_INFINITY;
1768
+ for (let corner = 0; corner < 8; corner += 1) {
1769
+ const x = (corner & 1) === 0 ? minX : maxX;
1770
+ const y = (corner & 2) === 0 ? minY : maxY;
1771
+ const z = (corner & 4) === 0 ? minZ : maxZ;
1772
+ const w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
1773
+ if (!Number.isFinite(w)) return false;
1774
+ if (w < minimumW) minimumW = w;
1775
+ if (w > maximumW) maximumW = w;
1776
+ }
1777
+ if (minimumW <= 0 && maximumW >= 0) return false;
1778
+ let unionMinX = Number.POSITIVE_INFINITY;
1779
+ let unionMinY = Number.POSITIVE_INFINITY;
1780
+ let unionMinZ = Number.POSITIVE_INFINITY;
1781
+ let unionMaxX = Number.NEGATIVE_INFINITY;
1782
+ let unionMaxY = Number.NEGATIVE_INFINITY;
1783
+ let unionMaxZ = Number.NEGATIVE_INFINITY;
1784
+ for (let corner = 0; corner < 8; corner += 1) {
1785
+ const x = (corner & 1) === 0 ? minX : maxX;
1786
+ const y = (corner & 2) === 0 ? minY : maxY;
1787
+ const z = (corner & 4) === 0 ? minZ : maxZ;
1788
+ const rawX = matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12];
1789
+ const rawY = matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13];
1790
+ const rawZ = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14];
1791
+ const w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
1792
+ const projectedX = rawX / w;
1793
+ const projectedY = rawY / w;
1794
+ const projectedZ = rawZ / w;
1795
+ if (!Number.isFinite(projectedX) || !Number.isFinite(projectedY) || !Number.isFinite(projectedZ)) {
1796
+ return false;
1797
+ }
1798
+ if (projectedX < unionMinX) unionMinX = projectedX;
1799
+ if (projectedY < unionMinY) unionMinY = projectedY;
1800
+ if (projectedZ < unionMinZ) unionMinZ = projectedZ;
1801
+ if (projectedX > unionMaxX) unionMaxX = projectedX;
1802
+ if (projectedY > unionMaxY) unionMaxY = projectedY;
1803
+ if (projectedZ > unionMaxZ) unionMaxZ = projectedZ;
1804
+ }
1805
+ out[0] = unionMinX;
1806
+ out[1] = unionMinY;
1807
+ out[2] = unionMinZ;
1808
+ out[3] = unionMaxX;
1809
+ out[4] = unionMaxY;
1810
+ out[5] = unionMaxZ;
1811
+ return finiteAabb(out);
1459
1812
  }
1460
1813
  function deriveInstancesUnionBounds(input) {
1461
1814
  const { meshAabb, entityWorld, transforms } = input;
@@ -1463,40 +1816,36 @@ function deriveInstancesUnionBounds(input) {
1463
1816
  return void 0;
1464
1817
  }
1465
1818
  if (transforms.length === 0 || transforms.length % 16 !== 0) return void 0;
1466
- const local = box3.create(
1467
- meshAabb[0],
1468
- meshAabb[1],
1469
- meshAabb[2],
1470
- meshAabb[3],
1471
- meshAabb[4],
1472
- meshAabb[5]
1473
- );
1474
- const union = box3.create();
1475
- const composed = mat4.create();
1476
- const transformed = box3.create();
1819
+ const local = meshAabb;
1820
+ const union = new Float32Array(6);
1821
+ const composed = new Float32Array(16);
1822
+ const transformed = new Float32Array(6);
1823
+ let initialized = false;
1477
1824
  for (let offset = 0; offset < transforms.length; offset += 16) {
1478
- const instance = new Float32Array(16);
1479
- for (let lane = 0; lane < 16; lane += 1) {
1480
- instance[lane] = transforms[offset + lane];
1481
- }
1482
- if (!finiteMatrix(instance)) return void 0;
1483
- mat4.multiply(composed, entityWorld, instance);
1484
- box3.transformBox3(transformed, local, composed);
1485
- if (!finiteAabb(transformed)) return void 0;
1486
- includeBox(union, transformed);
1825
+ if (!finiteMatrixAt(transforms, offset)) return void 0;
1826
+ multiplyMat4(composed, entityWorld, transforms, offset);
1827
+ if (!finiteMatrix(composed) || !transformAabb(transformed, local, composed)) return void 0;
1828
+ initialized = includeBox(union, transformed, initialized);
1487
1829
  }
1488
- return new Float32Array(union);
1830
+ return initialized && finiteAabb(union) ? union : void 0;
1489
1831
  }
1490
1832
  var InstanceBoundsCache = class {
1491
1833
  entries = /* @__PURE__ */ new Map();
1834
+ hits = 0;
1835
+ misses = 0;
1836
+ derives = 0;
1837
+ invalidations = 0;
1492
1838
  key(input) {
1493
1839
  return `${input.worldId === void 0 ? "" : `${input.worldId}:`}${input.entityKey}`;
1494
1840
  }
1495
1841
  get(input) {
1496
1842
  const previous = this.entries.get(this.key(input));
1497
1843
  if (previous !== void 0 && previous.meshGeneration === input.meshGeneration && previous.transformGeneration === input.transformGeneration && previous.matrixGeneration === input.matrixGeneration) {
1844
+ this.hits += 1;
1498
1845
  return previous.bounds;
1499
1846
  }
1847
+ this.misses += 1;
1848
+ this.derives += 1;
1500
1849
  const bounds = deriveInstancesUnionBounds(input);
1501
1850
  this.entries.set(this.key(input), {
1502
1851
  ...input.worldId === void 0 ? {} : { worldId: input.worldId },
@@ -1510,11 +1859,22 @@ var InstanceBoundsCache = class {
1510
1859
  }
1511
1860
  invalidate(entityKey, worldId) {
1512
1861
  if (entityKey === void 0) {
1862
+ if (this.entries.size > 0) this.invalidations += this.entries.size;
1513
1863
  this.entries.clear();
1514
1864
  } else {
1515
- this.entries.delete(this.key({ entityKey, ...worldId === void 0 ? {} : { worldId } }));
1865
+ if (this.entries.delete(this.key({ entityKey, ...worldId === void 0 ? {} : { worldId } }))) {
1866
+ this.invalidations += 1;
1867
+ }
1516
1868
  }
1517
1869
  }
1870
+ inspect() {
1871
+ return {
1872
+ hits: this.hits,
1873
+ misses: this.misses,
1874
+ derives: this.derives,
1875
+ invalidations: this.invalidations
1876
+ };
1877
+ }
1518
1878
  };
1519
1879
 
1520
1880
  // src/points-lines/bounds.ts
@@ -1602,13 +1962,40 @@ function createCookieProjectionMatrixData(count) {
1602
1962
  }
1603
1963
  return data;
1604
1964
  }
1965
+ function buildShadowFrusta(lights) {
1966
+ const result = [];
1967
+ const add = (matrix) => {
1968
+ result.push(frustum.fromViewProjection(frustum.create(), matrix));
1969
+ };
1970
+ for (const matrix of lights.lightViewProj?.slice(0, lights.cascadeCount) ?? []) add(matrix);
1971
+ for (const snapshot of lights.pointShadow) {
1972
+ if (snapshot.shadowAtlasLayer < 0) continue;
1973
+ for (let face = 0; face < 6; face += 1)
1974
+ add(snapshot.shadowMatrices.subarray(face * 16, (face + 1) * 16));
1975
+ }
1976
+ for (const snapshot of lights.spot) {
1977
+ if (snapshot.shadowAtlasTile >= 0 && snapshot.lightViewProj !== void 0)
1978
+ add(snapshot.lightViewProj);
1979
+ }
1980
+ return result;
1981
+ }
1605
1982
 
1606
1983
  // src/render-system-extract-tail.ts
1984
+ function skinPaletteIdentity(world, entity) {
1985
+ return `skin:${world.identity}:${entity}`;
1986
+ }
1607
1987
  function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCachesByWorld, options = {}) {
1608
1988
  const cameraOwner = typeof owner === "number" ? owner : owner.cameraOwner;
1609
1989
  const resourceOwner = typeof owner === "number" ? owner : owner.resourceOwner;
1990
+ const cameraEntityKey = typeof owner === "number" ? void 0 : owner.cameraEntityKey;
1991
+ const renderableRequest = options.renderables ?? "full";
1992
+ const renderableMode = typeof renderableRequest === "object" ? "full" : renderableRequest;
1993
+ const partialEntitiesByWorld = typeof renderableRequest === "object" ? renderableRequest.entitiesByWorld : void 0;
1994
+ const retainHidden = options.retainHidden ?? typeof renderableRequest === "object";
1610
1995
  const skinPaletteAllocator = pipelineState?.skinPaletteAllocator ?? null;
1611
- if (skinPaletteAllocator !== null) {
1996
+ const reconcileSkinFrame = renderableRequest === "full";
1997
+ if (skinPaletteAllocator !== null && reconcileSkinFrame) {
1998
+ skinPaletteAllocator.beginFrame();
1612
1999
  skinPaletteAllocator.resetForFrame();
1613
2000
  }
1614
2001
  const failedWorlds = /* @__PURE__ */ new Set();
@@ -1626,6 +2013,13 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1626
2013
  const world = worlds[wi];
1627
2014
  if (world === void 0 || failedWorlds.has(world)) continue;
1628
2015
  try {
2016
+ if (skinPaletteAllocator !== null && partialEntitiesByWorld !== void 0) {
2017
+ for (const entityKey of partialEntitiesByWorld[wi] ?? []) {
2018
+ if (!world.hasComponent(entityKey, Skin)) {
2019
+ skinPaletteAllocator.releasePersistentSlice(skinPaletteIdentity(world, entityKey));
2020
+ }
2021
+ }
2022
+ }
1629
2023
  const isCameraOwner = wi === cameraOwner;
1630
2024
  const cameraOwnerFrame2 = framesByWorld.get(cameraOwner);
1631
2025
  const prepared = prepareExtractContext(world, {
@@ -1641,18 +2035,20 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1641
2035
  },
1642
2036
  ...options.materialContext === void 0 ? {} : { materialContext: options.materialContext },
1643
2037
  cull: options.cull === "none" ? "none" : isCameraOwner ? "self" : "external",
1644
- renderables: options.renderables ?? "full",
1645
- ...options.renderableEntitiesByWorld?.[wi] === void 0 ? {} : { renderableEntities: options.renderableEntitiesByWorld[wi] },
1646
- retainHidden: options.retainHidden ?? false,
2038
+ renderables: renderableMode,
2039
+ ...isCameraOwner && cameraEntityKey !== void 0 ? { cameraEntityKey } : {},
2040
+ ...partialEntitiesByWorld?.[wi] === void 0 ? {} : { renderableEntities: partialEntitiesByWorld[wi] },
2041
+ retainHidden,
2042
+ worldId: wi,
1647
2043
  ...options.getMaterialShaderArtifact === void 0 ? {} : { getMaterialShaderArtifact: options.getMaterialShaderArtifact },
1648
2044
  ...options.instanceCollections === void 0 ? {} : { instanceCollections: options.instanceCollections },
1649
2045
  ...cameraOwnerFrame2 === void 0 ? {} : { cullCameras: cameraOwnerFrame2.cameras }
1650
2046
  });
1651
2047
  const frame = extractFrame(world, prepared);
1652
2048
  framesByWorld.set(wi, frame);
1653
- } catch (err6) {
2049
+ } catch (err8) {
1654
2050
  try {
1655
- createWorldInternalView(world)._routeError(err6, {
2051
+ createWorldInternalView(world)._routeError(err8, {
1656
2052
  severity: Severity.Error,
1657
2053
  systemName: `RenderSystem.extractFrames(world[${wi}])`
1658
2054
  });
@@ -1660,6 +2056,9 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1660
2056
  }
1661
2057
  }
1662
2058
  }
2059
+ if (skinPaletteAllocator !== null && reconcileSkinFrame) {
2060
+ skinPaletteAllocator.endFrame();
2061
+ }
1663
2062
  for (let wi = 0; wi < worlds.length; wi++) {
1664
2063
  const frame = framesByWorld.get(wi);
1665
2064
  if (frame === void 0) continue;
@@ -1668,6 +2067,9 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1668
2067
  }
1669
2068
  const renderables = [];
1670
2069
  const dispatchEntries = [];
2070
+ const shadowCasterEntityKeys = /* @__PURE__ */ new Set();
2071
+ const shadowCasterDrawKeys = /* @__PURE__ */ new Set();
2072
+ const shadowCasterMembership = /* @__PURE__ */ new Map();
1671
2073
  const visibilitySnapshots = [];
1672
2074
  const featureVisibilitySnapshots = [];
1673
2075
  const hiddenEntityReports = [];
@@ -1694,6 +2096,18 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1694
2096
  for (const d of f.dispatch) {
1695
2097
  dispatchEntries.push({ ...d, renderableIndex: (d.renderableIndex ?? 0) + base });
1696
2098
  }
2099
+ for (const key of f.shadowCasterEntityKeys) shadowCasterEntityKeys.add(key);
2100
+ for (const key of f.shadowCasterDrawKeys) shadowCasterDrawKeys.add(key);
2101
+ for (const membership of f.shadowCasterMembership ?? []) {
2102
+ const rebased = { ...membership, renderableIndex: membership.renderableIndex + base };
2103
+ const key = gpuDrivenShadowDrawKey(
2104
+ rebased.worldEntity,
2105
+ rebased.materialHandle,
2106
+ rebased.drawItemIndex,
2107
+ rebased.passIndex
2108
+ );
2109
+ shadowCasterMembership.set(key, rebased);
2110
+ }
1697
2111
  }
1698
2112
  dispatchEntries.sort((a, b) => (a.queue ?? 0) - (b.queue ?? 0));
1699
2113
  const point = [];
@@ -1713,11 +2127,14 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1713
2127
  const pointShadow = [];
1714
2128
  let directionalCsmConfig;
1715
2129
  let directionalCsmDirection;
1716
- for (const f of succeededFrames) {
1717
- for (const p of f.lights.point) point.push(p);
1718
- for (const s of f.lights.spot) spot.push(s);
2130
+ for (let fi = 0; fi < succeededFrames.length; fi += 1) {
2131
+ const f = succeededFrames[fi];
2132
+ const wId = succeededIndices[fi] ?? 0;
2133
+ if (f === void 0) continue;
2134
+ for (const p of f.lights.point) point.push({ ...p, worldId: wId });
2135
+ for (const s of f.lights.spot) spot.push({ ...s, worldId: wId });
1719
2136
  for (const r of f.lights.rect) rect.push(r);
1720
- for (const ps of f.lights.pointShadow) pointShadow.push(ps);
2137
+ for (const ps of f.lights.pointShadow) pointShadow.push({ ...ps, worldId: wId });
1721
2138
  if (directional === void 0 && f.lights.directional !== void 0) {
1722
2139
  directional = f.lights.directional;
1723
2140
  lightViewProj = f.lights.lightViewProj;
@@ -1740,8 +2157,8 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1740
2157
  if (succeededIndices[fi] === cameraOwner) cameraOwnerFrame = succeededFrames[fi];
1741
2158
  if (succeededIndices[fi] === resourceOwner) resourceOwnerFrame = succeededFrames[fi];
1742
2159
  }
1743
- const cameras = cameraOwnerFrame !== void 0 ? [...cameraOwnerFrame.cameras] : [];
1744
- const auxiliaryCameras = cameraOwnerFrame !== void 0 ? [...cameraOwnerFrame.auxiliaryCameras] : [];
2160
+ const cameras = cameraOwnerFrame?.cameras.map((camera) => ({ ...camera, worldId: cameraOwner })) ?? [];
2161
+ const auxiliaryCameras = cameraOwnerFrame?.auxiliaryCameras.map((camera) => ({ ...camera, worldId: cameraOwner })) ?? [];
1745
2162
  const cubeCameras = cameraOwnerFrame !== void 0 ? [...cameraOwnerFrame.cubeCameras] : [];
1746
2163
  const mergeCam = cameras[0];
1747
2164
  if (directionalCsmConfig !== void 0 && directionalCsmDirection !== void 0) {
@@ -1798,7 +2215,10 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1798
2215
  const fog = resourceOwnerFrame?.fog;
1799
2216
  const fogFailure = resourceOwnerFrame?.fogFailure;
1800
2217
  const environment = resourceOwnerFrame?.environment;
1801
- const lightProbes = succeededFrames.flatMap((frame) => frame.lightProbes ?? []);
2218
+ const lightProbes = succeededFrames.flatMap((frame, index) => {
2219
+ const worldId = succeededIndices[index] ?? 0;
2220
+ return (frame.lightProbes ?? []).map((probe) => ({ ...probe, worldId }));
2221
+ });
1802
2222
  const postProcessParams = new Map(resourceOwnerFrame?.postProcessParams);
1803
2223
  const OUTPUT_TRANSFORM_PARAM_KEY = STANDARD_OUTPUT_TRANSFORM_FEATURE_ID;
1804
2224
  const cameraTonemapParam = cameraOwnerFrame?.postProcessParams.get(OUTPUT_TRANSFORM_PARAM_KEY);
@@ -1814,28 +2234,28 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1814
2234
  const visibilityStats = {
1815
2235
  explicitlyHidden: succeededFrames.reduce((s, f) => s + f.visibilityStats.explicitlyHidden, 0)
1816
2236
  };
2237
+ const materialTextureSources = {
2238
+ sourceFieldsVisited: 0,
2239
+ numericSharedRefProbes: 0,
2240
+ sourceCacheHits: 0,
2241
+ sourceCacheMisses: 0,
2242
+ producerRoutes: {}
2243
+ };
2244
+ for (const frame of succeededFrames) {
2245
+ const stats = frame.materialTextureSources;
2246
+ if (stats === void 0) continue;
2247
+ materialTextureSources.sourceFieldsVisited += stats.sourceFieldsVisited;
2248
+ materialTextureSources.numericSharedRefProbes += stats.numericSharedRefProbes;
2249
+ materialTextureSources.sourceCacheHits += stats.sourceCacheHits;
2250
+ materialTextureSources.sourceCacheMisses += stats.sourceCacheMisses;
2251
+ for (const [route, count] of Object.entries(stats.producerRoutes)) {
2252
+ materialTextureSources.producerRoutes[route] = (materialTextureSources.producerRoutes[route] ?? 0) + count;
2253
+ }
2254
+ }
1817
2255
  const reflectionProbes = succeededFrames.flatMap((f, index) => {
1818
2256
  const worldId = succeededIndices[index] ?? 0;
1819
2257
  return (f.reflectionProbes ?? []).map((probe) => ({ ...probe, worldId }));
1820
2258
  });
1821
- if (options.renderables !== "none" && options.renderableEntitiesByWorld === void 0) {
1822
- options.instanceCollections?.retain(
1823
- new Set(
1824
- renderables.flatMap(
1825
- (row) => row.instances?.collectionId === void 0 ? [] : [row.instances.collectionId]
1826
- )
1827
- )
1828
- );
1829
- if (skinPaletteAllocator !== null && typeof skinPaletteAllocator.retainSliceKeys === "function") {
1830
- skinPaletteAllocator.retainSliceKeys(
1831
- new Set(
1832
- renderables.flatMap(
1833
- (row) => row.skin === void 0 ? [] : [`${worlds[row.worldId]?.identity ?? row.worldId}:${row.entityKey}`]
1834
- )
1835
- )
1836
- );
1837
- }
1838
- }
1839
2259
  return {
1840
2260
  cameras,
1841
2261
  auxiliaryCameras,
@@ -1845,6 +2265,9 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1845
2265
  ...volumetricFog === void 0 ? {} : { volumetricFog: { ...volumetricFog, worldId: resourceOwner } },
1846
2266
  renderables,
1847
2267
  dispatch: dispatchEntries,
2268
+ shadowCasterEntityKeys,
2269
+ shadowCasterDrawKeys,
2270
+ ...shadowCasterMembership.size === 0 ? {} : { shadowCasterMembership: [...shadowCasterMembership.values()] },
1848
2271
  skylight,
1849
2272
  skylightCount,
1850
2273
  lightProbes,
@@ -1856,6 +2279,7 @@ function extractFrames(worlds, owner, assets, pipelineState, materialSnapshotCac
1856
2279
  environmentReady: resourceOwnerFrame !== void 0 && environment !== void 0,
1857
2280
  frustumStats,
1858
2281
  visibilityStats,
2282
+ materialTextureSources,
1859
2283
  postProcessParams,
1860
2284
  visibilitySnapshots,
1861
2285
  featureVisibilitySnapshots,
@@ -1916,10 +2340,18 @@ function extractFrame(world, context) {
1916
2340
  const fogFailure = fogState(world).failure;
1917
2341
  const visibility = context.visibility.hasAnyHiddenIntent ? context.visibility : void 0;
1918
2342
  const skinPaletteAllocator = pipelineState?.skinPaletteAllocator ?? null;
2343
+ const materialTextureSourceStats = {
2344
+ sourceFieldsVisited: 0,
2345
+ numericSharedRefProbes: 0,
2346
+ sourceCacheHits: 0,
2347
+ sourceCacheMisses: 0,
2348
+ producerRoutes: {}
2349
+ };
2350
+ const materialTextureSourceCache = /* @__PURE__ */ new Map();
1919
2351
  const directionalLightQuery = world.query({ read: [DirectionalLight] }).unwrap();
1920
2352
  const worldInternal = createWorldInternalView(world);
1921
2353
  let volumetricFog = extractVolumeSnapshot(world, assets, worldInternal);
1922
- const cameraRoles = selectCameraRoles(world);
2354
+ const cameraRoles = selectCameraRoles(world, context.cameraEntityKey);
1923
2355
  const cameras = [...cameraRoles.display];
1924
2356
  const auxiliaryCameras = cameraRoles.auxiliary;
1925
2357
  const cubeCameras = collectCubeCameraSnapshots(world);
@@ -1996,6 +2428,7 @@ function extractFrame(world, context) {
1996
2428
  pointSnapshots.push({
1997
2429
  kind: "point",
1998
2430
  entity: entityId,
2431
+ worldId: context.worldId,
1999
2432
  position,
2000
2433
  color: vec3.create(
2001
2434
  (p.color[0] ?? 1) * intensity,
@@ -2129,6 +2562,7 @@ function extractFrame(world, context) {
2129
2562
  spotSnapshots.push({
2130
2563
  kind: "spot",
2131
2564
  entity: row.entity,
2565
+ worldId: context.worldId,
2132
2566
  // D-6: position reflects world transform; direction stays sourced
2133
2567
  // from SpotLight.direction (NOT rotated by the parent).
2134
2568
  position,
@@ -2340,10 +2774,13 @@ function extractFrame(world, context) {
2340
2774
  }
2341
2775
  pointShadowSnapshots.push({
2342
2776
  entity: row.entity,
2777
+ worldId: context.worldId,
2343
2778
  position: lightPos,
2344
2779
  mapSize,
2345
2780
  nearPlane,
2346
2781
  farPlane,
2782
+ depthBias: ps.depthBias,
2783
+ normalBias: ps.normalBias,
2347
2784
  shadowAtlasLayer: layer,
2348
2785
  shadowMatrices: packed
2349
2786
  });
@@ -2386,6 +2823,7 @@ function extractFrame(world, context) {
2386
2823
  directionalCsmConfig,
2387
2824
  directionalCsmDirection
2388
2825
  };
2826
+ const shadowFrusta = cullMode === "none" ? [] : buildShadowFrusta(lights);
2389
2827
  const skylightQuery = world.query({ read: [Skylight] }).unwrap();
2390
2828
  let skylight;
2391
2829
  let skylightCount = 0;
@@ -2432,6 +2870,7 @@ function extractFrame(world, context) {
2432
2870
  const transform = row.get(GlobalTransform);
2433
2871
  lightProbes.push({
2434
2872
  identity: String(row.entity),
2873
+ worldId: context.worldId,
2435
2874
  position: [transform.world[12] ?? 0, transform.world[13] ?? 0, transform.world[14] ?? 0],
2436
2875
  radius: probe.radius,
2437
2876
  irradiance: new Float32Array(probe.irradiance),
@@ -2494,19 +2933,21 @@ function extractFrame(world, context) {
2494
2933
  directionalDirection[1] ?? 0,
2495
2934
  directionalDirection[2] ?? 0
2496
2935
  );
2497
- const sun = directional === void 0 || directionalLength <= 1e-6 ? [] : [
2936
+ const sunIntensity = directional?.intensity ?? 0;
2937
+ const sunColor = sunIntensity > 0 && directional !== void 0 ? [
2938
+ (directional.color[0] ?? 0) / sunIntensity,
2939
+ (directional.color[1] ?? 0) / sunIntensity,
2940
+ (directional.color[2] ?? 0) / sunIntensity
2941
+ ] : [0, 0, 0];
2942
+ const sun = directional === void 0 || directional.entity === void 0 || directionalLength <= 1e-6 ? [] : [
2498
2943
  {
2499
- entityKey: 0,
2944
+ entityKey: directional.entity,
2500
2945
  direction: [
2501
2946
  -(directionalDirection?.[0] ?? 0) / directionalLength,
2502
2947
  -(directionalDirection?.[1] ?? 0) / directionalLength,
2503
2948
  -(directionalDirection?.[2] ?? 0) / directionalLength
2504
2949
  ],
2505
- color: [
2506
- directional.color[0] ?? 0,
2507
- directional.color[1] ?? 0,
2508
- directional.color[2] ?? 0
2509
- ],
2950
+ color: sunColor,
2510
2951
  intensity: directional.intensity
2511
2952
  }
2512
2953
  ];
@@ -2563,7 +3004,9 @@ function extractFrame(world, context) {
2563
3004
  let frustumTotal = 0;
2564
3005
  const explicitlyHidden = /* @__PURE__ */ new Set();
2565
3006
  let dispatch = [];
3007
+ const shadowMembershipEntries = [];
2566
3008
  const materialSnapshotCache = /* @__PURE__ */ new Map();
3009
+ const instanceSnapshotCache = /* @__PURE__ */ new Map();
2567
3010
  const skinnedMaterialSnapshotCache = /* @__PURE__ */ new Map();
2568
3011
  const meshRendererQuery = context.renderables === "none" ? [] : world.query({
2569
3012
  read: [MeshRenderer],
@@ -2606,7 +3049,8 @@ function extractFrame(world, context) {
2606
3049
  }
2607
3050
  const hasTransform = row.has(Transform);
2608
3051
  const meshFilter = row.get(MeshFilter);
2609
- const hasInstances = row.has(Instances);
3052
+ const instancesData = row.get(Instances);
3053
+ const hasInstances = instancesData !== void 0;
2610
3054
  const skin = row.get(Skin);
2611
3055
  const morphWeightsView = worldInternal._getArrayView(row.entity, MorphWeights, "weights");
2612
3056
  const hasMeshFilter = meshFilter !== void 0;
@@ -2641,9 +3085,7 @@ function extractFrame(world, context) {
2641
3085
  () => "renderer-override"
2642
3086
  );
2643
3087
  let materialBindingDiagnostics = [];
2644
- let gpuDrivenSubmeshes = [];
2645
- let gpuDrivenIndexed = false;
2646
- let gpuDrivenGeometry;
3088
+ let gpuDrivenMesh;
2647
3089
  const fAssetHandleVal = fAssetHandle;
2648
3090
  if (fAssetHandleVal !== void 0 && fAssetHandleVal !== 0 && assets !== void 0 && assets !== null) {
2649
3091
  const meshHandle = toShared(fAssetHandleVal);
@@ -2651,19 +3093,7 @@ function extractFrame(world, context) {
2651
3093
  if (meshRes.ok && meshRes.value.kind === "mesh") {
2652
3094
  const meshAsset = meshRes.value;
2653
3095
  const guid = meshRes.value.guid ?? "<no-guid>";
2654
- gpuDrivenSubmeshes = meshAsset.submeshes;
2655
- gpuDrivenIndexed = meshAsset.indices !== void 0;
2656
- const layoutProjection = deriveVertexLayoutProjection(meshAsset.attributes);
2657
- gpuDrivenGeometry = {
2658
- identity: `${guid}:${layoutProjection.digest}`,
2659
- vertexInputs: layoutProjection.attributes.map((attribute) => ({
2660
- semantic: attribute.key,
2661
- location: attribute.shaderLocation,
2662
- format: attribute.format
2663
- })),
2664
- topology: meshAsset.submeshes[0]?.topology ?? "triangle-list",
2665
- indexed: gpuDrivenIndexed
2666
- };
3096
+ gpuDrivenMesh = meshAsset;
2667
3097
  if (!Array.isArray(meshAsset.materialSlots) && world.get(entity, GlyphText).ok) {
2668
3098
  ensureGlyphMeshMaterialSlots(world, meshHandle);
2669
3099
  }
@@ -2830,28 +3260,28 @@ function extractFrame(world, context) {
2830
3260
  } else {
2831
3261
  const resolvedResult = walkMaterialPassesOverSharedRefs(world, tagged, assets);
2832
3262
  if (!resolvedResult.ok) {
2833
- const err6 = resolvedResult.error;
2834
- switch (err6.code) {
3263
+ const err8 = resolvedResult.error;
3264
+ switch (err8.code) {
2835
3265
  case "material-parent-not-found":
2836
3266
  case "material-no-effective-pass":
2837
3267
  case "material-value-unknown":
2838
3268
  case "material-value-type-mismatch":
2839
3269
  case "material-contract-program-mismatch":
2840
- worldInternal._routeError(err6, {
3270
+ worldInternal._routeError(err8, {
2841
3271
  severity: Severity.Error,
2842
- systemName: `RenderSystem.extract (${err6.code})`
3272
+ systemName: `RenderSystem.extract (${err8.code})`
2843
3273
  });
2844
3274
  break;
2845
3275
  case "material-circular-inheritance":
2846
- worldInternal._routeError(err6, {
3276
+ worldInternal._routeError(err8, {
2847
3277
  severity: Severity.Error,
2848
3278
  systemName: "RenderSystem.extract (material-circular-inheritance)"
2849
3279
  });
2850
3280
  break;
2851
3281
  default:
2852
- worldInternal._routeError(err6, {
3282
+ worldInternal._routeError(err8, {
2853
3283
  severity: Severity.Error,
2854
- systemName: `RenderSystem.extract (_materialWalk: ${err6.code})`
3284
+ systemName: `RenderSystem.extract (_materialWalk: ${err8.code})`
2855
3285
  });
2856
3286
  }
2857
3287
  continue;
@@ -2983,6 +3413,16 @@ function extractFrame(world, context) {
2983
3413
  firstPassShader,
2984
3414
  materialParamSchema.length > 0 ? derive(materialParamSchema).textureFieldNames : firstPassShader !== void 0 && assets !== null && assets !== void 0 ? assets.materialShaderTextureFieldNames(firstPassShader) : void 0
2985
3415
  ) ?? BUILTIN_USER_REGION_TEXTURE_FIELDS;
3416
+ const authoredTextureFields = collectAuthoredMaterialTextureFields(
3417
+ resolved.values,
3418
+ firstPassShader,
3419
+ materialParamSchema.length > 0 ? materialParamSchema : void 0,
3420
+ assets
3421
+ );
3422
+ const authoredSamplerFields = collectAuthoredMaterialSamplerFields(
3423
+ resolved.values,
3424
+ authoredTextureFields
3425
+ );
2986
3426
  const textureHandles = /* @__PURE__ */ new Map();
2987
3427
  const videoTextureFields = /* @__PURE__ */ new Map();
2988
3428
  for (const field of userRegionFields) {
@@ -3010,7 +3450,15 @@ function extractFrame(world, context) {
3010
3450
  pv.occlusionTexture
3011
3451
  );
3012
3452
  const textureCoordinates = collectMaterialTextureCoordinates(pv);
3013
- const textureSources = collectMaterialTextureSources(pv, world);
3453
+ const textureSources = collectMaterialTextureSources(
3454
+ pv,
3455
+ world,
3456
+ materialTextureSourceFields(
3457
+ materialParamSchema.length > 0 ? materialParamSchema : void 0
3458
+ ),
3459
+ materialTextureSourceStats,
3460
+ materialTextureSourceCache
3461
+ );
3014
3462
  const emissivePv = pv.emissive;
3015
3463
  const firstPassTransparent = allPasses[0]?.renderState?.blend !== void 0;
3016
3464
  if (isSprite) {
@@ -3068,8 +3516,15 @@ function extractFrame(world, context) {
3068
3516
  renderState: pipelineRenderState(allPasses[0]?.renderState),
3069
3517
  paramSnapshot: paramSnap,
3070
3518
  ...materialParamSchema.length > 0 && { materialParamSchema },
3519
+ standardTextureMask: materialStandardTextureMask(
3520
+ resolved.parameters,
3521
+ firstPassShader,
3522
+ pv
3523
+ ),
3071
3524
  ...textureCoordinates.size > 0 && { textureCoordinates },
3525
+ ...authoredTextureFields === void 0 ? {} : { authoredTextureFields },
3072
3526
  ...samplerHandles.size > 0 && { samplerHandles },
3527
+ ...authoredSamplerFields === void 0 ? {} : { authoredSamplerFields },
3073
3528
  ...textureHandles.size > 0 && { textureHandles },
3074
3529
  ...textureSources.size > 0 && { textureSources },
3075
3530
  ...videoTextureFields.size > 0 && { videoTextureFields },
@@ -3155,6 +3610,12 @@ function extractFrame(world, context) {
3155
3610
  }
3156
3611
  if (isRenderable) {
3157
3612
  let skinSlice;
3613
+ const skinIdentity = hasSkin ? skinPaletteIdentity(world, entity) : void 0;
3614
+ const releaseSkinIdentity = () => {
3615
+ if (skinIdentity !== void 0) {
3616
+ skinPaletteAllocator?.releasePersistentSlice(skinIdentity);
3617
+ }
3618
+ };
3158
3619
  if (hasSkin) {
3159
3620
  const skeletonHandleRaw = skinSkeletonView;
3160
3621
  if (skeletonHandleRaw !== void 0 && skeletonHandleRaw !== 0 && assets !== void 0 && assets !== null) {
@@ -3163,6 +3624,7 @@ function extractFrame(world, context) {
3163
3624
  severity: Severity.Error,
3164
3625
  systemName: "RenderSystem.extract (skin-instances-coexist)"
3165
3626
  });
3627
+ releaseSkinIdentity();
3166
3628
  continue;
3167
3629
  }
3168
3630
  const skeletonHandle = toShared(skeletonHandleRaw);
@@ -3172,11 +3634,15 @@ function extractFrame(world, context) {
3172
3634
  severity: Severity.Error,
3173
3635
  systemName: "RenderSystem.extract (skeleton-resolve-failed)"
3174
3636
  });
3637
+ releaseSkinIdentity();
3175
3638
  continue;
3176
3639
  }
3177
3640
  const skeleton = skeletonRes.value;
3178
3641
  const skinJoints = skin?.joints;
3179
- if (skinJoints === void 0) continue;
3642
+ if (skinJoints === void 0) {
3643
+ releaseSkinIdentity();
3644
+ continue;
3645
+ }
3180
3646
  const jointsLength = skinJoints.length;
3181
3647
  if (jointsLength !== skeleton.jointCount) {
3182
3648
  worldInternal._routeError(
@@ -3186,6 +3652,7 @@ function extractFrame(world, context) {
3186
3652
  systemName: "RenderSystem.extract (joint-count-mismatch)"
3187
3653
  }
3188
3654
  );
3655
+ releaseSkinIdentity();
3189
3656
  continue;
3190
3657
  }
3191
3658
  const jointWorlds = new Array(skeleton.jointCount);
@@ -3207,6 +3674,7 @@ function extractFrame(world, context) {
3207
3674
  severity: Severity.Error,
3208
3675
  systemName: "RenderSystem.extract (joint-entity-dangling)"
3209
3676
  });
3677
+ releaseSkinIdentity();
3210
3678
  continue;
3211
3679
  }
3212
3680
  const ibmFlat = skeleton.inverseBindMatrices;
@@ -3215,25 +3683,33 @@ function extractFrame(world, context) {
3215
3683
  ibms[jIdx] = ibmFlat.subarray(jIdx * 16, jIdx * 16 + 16);
3216
3684
  }
3217
3685
  if (skinPaletteAllocator !== null) {
3218
- const slice = typeof skinPaletteAllocator.allocateSliceFor === "function" ? skinPaletteAllocator.allocateSliceFor(
3219
- `${world.identity}:${entity}`,
3220
- skeleton.jointCount
3221
- ) : skinPaletteAllocator.allocateSlice(skeleton.jointCount);
3222
- skinPaletteAllocator.writeJointPalette(slice, ibms, jointWorlds);
3223
- skinSlice = {
3224
- jointCount: slice.jointCount,
3225
- byteOffset: slice.byteOffset,
3226
- buffer: slice.buffer
3227
- };
3686
+ const identity = skinPaletteIdentity(world, entity);
3687
+ const generation = skeletonHandleRaw >>> 0 ^ skeleton.jointCount;
3688
+ const bounds = hasFiniteOrderedLocalAabb(skeleton.bounds) ? new Float32Array(skeleton.bounds) : void 0;
3689
+ skinPaletteAllocator.observePersistentJoints(identity, ibms, jointWorlds);
3690
+ const receipt = skinPaletteAllocator.allocatePersistentSlice({
3691
+ identity,
3692
+ generation: generation >>> 0,
3693
+ jointCount: skeleton.jointCount,
3694
+ ...bounds === void 0 ? {} : { bounds }
3695
+ });
3696
+ skinPaletteAllocator.writePersistentJointPalette(receipt, ibms, jointWorlds);
3697
+ skinSlice = receipt;
3228
3698
  }
3229
3699
  }
3230
3700
  }
3231
- if (materialSnap.materialShaderId === "forgeax::pbr-skin" && skinSlice === void 0) {
3232
- pendingDispatch.length = 0;
3233
- continue;
3701
+ if (skinSlice === void 0 && hasSkin) {
3702
+ releaseSkinIdentity();
3703
+ if (materialSnap.materialShaderId === "forgeax::pbr-skin") {
3704
+ pendingDispatch.length = 0;
3705
+ continue;
3706
+ }
3234
3707
  }
3235
3708
  const worldView = worldInternal._getArrayView(entity, GlobalTransform, "world");
3236
- if (worldView === void 0) continue;
3709
+ if (worldView === void 0) {
3710
+ releaseSkinIdentity();
3711
+ continue;
3712
+ }
3237
3713
  const worldMat = new Float32Array(worldView);
3238
3714
  const transformSnap = { world: worldMat };
3239
3715
  const materialsArr = [materialSnap];
@@ -3252,7 +3728,9 @@ function extractFrame(world, context) {
3252
3728
  context.materialContext === void 0 ? void 0 : {
3253
3729
  ...context.materialContext,
3254
3730
  geometry: hasSkin ? "skinned" : context.materialContext.geometry
3255
- }
3731
+ },
3732
+ materialTextureSourceStats,
3733
+ materialTextureSourceCache
3256
3734
  )
3257
3735
  );
3258
3736
  }
@@ -3344,7 +3822,7 @@ function extractFrame(world, context) {
3344
3822
  lods = meshAsset.lods;
3345
3823
  lodHysteresis = meshAsset.lodHysteresis;
3346
3824
  morph = morphSnapshotFor(meshAsset, morphWeightsView);
3347
- const meshAabb = meshAsset.aabb;
3825
+ const meshAabb = skinSlice?.bounds ?? meshAsset.aabb;
3348
3826
  if (morph === void 0 && hasFiniteOrderedLocalAabb(meshAabb)) {
3349
3827
  localAabb = new Float32Array(meshAabb);
3350
3828
  }
@@ -3356,7 +3834,7 @@ function extractFrame(world, context) {
3356
3834
  })() : lines === void 0 ? void 0 : { kind: "lines", widthPx: lines.widthPx };
3357
3835
  const cullingLocalAabb = expandPointsLinesBounds(localAabb ?? [], pointsLinesStyle);
3358
3836
  const pointsLines = pointsLinesComponent === void 0 ? void 0 : {
3359
- worldId: 0,
3837
+ worldId: context.worldId,
3360
3838
  entityKey: entity,
3361
3839
  component: pointsLinesComponent,
3362
3840
  meshHandle: assetHandleRaw,
@@ -3373,27 +3851,44 @@ function extractFrame(world, context) {
3373
3851
  };
3374
3852
  let instancesSnap;
3375
3853
  if (hasInstances) {
3376
- const transforms = worldInternal._getArrayView(entity, Instances, "transforms") ?? new Float32Array();
3377
- if (transforms.length % 16 !== 0) {
3378
- worldInternal._routeError(
3379
- new InstanceTransformsStrideMismatchError(transforms.length),
3380
- {
3381
- severity: Severity.Error,
3382
- systemName: "RenderSystem.extract (Instances stride)"
3383
- }
3854
+ const collectionId = instancesData?.collectionId;
3855
+ let collectionResult = collectionId !== void 0 ? instanceSnapshotCache.get(collectionId) : void 0;
3856
+ if (collectionResult === void 0) {
3857
+ collectionResult = collectionId !== void 0 && collectionId > 0 && instanceCollections !== void 0 ? instanceCollections.snapshot(collectionId) : err(
3858
+ new InstanceCollectionError(
3859
+ "instance-collection-invalid",
3860
+ "Instances.collectionId references a live renderer-owned collection",
3861
+ "create the collection through renderer.instances before attaching Instances",
3862
+ {
3863
+ operation: "inspect",
3864
+ expected: "a positive collectionId with a live renderer owner",
3865
+ actual: Number(collectionId ?? 0),
3866
+ ...collectionId === void 0 ? {} : { collectionId }
3867
+ }
3868
+ )
3384
3869
  );
3870
+ if (collectionId !== void 0)
3871
+ instanceSnapshotCache.set(collectionId, collectionResult);
3872
+ }
3873
+ if (collectionResult === void 0) continue;
3874
+ if (!collectionResult.ok) {
3875
+ worldInternal._routeError(collectionResult.error, {
3876
+ severity: Severity.Error,
3877
+ systemName: "RenderSystem.extract (Instances collection)"
3878
+ });
3385
3879
  continue;
3386
3880
  }
3387
- const projected = instanceCollections?.project(world, entity, transforms);
3388
3881
  instancesSnap = {
3389
- transforms: projected?.transforms ?? new Float32Array(transforms),
3390
- instanceCount: transforms.length / 16,
3882
+ transforms: collectionResult.value.transforms,
3883
+ instanceCount: collectionResult.value.count,
3884
+ collectionId: collectionResult.value.collectionId,
3885
+ revision: collectionResult.value.revision,
3886
+ capacity: collectionResult.value.capacity,
3887
+ dirtyRanges: collectionResult.value.dirtyRanges,
3391
3888
  cacheKey: entity,
3392
- archVersion: projected === void 0 ? fingerprintNumericArray(transforms) : 0,
3393
- ...projected === void 0 ? {} : {
3394
- collectionId: projected.collectionId,
3395
- revision: projected.revision
3396
- }
3889
+ // Explicit collection revisions supersede ECS archetype content
3890
+ // hashes; retain zero as the legacy sprite-only field value.
3891
+ archVersion: 0
3397
3892
  };
3398
3893
  }
3399
3894
  const baseRenderable = {
@@ -3406,7 +3901,7 @@ function extractFrame(world, context) {
3406
3901
  materials: materialsArr,
3407
3902
  materialBindingSources,
3408
3903
  materialBindingDiagnostics,
3409
- worldId: 0,
3904
+ worldId: context.worldId,
3410
3905
  entityKey: entity,
3411
3906
  ...authorVisible ? {} : { authorVisible: false },
3412
3907
  ...skinSlice !== void 0 ? { skin: skinSlice } : {},
@@ -3417,32 +3912,25 @@ function extractFrame(world, context) {
3417
3912
  ...pointsLines !== void 0 ? { pointsLines } : {}
3418
3913
  };
3419
3914
  const gpuDrivenDraws = buildGpuDrivenDraws({
3420
- submeshes: gpuDrivenSubmeshes,
3421
- indexed: gpuDrivenIndexed,
3915
+ mesh: gpuDrivenMesh,
3422
3916
  materials: materialsArr,
3423
3917
  fallbackMaterial: materialSnap,
3424
- ...gpuDrivenGeometry === void 0 || getMaterialShaderArtifact === void 0 ? {} : {
3425
- prepare(draw, drawMaterial) {
3426
- const materialShaderId = drawMaterial.materialShaderId;
3427
- if (materialShaderId === void 0) return void 0;
3428
- const artifact = getMaterialShaderArtifact(materialShaderId);
3429
- if (artifact?.receipt === void 0) return void 0;
3430
- const geometry = {
3431
- ...gpuDrivenGeometry,
3432
- topology: draw.topology,
3433
- indexed: draw.kind === "indexed"
3434
- };
3435
- const result = resolvePreparedGpuDrivenDraw({
3436
- snapshot: { ...baseRenderable, material: drawMaterial },
3437
- artifact,
3438
- geometry,
3439
- generation: artifact.receipt.generation,
3440
- draw
3441
- });
3442
- return result.ok ? result.value : void 0;
3443
- }
3918
+ baseSnapshot: baseRenderable,
3919
+ ...getMaterialShaderArtifact === void 0 ? {} : { getMaterialShaderArtifact },
3920
+ ...lods === void 0 ? {} : {
3921
+ lodMeshes: lods.map((lod) => {
3922
+ const lower = assets?.lookup(lod.mesh);
3923
+ return lower?.kind === "mesh" ? lower : void 0;
3924
+ })
3444
3925
  }
3445
3926
  });
3927
+ for (const draw of gpuDrivenDraws) {
3928
+ if (draw.preparationError === void 0) continue;
3929
+ worldInternal._routeError(draw.preparationError, {
3930
+ severity: Severity.Error,
3931
+ systemName: `RenderSystem.extract (gpu-driven-preparation:${draw.preparationError.code})`
3932
+ });
3933
+ }
3446
3934
  const renderable = morph === void 0 && gpuDrivenDraws.length > 0 ? { ...baseRenderable, gpuDrivenDraws } : baseRenderable;
3447
3935
  if (localAabb !== void 0) {
3448
3936
  const derivedInstancesBounds = instancesSnap === void 0 || instancesSnap.instanceCount === 0 ? void 0 : deriveInstancesUnionBounds({
@@ -3477,16 +3965,93 @@ function extractFrame(world, context) {
3477
3965
  }
3478
3966
  if (!visible) {
3479
3967
  frustumCulled += 1;
3968
+ const shadowVisible = shadowFrusta.length > 0 && pendingDispatch.some((entry) => entry.tags.LightMode === "ShadowCaster") && shadowFrusta.some(
3969
+ (lightPlanes) => frustum.intersectsBox(lightPlanes, worldAabb)
3970
+ );
3971
+ if (!shadowVisible) continue;
3972
+ for (let i = pendingDispatch.length - 1; i >= 0; i -= 1) {
3973
+ if (pendingDispatch[i]?.tags.LightMode !== "ShadowCaster") {
3974
+ pendingDispatch.splice(i, 1);
3975
+ }
3976
+ }
3977
+ }
3978
+ }
3979
+ }
3980
+ const localShadowMembershipEntries = [];
3981
+ if (gpuDrivenMesh !== void 0) {
3982
+ const worldEntity = worldEntityKey(context.worldId, entity);
3983
+ for (const [drawItemIndex, submesh] of gpuDrivenMesh.submeshes.entries()) {
3984
+ if (submesh.topology !== "triangle-list" && submesh.topology !== "triangle-strip") {
3480
3985
  continue;
3481
3986
  }
3987
+ const material = materialsArr[submesh.materialSlot] ?? materialSnap;
3988
+ const materialHandle = material.materialHandle ?? -1;
3989
+ const shadowEntries = pendingDispatch.filter(
3990
+ (entry) => entry.tags.LightMode === "ShadowCaster" && entry.materialHandle === materialHandle
3991
+ );
3992
+ const draw = renderable.gpuDrivenDraws?.find(
3993
+ (candidate, compactIndex) => gpuDrivenSourceDrawItemIndex(candidate, compactIndex) === drawItemIndex
3994
+ );
3995
+ const cpuReason = shadowCasterCpuReason(
3996
+ material,
3997
+ draw,
3998
+ shadowEntries,
3999
+ morph,
4000
+ skinSlice
4001
+ );
4002
+ for (const entry of shadowEntries) {
4003
+ const membership = {
4004
+ worldEntity,
4005
+ renderableIndex: renderables.length,
4006
+ drawItemIndex,
4007
+ materialHandle,
4008
+ passIndex: entry.passIndex,
4009
+ ...entry.materialShaderId === void 0 ? {} : { materialShaderId: entry.materialShaderId },
4010
+ ...entry.renderState === void 0 ? {} : { renderState: entry.renderState },
4011
+ ...cpuReason === void 0 ? {} : { cpuReason }
4012
+ };
4013
+ shadowMembershipEntries.push(membership);
4014
+ localShadowMembershipEntries.push(membership);
4015
+ }
3482
4016
  }
3483
4017
  }
4018
+ const shadowCasterPasses = localShadowMembershipEntries.map((membership) => ({
4019
+ drawItemIndex: membership.drawItemIndex,
4020
+ materialHandle: membership.materialHandle,
4021
+ passIndex: membership.passIndex,
4022
+ ...membership.materialShaderId === void 0 ? {} : { materialShaderId: membership.materialShaderId },
4023
+ ...membership.renderState === void 0 ? {} : { renderState: membership.renderState },
4024
+ ...membership.cpuReason === void 0 ? {} : { cpuReason: membership.cpuReason }
4025
+ }));
4026
+ const renderableWithShadowPasses = shadowCasterPasses.length === 0 ? renderable : { ...renderable, shadowCasterPasses };
3484
4027
  flushPendingDispatch(pendingDispatch);
3485
- renderables.push(renderable);
4028
+ renderables.push(renderableWithShadowPasses);
3486
4029
  }
3487
4030
  }
3488
4031
  }
3489
4032
  dispatch = sortDispatchByQueue(dispatch);
4033
+ const shadowCasterEntityKeys = /* @__PURE__ */ new Set();
4034
+ const shadowCasterDrawKeys = /* @__PURE__ */ new Set();
4035
+ const shadowCasterMembership = /* @__PURE__ */ new Map();
4036
+ for (const entry of dispatch) {
4037
+ if (entry.tags.LightMode !== "ShadowCaster") continue;
4038
+ const renderable = renderables[entry.renderableIndex];
4039
+ if (renderable !== void 0) {
4040
+ const worldEntity = worldEntityKey(renderable.worldId, renderable.entityKey);
4041
+ shadowCasterEntityKeys.add(worldEntity);
4042
+ }
4043
+ }
4044
+ for (const membership of shadowMembershipEntries) {
4045
+ const key = gpuDrivenShadowDrawKey(
4046
+ membership.worldEntity,
4047
+ membership.materialHandle,
4048
+ membership.drawItemIndex,
4049
+ membership.passIndex
4050
+ );
4051
+ shadowCasterDrawKeys.add(key);
4052
+ shadowCasterMembership.set(key, membership);
4053
+ shadowCasterEntityKeys.add(membership.worldEntity);
4054
+ }
3490
4055
  const postProcessParams = /* @__PURE__ */ new Map();
3491
4056
  const postProcessParamsQuery = world.query({ with: [PostProcessParams] }).unwrap();
3492
4057
  for (const row of postProcessParamsQuery) {
@@ -3510,6 +4075,9 @@ function extractFrame(world, context) {
3510
4075
  ...volumetricFog === void 0 ? {} : { volumetricFog },
3511
4076
  renderables,
3512
4077
  dispatch,
4078
+ shadowCasterEntityKeys,
4079
+ shadowCasterDrawKeys,
4080
+ ...shadowCasterMembership.size === 0 ? {} : { shadowCasterMembership: [...shadowCasterMembership.values()] },
3513
4081
  skylight,
3514
4082
  skylightCount,
3515
4083
  lightProbes,
@@ -3519,19 +4087,21 @@ function extractFrame(world, context) {
3519
4087
  ...fogFailure === void 0 ? {} : { fogFailure },
3520
4088
  frustumStats: { culled: frustumCulled, total: frustumTotal },
3521
4089
  visibilityStats: { explicitlyHidden: explicitlyHidden.size },
4090
+ materialTextureSources: materialTextureSourceStats,
3522
4091
  postProcessParams,
3523
4092
  visibilitySnapshots: [context.visibility],
3524
4093
  featureVisibilitySnapshots: [{ world, snapshot: context.visibility }],
3525
4094
  hiddenEntityReports: [...explicitlyHidden].map((entity) => ({ world, entity }))
3526
4095
  };
3527
4096
  }
4097
+ var DEFAULT_MATERIAL_SNAPSHOT = Object.freeze({
4098
+ baseColor: vec3.create(0.5, 0.5, 0.5),
4099
+ metallic: 0,
4100
+ roughness: 1,
4101
+ materialHandle: 0
4102
+ });
3528
4103
  function defaultMaterialSnapshot(materialHandle = 0) {
3529
- return {
3530
- baseColor: vec3.create(0.5, 0.5, 0.5),
3531
- metallic: 0,
3532
- roughness: 1,
3533
- materialHandle
3534
- };
4104
+ return materialHandle === 0 ? DEFAULT_MATERIAL_SNAPSHOT : { ...DEFAULT_MATERIAL_SNAPSHOT, materialHandle };
3535
4105
  }
3536
4106
  function identityProjection() {
3537
4107
  const projection = new Float32Array(16);
@@ -3685,6 +4255,31 @@ function materialTextureFields(shaderId, fields) {
3685
4255
  }
3686
4256
  return fields;
3687
4257
  }
4258
+ function declaredMaterialTextureFields(shaderId, paramSchema, assets) {
4259
+ return materialTextureFields(
4260
+ shaderId,
4261
+ paramSchema !== void 0 ? derive(paramSchema).textureFieldNames : shaderId !== void 0 ? assets.materialShaderTextureFieldNames(shaderId) : void 0
4262
+ );
4263
+ }
4264
+ function collectAuthoredMaterialTextureFields(values, shaderId, paramSchema, assets) {
4265
+ const fields = declaredMaterialTextureFields(shaderId, paramSchema, assets);
4266
+ if (fields === void 0) return void 0;
4267
+ const authored = /* @__PURE__ */ new Set();
4268
+ for (const field of fields) {
4269
+ if (Object.hasOwn(values, field)) authored.add(field);
4270
+ }
4271
+ return authored.size === 0 ? void 0 : authored;
4272
+ }
4273
+ function collectAuthoredMaterialSamplerFields(values, textureFields) {
4274
+ const authored = /* @__PURE__ */ new Set();
4275
+ for (const field of textureFields ?? []) {
4276
+ if (materialTextureValue(values[field])?.sampler !== void 0) authored.add(field);
4277
+ }
4278
+ if (Object.hasOwn(values, "sampler") && values.sampler !== void 0) {
4279
+ authored.add("baseColorTexture");
4280
+ }
4281
+ return authored.size === 0 ? void 0 : authored;
4282
+ }
3688
4283
  function runtimeMaterialShaderId(module, passName) {
3689
4284
  if (passName === "shadow-caster" && (module === "forgeax_material::standard" || module === "forgeax_material::unlit" || module === "forgeax::default-standard-pbr" || module === "forgeax::default-unlit")) {
3690
4285
  return "forgeax::default-shadow-caster";
@@ -3763,6 +4358,42 @@ function pipelineRenderState(renderState) {
3763
4358
  ...frontFace !== void 0 && { frontFace }
3764
4359
  };
3765
4360
  }
4361
+ function shadowCasterCpuReason(material, draw, shadowEntries, morph, skin) {
4362
+ if (shadowEntries.length !== 1) return "multi-pass";
4363
+ if (material.transparent === true || material.renderState?.blend !== void 0) {
4364
+ return "transparent";
4365
+ }
4366
+ if (morph !== void 0) return "morph";
4367
+ const isStandardPbr = material.materialShaderId === "forgeax::default-standard-pbr" || material.materialShaderId === "forgeax::pbr-skin" || material.materialShaderId === "forgeax::default-standard-pbr-skin";
4368
+ if (!isStandardPbr) return "unsupported-shader";
4369
+ const shadowEntry = shadowEntries[0];
4370
+ if (shadowEntry !== void 0 && shadowEntry.materialShaderId !== void 0 && shadowEntry.materialShaderId !== "forgeax::default-shadow-caster") {
4371
+ return "unsupported-shader";
4372
+ }
4373
+ if (shadowEntry?.renderState !== void 0) return "unsupported-render-state";
4374
+ if (draw === void 0) return "missing-gpu-draw";
4375
+ if (draw.prepared === void 0) return "unprepared";
4376
+ const isSkinnedPbr = material.materialShaderId === "forgeax::pbr-skin" || material.materialShaderId === "forgeax::default-standard-pbr-skin";
4377
+ const preparedMaterial = draw.prepared.identity.material;
4378
+ const preparedDeformation = draw.prepared.identity.deformation;
4379
+ const materialContractMatches = material.materialShaderId === "forgeax::default-standard-pbr" && preparedMaterial === "forgeax::default-standard-pbr" || isSkinnedPbr && (preparedMaterial === "forgeax::pbr-skin" || preparedMaterial === "forgeax::default-standard-pbr-skin");
4380
+ const deformationContractMatches = skin === void 0 && preparedDeformation === "rigid" || skin !== void 0 && preparedDeformation === "skin";
4381
+ if (!materialContractMatches || !deformationContractMatches) return "prepared-contract";
4382
+ if (isSkinnedPbr && !hasFiniteOrderedSkinBounds(skin?.bounds)) {
4383
+ return "missing-skin-bounds";
4384
+ }
4385
+ return void 0;
4386
+ }
4387
+ function hasFiniteOrderedSkinBounds(bounds) {
4388
+ if (bounds === void 0 || bounds.length !== 6) return false;
4389
+ const minX = bounds[0];
4390
+ const minY = bounds[1];
4391
+ const minZ = bounds[2];
4392
+ const maxX = bounds[3];
4393
+ const maxY = bounds[4];
4394
+ const maxZ = bounds[5];
4395
+ return minX !== void 0 && minY !== void 0 && minZ !== void 0 && maxX !== void 0 && maxY !== void 0 && maxZ !== void 0 && Number.isFinite(minX) && Number.isFinite(minY) && Number.isFinite(minZ) && Number.isFinite(maxX) && Number.isFinite(maxY) && Number.isFinite(maxZ) && minX <= maxX && minY <= maxY && minZ <= maxZ;
4396
+ }
3766
4397
  var guidHandleInternByWorld = /* @__PURE__ */ new WeakMap();
3767
4398
  function internSharedRefFromGuid(world, assetsRef, guid, brand) {
3768
4399
  let perWorld = guidHandleInternByWorld.get(world);
@@ -3787,8 +4418,8 @@ function internSharedRefFromGuid(world, assetsRef, guid, brand) {
3787
4418
  return handle;
3788
4419
  }
3789
4420
  function resolveVideoFieldHandle(value, world, assetsRef) {
3790
- const texture = materialTextureValue(value);
3791
- const textureGuid = assetReferenceText(texture?.texture ?? value);
4421
+ const texture2 = materialTextureValue(value);
4422
+ const textureGuid = assetReferenceText(texture2?.texture ?? value);
3792
4423
  if (textureGuid === void 0) return void 0;
3793
4424
  const payload = assetsRef.lookup(textureGuid);
3794
4425
  if (payload === void 0 || payload.kind !== "video") return void 0;
@@ -3827,14 +4458,45 @@ function collectMaterialTextureCoordinates(values) {
3827
4458
  }
3828
4459
  return out;
3829
4460
  }
3830
- function collectMaterialTextureSources(values, world) {
4461
+ function materialTextureSourceFields(schema) {
4462
+ if (schema === void 0) return void 0;
4463
+ const fields = /* @__PURE__ */ new Set();
4464
+ for (const entry of schema) {
4465
+ if (entry.type.startsWith("texture")) fields.add(entry.name);
4466
+ }
4467
+ return fields;
4468
+ }
4469
+ function collectMaterialTextureSources(values, world, textureFields, stats, cache) {
3831
4470
  const out = /* @__PURE__ */ new Map();
3832
4471
  for (const [field, value] of Object.entries(values)) {
3833
- const reference = materialTextureRef(value);
4472
+ const structured = materialTextureValue(value);
4473
+ const schemaKnown = textureFields !== void 0;
4474
+ const schemaAdmitted = textureFields?.has(field) === true;
4475
+ if (schemaKnown && !schemaAdmitted) continue;
4476
+ const reference = structured?.texture ?? value;
4477
+ if (stats !== void 0) stats.sourceFieldsVisited += 1;
3834
4478
  if (typeof reference !== "number") continue;
3835
- const resolved = world.sharedRefs.resolve(toShared(reference));
3836
- if (!resolved.ok || resolveRenderTargetMaterialSource(resolved.value) === void 0) continue;
3837
- out.set(field, resolved.value);
4479
+ if (stats !== void 0) stats.numericSharedRefProbes += 1;
4480
+ let source;
4481
+ if (cache?.has(reference) === true) {
4482
+ if (stats !== void 0) stats.sourceCacheHits += 1;
4483
+ source = cache.get(reference) ?? void 0;
4484
+ } else {
4485
+ if (stats !== void 0) stats.sourceCacheMisses += 1;
4486
+ const resolved = world.sharedRefs.resolve(toShared(reference));
4487
+ if (!resolved.ok) {
4488
+ cache?.set(reference, null);
4489
+ } else {
4490
+ const binding = resolveRenderTargetMaterialSource(resolved.value);
4491
+ cache?.set(reference, binding === void 0 ? null : resolved.value);
4492
+ source = binding === void 0 ? void 0 : resolved.value;
4493
+ }
4494
+ }
4495
+ if (source === void 0) continue;
4496
+ if (stats !== void 0) {
4497
+ stats.producerRoutes.renderTarget = (stats.producerRoutes.renderTarget ?? 0) + 1;
4498
+ }
4499
+ out.set(field, source);
3838
4500
  }
3839
4501
  return out;
3840
4502
  }
@@ -3871,6 +4533,17 @@ var ENGINE_INJECTED_TEXTURE_FIELDS = /* @__PURE__ */ new Set(["emissiveTexture",
3871
4533
  function isEngineInjectedTextureField(shaderId, fieldName) {
3872
4534
  return isStandardPbrMaterialShader(shaderId) && ENGINE_INJECTED_TEXTURE_FIELDS.has(fieldName);
3873
4535
  }
4536
+ function materialStandardTextureMask(parameters, shaderId, values) {
4537
+ return isCanonicalStandardPbrMaterialShader(shaderId) ? standardTextureMask(
4538
+ // Canonical materials may provide values without redeclaring the root
4539
+ // schema. Pruning must agree with the texture binder in that route too.
4540
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA.filter(
4541
+ (entry) => entry.type === "texture2d" && (values[entry.name] !== void 0 || parameters?.some(
4542
+ (parameter) => parameter.name === entry.name && parameter.default !== void 0
4543
+ ))
4544
+ )
4545
+ ) : void 0;
4546
+ }
3874
4547
  function materialParametersToParamSchema(parameters, shaderId) {
3875
4548
  if (isCanonicalStandardPbrMaterialShader(shaderId)) return STANDARD_PIPELINE_PARAM_SCHEMA;
3876
4549
  return materialParametersToParamSchema$1(parameters);
@@ -3950,7 +4623,7 @@ function storeMaterialSnapshot(cache, handleRaw, snapshot, passes, root, assets)
3950
4623
  cache.set(handleRaw, entry);
3951
4624
  return entry;
3952
4625
  }
3953
- function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache, materialContext) {
4626
+ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCache, persistentMaterialSnapshotCache, materialContext, materialTextureSourceStats, materialTextureSourceCache) {
3954
4627
  if (handleRaw === 0) return defaultMaterialSnapshot(handleRaw);
3955
4628
  const cached = materialSnapshotCache?.get(handleRaw);
3956
4629
  if (cached !== void 0) return cached.snapshot;
@@ -4033,7 +4706,13 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
4033
4706
  pv,
4034
4707
  (value) => resolveTexLike(materialTextureRef(value), "SamplerAsset")
4035
4708
  );
4036
- const textureSources = collectMaterialTextureSources(pv, world);
4709
+ const textureSources = collectMaterialTextureSources(
4710
+ pv,
4711
+ world,
4712
+ materialTextureSourceFields(materialParamSchema.length > 0 ? materialParamSchema : void 0),
4713
+ materialTextureSourceStats,
4714
+ materialTextureSourceCache
4715
+ );
4037
4716
  const emissiveTextureHandle = resolveTexLike(
4038
4717
  materialTextureRef(pv.emissiveTexture),
4039
4718
  "TextureAsset"
@@ -4065,6 +4744,7 @@ function resolveMaterialSnapshot(handleRaw, world, assetsRef, materialSnapshotCa
4065
4744
  renderState: pipelineRenderState(allPasses[0]?.renderState),
4066
4745
  paramSnapshot: paramSnap,
4067
4746
  ...materialParamSchema.length > 0 && { materialParamSchema },
4747
+ standardTextureMask: materialStandardTextureMask(resolved.parameters, firstPassShader, pv),
4068
4748
  ...textureCoordinates.size > 0 && { textureCoordinates },
4069
4749
  ...textureHandles.size > 0 && { textureHandles },
4070
4750
  ...textureSources.size > 0 && { textureSources },
@@ -4156,43 +4836,11 @@ function pssmSplit(nearPlane, farPlane, cascadeCount, splitLambda) {
4156
4836
  }
4157
4837
  return result;
4158
4838
  }
4159
- var POINT_SHADOW_FACE_LOOK = [
4160
- vec3.create(1, 0, 0),
4161
- vec3.create(-1, 0, 0),
4162
- vec3.create(0, 1, 0),
4163
- vec3.create(0, -1, 0),
4164
- vec3.create(0, 0, 1),
4165
- vec3.create(0, 0, -1)
4166
- ];
4167
- var POINT_SHADOW_FACE_UP = [
4168
- vec3.create(0, -1, 0),
4169
- vec3.create(0, -1, 0),
4170
- vec3.create(0, 0, 1),
4171
- vec3.create(0, 0, -1),
4172
- vec3.create(0, -1, 0),
4173
- vec3.create(0, -1, 0)
4174
- ];
4175
4839
  function buildPointShadowMatrices(lightPos, near, far) {
4176
- const fovY = Math.PI / 2;
4177
- const aspect = 1;
4178
- const proj = mat4.create();
4179
- mat4.perspective(proj, fovY, aspect, near, far);
4180
- const out = [];
4181
- for (let i = 0; i < 6; i++) {
4182
- const look = POINT_SHADOW_FACE_LOOK[i];
4183
- const up = POINT_SHADOW_FACE_UP[i];
4184
- const target = vec3.create(
4185
- (lightPos[0] ?? 0) + (look[0] ?? 0),
4186
- (lightPos[1] ?? 0) + (look[1] ?? 0),
4187
- (lightPos[2] ?? 0) + (look[2] ?? 0)
4188
- );
4189
- const view = mat4.create();
4190
- mat4.lookAt(view, lightPos, target, up);
4191
- const vp = mat4.create();
4192
- mat4.multiply(vp, proj, view);
4193
- out.push(vp);
4194
- }
4195
- return out;
4840
+ return buildCubeCameraFaceViews({ position: lightPos, near, far }).map(({ viewProjection }) => {
4841
+ for (const offset of [0, 4, 8, 12]) viewProjection[offset] = -(viewProjection[offset] ?? 0);
4842
+ return viewProjection;
4843
+ });
4196
4844
  }
4197
4845
  function computeDirectionalCsm(direction, config, cameraData) {
4198
4846
  const cascadeCount = Math.round(config.cascadeCount);
@@ -4311,15 +4959,28 @@ var ALL_VISIBLE = {
4311
4959
  function collectCameraSnapshots(world) {
4312
4960
  const worldInternal = createWorldInternalView(world);
4313
4961
  const cameras = [];
4314
- const cameraQuery = world.query({ read: [Camera], optional: [MotionBlur], with: [Transform, GlobalTransform] }).unwrap();
4962
+ const cameraQuery = world.query({
4963
+ read: [Camera],
4964
+ optional: [MotionBlur, ScreenSpaceReflection],
4965
+ with: [Transform, GlobalTransform]
4966
+ }).unwrap();
4315
4967
  for (const row of cameraQuery) {
4316
4968
  const cam = row.get(Camera);
4317
4969
  const motionBlur = row.get(MotionBlur);
4970
+ const screenSpaceReflection = row.get(ScreenSpaceReflection);
4318
4971
  const entity = row.entity;
4319
4972
  const view = worldInternal._getArrayView(entity, GlobalTransform, "world");
4320
4973
  if (view === void 0) continue;
4321
4974
  const worldMat = new Float32Array(view);
4322
4975
  const target = resolveCameraTarget(world, cam.target);
4976
+ const hasNonDefaultOutput = cam.exposureMode !== CAMERA_EXPOSURE_MODE_MANUAL || cam.exposure !== 1 || cam.temperature !== 6504 || cam.tint !== 0 || cam.colorLut !== 0 || cam.colorLutStrength !== 0;
4977
+ const output = hasNonDefaultOutput ? {
4978
+ exposure: cameraExposureFromColumns(cam),
4979
+ temperature: cam.temperature,
4980
+ tint: cam.tint,
4981
+ colorLut: cam.colorLut,
4982
+ colorLutStrength: cam.colorLutStrength
4983
+ } : void 0;
4323
4984
  cameras.push({
4324
4985
  entityKey: entity,
4325
4986
  ...target === void 0 ? {} : { target },
@@ -4338,6 +4999,7 @@ function collectCameraSnapshots(world) {
4338
4999
  tonemap: tonemapFromF32(cam.tonemap),
4339
5000
  exposure: cam.exposure,
4340
5001
  whitePoint: cam.whitePoint,
5002
+ ...output === void 0 ? {} : { output },
4341
5003
  antialias: antialiasFromF32(cam.antialias),
4342
5004
  bloom: bloomEnabledFromF32(cam.bloom),
4343
5005
  bloomThreshold: cam.bloomThreshold,
@@ -4355,6 +5017,13 @@ function collectCameraSnapshots(world) {
4355
5017
  maxRadiusPixels: motionBlur.maxRadiusPixels,
4356
5018
  sampleCount: motionBlur.sampleCount
4357
5019
  }
5020
+ },
5021
+ ...screenSpaceReflection === void 0 ? {} : {
5022
+ screenSpaceReflection: {
5023
+ maxDistance: screenSpaceReflection.maxDistance,
5024
+ thickness: screenSpaceReflection.thickness,
5025
+ maxRoughness: screenSpaceReflection.maxRoughness
5026
+ }
4358
5027
  }
4359
5028
  });
4360
5029
  }
@@ -4412,14 +5081,15 @@ function collectReflectionProbeFacts(world) {
4412
5081
  }
4413
5082
  return facts;
4414
5083
  }
4415
- function selectCameraRoles(world) {
5084
+ function selectCameraRoles(world, requestedEntityKey) {
4416
5085
  const cameras = collectCameraSnapshots(world);
4417
5086
  const displayEntities = cameras.filter((camera) => camera.target === void 0).map((camera) => camera.entityKey ?? 0);
5087
+ const hasExplicitSelection = requestedEntityKey !== void 0;
4418
5088
  const activeCameraIndex = selectActiveCameraIndex(
4419
5089
  displayEntities,
4420
- getActiveCamera(world)?.entity
5090
+ hasExplicitSelection ? requestedEntityKey : getActiveCamera(world)?.entity
4421
5091
  );
4422
- const displayEntityKey = displayEntities[activeCameraIndex] ?? displayEntities[0];
5092
+ const displayEntityKey = hasExplicitSelection ? displayEntities[activeCameraIndex] : displayEntities[activeCameraIndex] ?? displayEntities[0];
4423
5093
  const display = displayEntityKey === void 0 ? [] : cameras.filter((camera) => camera.entityKey === displayEntityKey);
4424
5094
  const candidates = cameras.map((camera) => ({
4425
5095
  worldId: 0,
@@ -4456,7 +5126,9 @@ function prepareExtractContext(world, options = {}) {
4456
5126
  resourceOwnerFog: options.resourceOwnerFog,
4457
5127
  cull: options.cull ?? "self",
4458
5128
  cullCameras: options.cullCameras,
5129
+ ...options.cameraEntityKey === void 0 ? {} : { cameraEntityKey: options.cameraEntityKey },
4459
5130
  renderables,
5131
+ worldId: options.worldId ?? 0,
4460
5132
  renderableEntities: options.renderableEntities,
4461
5133
  retainHidden: options.retainHidden ?? false,
4462
5134
  visibility: renderables === "none" ? ALL_VISIBLE : resolveVisibility(world),
@@ -4514,9 +5186,9 @@ function selectFogFrame(world) {
4514
5186
  if (state.lkg !== void 0) return state.lkg;
4515
5187
  throw fogSelection.error;
4516
5188
  }
4517
- function textureDigest(texture) {
5189
+ function textureDigest(texture2) {
4518
5190
  let hash = 2166136261;
4519
- for (const byte of texture.data) hash = Math.imul(hash ^ byte, 16777619) >>> 0;
5191
+ for (const byte of texture2.data) hash = Math.imul(hash ^ byte, 16777619) >>> 0;
4520
5192
  return `fnv1a:${hash.toString(16).padStart(8, "0")}`;
4521
5193
  }
4522
5194
  function extractVolumeSnapshot(world, assets, worldInternal) {
@@ -5178,6 +5850,6 @@ var ProbeBlendSceneProjection = class {
5178
5850
  }
5179
5851
  };
5180
5852
 
5181
- export { InstanceBoundsCache, OcclusionRenderRuntime, PROBE_MAX_CONTRIBUTORS, ProbeBlendSceneProjection, SKYLIGHT_RECOVERY_FALLBACK, admitProbeContributors, blendLightProbes, buildRectAreaWorldFrame, createCookieProjectionMatrixData, createExtendedLightingState, extractFrames, fingerprintNumericArray, glyphTextLayoutSystem, primitiveKey, primitiveKeyId, projectExtendedLightingInspection, promoteExtendedLightingCandidate, recordExtendedLightingFailure, rectAreaFacesPoint, scaledProbeWeight, setOcclusionRuntimeTestHooks, viewKey, viewKeyId };
5182
- //# sourceMappingURL=chunk-XDP6XE5V.mjs.map
5183
- //# sourceMappingURL=chunk-XDP6XE5V.mjs.map
5853
+ export { InstanceBoundsCache, OcclusionRenderRuntime, PROBE_MAX_CONTRIBUTORS, ProbeBlendSceneProjection, SKYLIGHT_RECOVERY_FALLBACK, SSR_HISTORY_FORMAT, SsrHistoryOwner, admitProbeContributors, blendLightProbes, buildRectAreaWorldFrame, buildShadowFrusta, createCookieProjectionMatrixData, createExtendedLightingState, createSsrHistoryOwner, createSsrSpatialResources, estimateSsrSpatialMemory, extractFrames, fingerprintNumericArray, glyphTextLayoutSystem, primitiveKey, primitiveKeyId, projectExtendedLightingInspection, promoteExtendedLightingCandidate, recordExtendedLightingFailure, rectAreaFacesPoint, scaledProbeWeight, setOcclusionRuntimeTestHooks, viewKey, viewKeyId };
5854
+ //# sourceMappingURL=chunk-S4DNKQYQ.mjs.map
5855
+ //# sourceMappingURL=chunk-S4DNKQYQ.mjs.map