@forgeax/engine-render 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (768) hide show
  1. package/README.md +856 -126
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +27 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  9. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  10. package/dist/assembly/factory.d.ts +3 -1
  11. package/dist/assembly/factory.d.ts.map +1 -1
  12. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  13. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  14. package/dist/assembly/host-contract.d.ts +14 -0
  15. package/dist/assembly/host-contract.d.ts.map +1 -1
  16. package/dist/assembly/material/assembly.d.ts +31 -1
  17. package/dist/assembly/material/assembly.d.ts.map +1 -1
  18. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  19. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  20. package/dist/assembly/material-shader-policy.d.ts +3 -1
  21. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  22. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  23. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  24. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  25. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  26. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  27. package/dist/assembly/recovery/renderer-recover.d.ts +7 -4
  28. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  32. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-helpers.d.ts +3 -0
  35. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  36. package/dist/assembly/renderer-inspection.d.ts +4 -0
  37. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  38. package/dist/assembly/shader-prewarm-policy.d.ts +7 -1
  39. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  40. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  41. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  42. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  43. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  44. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  45. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  49. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  50. package/dist/assembly/webgpu-ready.d.ts +7 -3
  51. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  52. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  53. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  54. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  55. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  56. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  57. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  58. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  59. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  60. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  61. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  62. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  63. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  64. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  65. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  66. package/dist/authoring.mjs +2 -2
  67. package/dist/capture/scene-projection.d.ts +41 -0
  68. package/dist/capture/scene-projection.d.ts.map +1 -0
  69. package/dist/{chunk-J52NMQKR.mjs → chunk-7MQ3XBSP.mjs} +1098 -844
  70. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  71. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  72. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  73. package/dist/{chunk-VSL23LZE.mjs → chunk-C3DDSXYK.mjs} +1188 -463
  74. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  75. package/dist/{chunk-IQMKJLNU.mjs → chunk-FUUO4UND.mjs} +443 -30
  76. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  77. package/dist/{chunk-J6KACNOH.mjs → chunk-JRBDO2KB.mjs} +617 -7
  78. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  79. package/dist/{chunk-GE3SDD72.mjs → chunk-MDQJPY3T.mjs} +20 -40
  80. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  81. package/dist/{chunk-MYJ5RPJO.mjs → chunk-NO4WZCAH.mjs} +3 -3
  82. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  83. package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
  84. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  85. package/dist/{chunk-MBU4ZVE7.mjs → chunk-PSEQ6QPH.mjs} +4655 -892
  86. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  87. package/dist/{chunk-JAASCMXA.mjs → chunk-S5UE2T5P.mjs} +289 -41
  88. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  89. package/dist/components/camera.d.ts +62 -2
  90. package/dist/components/camera.d.ts.map +1 -1
  91. package/dist/components/directional-light.d.ts +2 -2
  92. package/dist/components/dynamic-resolution.d.ts +15 -0
  93. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  94. package/dist/components/index.d.ts +2 -0
  95. package/dist/components/index.d.ts.map +1 -1
  96. package/dist/components/instances.d.ts +6 -20
  97. package/dist/components/instances.d.ts.map +1 -1
  98. package/dist/components/light-helpers.d.ts.map +1 -1
  99. package/dist/components/reflection-probe.d.ts +1 -0
  100. package/dist/components/reflection-probe.d.ts.map +1 -1
  101. package/dist/components/scene-instance.d.ts +2 -1
  102. package/dist/components/scene-instance.d.ts.map +1 -1
  103. package/dist/components/screen-space-reflection.d.ts +14 -0
  104. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  105. package/dist/components/skylight.d.ts +4 -1
  106. package/dist/components/skylight.d.ts.map +1 -1
  107. package/dist/construct-renderer.mjs +14809 -7570
  108. package/dist/construct-renderer.mjs.map +1 -1
  109. package/dist/device/device-scope.d.ts +2 -0
  110. package/dist/device/device-scope.d.ts.map +1 -1
  111. package/dist/device/gpu-residency.d.ts +3 -14
  112. package/dist/device/gpu-residency.d.ts.map +1 -1
  113. package/dist/dynamic-geometry.d.ts.map +1 -1
  114. package/dist/environment/background.d.ts +7 -0
  115. package/dist/environment/background.d.ts.map +1 -0
  116. package/dist/environment/ibl.d.ts +11 -0
  117. package/dist/environment/ibl.d.ts.map +1 -0
  118. package/dist/environment/storage.d.ts +14 -0
  119. package/dist/environment/storage.d.ts.map +1 -0
  120. package/dist/errors/gpu-driven.d.ts +6 -3
  121. package/dist/errors/gpu-driven.d.ts.map +1 -1
  122. package/dist/errors/render.d.ts +41 -4
  123. package/dist/errors/render.d.ts.map +1 -1
  124. package/dist/extract/camera.d.ts.map +1 -1
  125. package/dist/extract/contracts.d.ts +7 -0
  126. package/dist/extract/contracts.d.ts.map +1 -1
  127. package/dist/extract/gpu-driven.d.ts +50 -3
  128. package/dist/extract/gpu-driven.d.ts.map +1 -1
  129. package/dist/features/host.d.ts +23 -1
  130. package/dist/features/host.d.ts.map +1 -1
  131. package/dist/features/noise-texture.d.ts +17 -0
  132. package/dist/features/noise-texture.d.ts.map +1 -0
  133. package/dist/features/plan.d.ts +83 -2
  134. package/dist/features/plan.d.ts.map +1 -1
  135. package/dist/features/prepared-gpu-work.d.ts +37 -4
  136. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  137. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  138. package/dist/features/prepared-graphics.d.ts +5 -0
  139. package/dist/features/prepared-graphics.d.ts.map +1 -1
  140. package/dist/features/render-graph-compute.d.ts +5 -3
  141. package/dist/features/render-graph-compute.d.ts.map +1 -1
  142. package/dist/features/render-graph-contribution.d.ts +11 -3
  143. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  144. package/dist/features/render-graph-raster.d.ts +19 -3
  145. package/dist/features/render-graph-raster.d.ts.map +1 -1
  146. package/dist/features/types.d.ts +11 -0
  147. package/dist/features/types.d.ts.map +1 -1
  148. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  149. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  150. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  151. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  152. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  153. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  154. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  155. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  156. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  157. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  158. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  159. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  160. package/dist/gpu-driven/production-raster.d.ts +169 -27
  161. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  162. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  163. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  164. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  165. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  166. package/dist/gpu-resource.d.ts +5 -2
  167. package/dist/gpu-resource.d.ts.map +1 -1
  168. package/dist/gpu-scene-schema.d.ts +2 -8
  169. package/dist/gpu-scene-schema.d.ts.map +1 -1
  170. package/dist/gpu-scene.d.ts +14 -0
  171. package/dist/gpu-scene.d.ts.map +1 -1
  172. package/dist/gpu-texture-usage.d.ts +1 -0
  173. package/dist/gpu-texture-usage.d.ts.map +1 -1
  174. package/dist/hdrp-buffers.d.ts +9 -0
  175. package/dist/hdrp-buffers.d.ts.map +1 -1
  176. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  177. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  178. package/dist/ibl/frame-resources.d.ts +8 -0
  179. package/dist/ibl/frame-resources.d.ts.map +1 -0
  180. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  181. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  182. package/dist/index.d.ts +87 -75
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.mjs +10 -8
  185. package/dist/index.mjs.map +1 -1
  186. package/dist/inspection-types.d.ts +180 -1
  187. package/dist/inspection-types.d.ts.map +1 -1
  188. package/dist/instances-derived-bounds.d.ts +11 -0
  189. package/dist/instances-derived-bounds.d.ts.map +1 -1
  190. package/dist/instances.d.ts +89 -44
  191. package/dist/instances.d.ts.map +1 -1
  192. package/dist/internal.d.ts +3 -0
  193. package/dist/internal.d.ts.map +1 -1
  194. package/dist/internal.mjs +117 -9
  195. package/dist/internal.mjs.map +1 -1
  196. package/dist/lifecycle.d.ts +2 -1
  197. package/dist/lifecycle.d.ts.map +1 -1
  198. package/dist/material-row.d.ts +15 -0
  199. package/dist/material-row.d.ts.map +1 -0
  200. package/dist/materials.d.ts +15 -0
  201. package/dist/materials.d.ts.map +1 -1
  202. package/dist/pbr-pipeline.d.ts +23 -5
  203. package/dist/pbr-pipeline.d.ts.map +1 -1
  204. package/dist/pipeline/render-extent.d.ts +51 -0
  205. package/dist/pipeline/render-extent.d.ts.map +1 -0
  206. package/dist/pipeline/standard-build-context.d.ts +7 -0
  207. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  208. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  209. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  210. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  211. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  212. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  213. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  214. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  215. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  216. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  217. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  218. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  219. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  220. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  221. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  222. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  223. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  224. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  225. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  226. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  227. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  228. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  229. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  230. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  231. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  232. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  233. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  234. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  235. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  236. package/dist/pipeline/standard-output/types.d.ts +39 -0
  237. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  238. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  239. package/dist/pipeline/standard-post.d.ts +2 -2
  240. package/dist/pipeline/standard-post.d.ts.map +1 -1
  241. package/dist/pipeline/standard-profile.d.ts +2 -1
  242. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  243. package/dist/pipeline-builder.d.ts +5 -2
  244. package/dist/pipeline-builder.d.ts.map +1 -1
  245. package/dist/pipeline-spec-types.d.ts +4 -0
  246. package/dist/pipeline-spec-types.d.ts.map +1 -1
  247. package/dist/pipeline-spec.d.ts +1 -9
  248. package/dist/pipeline-spec.d.ts.map +1 -1
  249. package/dist/plugin.d.ts.map +1 -1
  250. package/dist/points-lines/standard-owner.d.ts +1 -1
  251. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  252. package/dist/post-process-errors.d.ts +9 -2
  253. package/dist/post-process-errors.d.ts.map +1 -1
  254. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  255. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  256. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  257. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  258. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  259. package/dist/record/frame-lighting.d.ts +3 -3
  260. package/dist/record/frame-lighting.d.ts.map +1 -1
  261. package/dist/record/frame-snapshot.d.ts +109 -13
  262. package/dist/record/frame-snapshot.d.ts.map +1 -1
  263. package/dist/record/frame-targets.d.ts.map +1 -1
  264. package/dist/record/frame.d.ts +41 -5
  265. package/dist/record/frame.d.ts.map +1 -1
  266. package/dist/record/main-pass-geometry.d.ts +13 -9
  267. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  268. package/dist/record/main-pass-material.d.ts +43 -3
  269. package/dist/record/main-pass-material.d.ts.map +1 -1
  270. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  271. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  272. package/dist/record/main-pass.d.ts +14 -2
  273. package/dist/record/main-pass.d.ts.map +1 -1
  274. package/dist/record/mesh-ssbo.d.ts +15 -6
  275. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  276. package/dist/record/prepared-material-bindings.d.ts +19 -0
  277. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  278. package/dist/record/recovery-pipeline.d.ts +1 -0
  279. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  280. package/dist/record/render-context.d.ts +101 -22
  281. package/dist/record/render-context.d.ts.map +1 -1
  282. package/dist/record/shadow-pass.d.ts +62 -7
  283. package/dist/record/shadow-pass.d.ts.map +1 -1
  284. package/dist/record/skybox-post-pass.d.ts +1 -1
  285. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  286. package/dist/record/typed-frame-graph.d.ts +39 -8
  287. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  288. package/dist/record/view-ubo.d.ts +1 -0
  289. package/dist/record/view-ubo.d.ts.map +1 -1
  290. package/dist/recovery/render-system-candidate.d.ts +10 -2
  291. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  292. package/dist/recovery/render-system-roots.d.ts +11 -0
  293. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  294. package/dist/recovery/types.d.ts +76 -0
  295. package/dist/recovery/types.d.ts.map +1 -0
  296. package/dist/reflection/background.d.ts +14 -0
  297. package/dist/reflection/background.d.ts.map +1 -0
  298. package/dist/reflection/filter.d.ts.map +1 -1
  299. package/dist/reflection/projection.d.ts +1 -0
  300. package/dist/reflection/projection.d.ts.map +1 -1
  301. package/dist/reflection/record-owner.d.ts +4 -4
  302. package/dist/reflection/record-owner.d.ts.map +1 -1
  303. package/dist/render-contract.d.ts +211 -53
  304. package/dist/render-contract.d.ts.map +1 -1
  305. package/dist/render-graph-primitives.d.ts +1 -0
  306. package/dist/render-graph-primitives.d.ts.map +1 -1
  307. package/dist/render-pipeline.d.ts +81 -6
  308. package/dist/render-pipeline.d.ts.map +1 -1
  309. package/dist/render-system-extract-tail.d.ts +15 -6
  310. package/dist/render-system-extract-tail.d.ts.map +1 -1
  311. package/dist/render-system-extract.d.ts +128 -41
  312. package/dist/render-system-extract.d.ts.map +1 -1
  313. package/dist/render-system-projections.d.ts +22 -0
  314. package/dist/render-system-projections.d.ts.map +1 -0
  315. package/dist/render-system.d.ts +27 -77
  316. package/dist/render-system.d.ts.map +1 -1
  317. package/dist/scene/render-scene-types.d.ts +14 -7
  318. package/dist/scene/render-scene-types.d.ts.map +1 -1
  319. package/dist/scene/render-scene.d.ts +31 -11
  320. package/dist/scene/render-scene.d.ts.map +1 -1
  321. package/dist/scene/shadow-visibility.d.ts +5 -0
  322. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  323. package/dist/ssao-config.d.ts +8 -6
  324. package/dist/ssao-config.d.ts.map +1 -1
  325. package/dist/ssr/admission.d.ts +70 -1
  326. package/dist/ssr/admission.d.ts.map +1 -1
  327. package/dist/ssr/compose.d.ts +13 -0
  328. package/dist/ssr/compose.d.ts.map +1 -0
  329. package/dist/ssr/errors.d.ts +35 -0
  330. package/dist/ssr/errors.d.ts.map +1 -1
  331. package/dist/ssr/graph.d.ts +60 -0
  332. package/dist/ssr/graph.d.ts.map +1 -0
  333. package/dist/ssr/history.d.ts +97 -0
  334. package/dist/ssr/history.d.ts.map +1 -0
  335. package/dist/ssr/hiz.d.ts +37 -0
  336. package/dist/ssr/hiz.d.ts.map +1 -0
  337. package/dist/ssr/inspection.d.ts +42 -0
  338. package/dist/ssr/inspection.d.ts.map +1 -0
  339. package/dist/ssr/resources.d.ts +58 -0
  340. package/dist/ssr/resources.d.ts.map +1 -0
  341. package/dist/ssr/temporal.d.ts +38 -0
  342. package/dist/ssr/temporal.d.ts.map +1 -0
  343. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  344. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  345. package/dist/systems/skin-palette-types.d.ts +15 -0
  346. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  347. package/dist/systems/transparent-dispatch.d.ts +9 -0
  348. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  349. package/dist/targets/material-source.d.ts +7 -0
  350. package/dist/targets/material-source.d.ts.map +1 -1
  351. package/dist/temporal/frame-coordinator.d.ts +7 -0
  352. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  353. package/dist/temporal/gpu.d.ts +8 -0
  354. package/dist/temporal/gpu.d.ts.map +1 -1
  355. package/dist/temporal/history.d.ts.map +1 -1
  356. package/dist/temporal/index.mjs +6 -6
  357. package/dist/temporal/inspection.d.ts.map +1 -1
  358. package/dist/temporal/standard-scene-data.d.ts +4 -2
  359. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  360. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  361. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  362. package/dist/temporal/temporal-view.d.ts +6 -0
  363. package/dist/temporal/temporal-view.d.ts.map +1 -1
  364. package/dist/temporal/view.d.ts +6 -0
  365. package/dist/temporal/view.d.ts.map +1 -1
  366. package/dist/typed-render-graph-primitives.d.ts +41 -1
  367. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  368. package/dist/typed-shadow-passes.d.ts +3 -1
  369. package/dist/typed-shadow-passes.d.ts.map +1 -1
  370. package/dist/volume/component.d.ts +1 -0
  371. package/dist/volume/component.d.ts.map +1 -1
  372. package/dist/volume/temporal.d.ts +6 -0
  373. package/dist/volume/temporal.d.ts.map +1 -1
  374. package/package.json +21 -20
  375. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  376. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  377. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  378. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  379. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  380. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  381. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  382. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  383. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  384. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  385. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  386. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  387. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  388. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  389. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  390. package/src/__tests__/factory-contract.integration.test.ts +231 -9
  391. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  392. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  393. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  394. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  395. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  396. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  397. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  398. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  399. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  400. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  401. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +307 -7
  402. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  403. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  404. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +261 -0
  405. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +346 -0
  406. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1422 -0
  407. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  408. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  409. package/src/__tests__/gpu-driven-production.integration.test.ts +1076 -106
  410. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  411. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  412. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  413. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  414. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  415. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  416. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  417. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  418. package/src/__tests__/gpu-driven-view.unit.test.ts +160 -52
  419. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  420. package/src/__tests__/gpu-pass-timing.browser.test.ts +20 -2
  421. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  422. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  423. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  424. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  425. package/src/__tests__/gpu-scene.unit.test.ts +613 -33
  426. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  427. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  428. package/src/__tests__/instances-store.unit.test.ts +242 -39
  429. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  430. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  431. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  432. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  433. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  434. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  435. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  436. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  437. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  438. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  439. package/src/__tests__/materials-standard-contract.unit.test.ts +57 -3
  440. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  441. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  442. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  443. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  444. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  445. package/src/__tests__/physical-clearcoat.integration.test.ts +42 -3
  446. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  447. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  448. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  449. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  450. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  451. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +251 -9
  452. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  453. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  454. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  455. package/src/__tests__/public-surface.test-d.ts +3 -0
  456. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  457. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +171 -0
  458. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  459. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  460. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  461. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  462. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -14
  463. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  464. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  465. package/src/__tests__/render-error-detail-ssot.test-d.ts +27 -1
  466. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  467. package/src/__tests__/render-extent.unit.test.ts +63 -0
  468. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  469. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  470. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  471. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  472. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  473. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  474. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  475. package/src/__tests__/render-scene-projection.unit.test.ts +915 -23
  476. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  477. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  478. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  479. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  480. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +233 -9
  481. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  482. package/src/__tests__/shader-manifest-fixture.ts +45 -0
  483. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  484. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  485. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  486. package/src/__tests__/skinned-shadow-caster.test.ts +125 -14
  487. package/src/__tests__/specular-environment-scale.dawn.test.ts +158 -0
  488. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  489. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  490. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  491. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  492. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  493. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  494. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  495. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +99 -0
  496. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +116 -0
  497. package/src/__tests__/ssr-gpu-dispatch.ts +951 -0
  498. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  499. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  500. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  501. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  502. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  503. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  504. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  505. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  506. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  507. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  508. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  509. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  510. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  511. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  512. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  513. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  514. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  515. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  516. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  517. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  518. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  519. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  520. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +84 -12
  521. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  522. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  523. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  524. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  525. package/src/__tests__/standard-output.browser.test.ts +15 -0
  526. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  527. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +275 -0
  528. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  529. package/src/__tests__/standard-profile-oracle.unit.test.ts +49 -0
  530. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  531. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  532. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  533. package/src/__tests__/taa-coverage-edge.dawn.test.ts +199 -0
  534. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  535. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +782 -0
  536. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  537. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  538. package/src/__tests__/taa-stability-feedback.ts +342 -0
  539. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  540. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  541. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  542. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  543. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  544. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  545. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  546. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  547. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  548. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  549. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  550. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  551. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  552. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  553. package/src/assembly/atmosphere-shader-prewarm.ts +39 -0
  554. package/src/assembly/device-feature-admission.ts +9 -4
  555. package/src/assembly/dynamic-geometry-host.ts +284 -163
  556. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  557. package/src/assembly/factory.ts +4 -0
  558. package/src/assembly/gpu-driven-owner.ts +29 -0
  559. package/src/assembly/host-contract.ts +19 -0
  560. package/src/assembly/material/assembly.ts +383 -1
  561. package/src/assembly/material/pipeline-helpers.ts +100 -0
  562. package/src/assembly/material-shader-policy.ts +110 -46
  563. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  564. package/src/assembly/recovery/failure-location.ts +62 -0
  565. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  566. package/src/assembly/recovery/renderer-recover.ts +16 -17
  567. package/src/assembly/renderer-facade.ts +34 -1
  568. package/src/assembly/renderer-feature-inspection.ts +13 -0
  569. package/src/assembly/renderer-frame-transaction.ts +63 -0
  570. package/src/assembly/renderer-helpers.ts +26 -0
  571. package/src/assembly/renderer-inspection.ts +6 -0
  572. package/src/assembly/shader-prewarm-policy.ts +46 -1
  573. package/src/assembly/skin-palette-owner.ts +21 -0
  574. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  575. package/src/assembly/webgpu-device-loss.ts +75 -0
  576. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  577. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  578. package/src/assembly/webgpu-ready.ts +161 -131
  579. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  580. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  581. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  582. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  583. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  584. package/src/assembly/webgpu-renderer.ts +744 -730
  585. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  586. package/src/capture/scene-projection.ts +37 -0
  587. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  588. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  589. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  590. package/src/components/camera.ts +287 -7
  591. package/src/components/directional-light.ts +3 -3
  592. package/src/components/dynamic-resolution.ts +67 -0
  593. package/src/components/index.ts +2 -0
  594. package/src/components/instances.ts +45 -18
  595. package/src/components/light-helpers.ts +6 -1
  596. package/src/components/reflection-probe.ts +1 -0
  597. package/src/components/scene-instance.ts +2 -1
  598. package/src/components/screen-space-reflection.ts +21 -0
  599. package/src/components/skylight.ts +4 -1
  600. package/src/components/sprite-animation.ts +2 -2
  601. package/src/components/sprite-instances.ts +1 -1
  602. package/src/device/device-scope.ts +13 -7
  603. package/src/device/gpu-residency.ts +45 -42
  604. package/src/dynamic-geometry.ts +13 -8
  605. package/src/environment/background.ts +281 -0
  606. package/src/environment/ibl.ts +211 -0
  607. package/src/environment/storage.ts +63 -0
  608. package/src/errors/gpu-driven.ts +49 -8
  609. package/src/errors/render.ts +91 -3
  610. package/src/extract/camera.ts +37 -1
  611. package/src/extract/contracts.ts +10 -0
  612. package/src/extract/gpu-driven.ts +240 -10
  613. package/src/features/host.ts +237 -19
  614. package/src/features/noise-texture.ts +91 -0
  615. package/src/features/plan.ts +553 -24
  616. package/src/features/prepared-gpu-work.ts +631 -49
  617. package/src/features/prepared-graphics-store.ts +31 -0
  618. package/src/features/prepared-graphics.ts +5 -0
  619. package/src/features/render-graph-compute.ts +41 -8
  620. package/src/features/render-graph-contribution.ts +141 -3
  621. package/src/features/render-graph-raster.ts +143 -30
  622. package/src/features/types.ts +11 -0
  623. package/src/fullscreen-post-process-pass.ts +3 -0
  624. package/src/gpu-driven/batch-topology.ts +452 -108
  625. package/src/gpu-driven/material-artifacts.ts +179 -0
  626. package/src/gpu-driven/material-bindings.ts +41 -0
  627. package/src/gpu-driven/pbr-program.ts +31 -0
  628. package/src/gpu-driven/prepared-draw.ts +42 -6
  629. package/src/gpu-driven/production-raster.ts +2806 -716
  630. package/src/gpu-driven/shadow-views.ts +539 -0
  631. package/src/gpu-driven/view-gpu.ts +188 -41
  632. package/src/gpu-resource.ts +21 -2
  633. package/src/gpu-scene-schema.ts +61 -11
  634. package/src/gpu-scene.ts +197 -99
  635. package/src/gpu-texture-usage.ts +1 -0
  636. package/src/hdrp-buffers.ts +141 -36
  637. package/src/ibl/IblPipelineCache.ts +5 -0
  638. package/src/ibl/frame-resources.ts +38 -0
  639. package/src/ibl/skylight-bind-group.ts +32 -21
  640. package/src/index.ts +194 -75
  641. package/src/inspection-types.ts +207 -1
  642. package/src/instances-derived-bounds.ts +258 -34
  643. package/src/instances.ts +459 -150
  644. package/src/internal.ts +22 -0
  645. package/src/lifecycle.ts +2 -0
  646. package/src/material-row.ts +194 -0
  647. package/src/materials.ts +44 -8
  648. package/src/pbr-pipeline.ts +172 -19
  649. package/src/pipeline/render-extent.ts +111 -0
  650. package/src/pipeline/standard-build-context.ts +7 -0
  651. package/src/pipeline/standard-forward-lane.ts +74 -29
  652. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  653. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  654. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  655. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  656. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  657. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  658. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  659. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  660. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  661. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  662. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  663. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  664. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  665. package/src/pipeline/standard-output/color-transform.ts +124 -0
  666. package/src/pipeline/standard-output/graph.ts +139 -0
  667. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  668. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  669. package/src/pipeline/standard-output/lut-state.ts +176 -0
  670. package/src/pipeline/standard-output/resources.ts +121 -0
  671. package/src/pipeline/standard-output/types.ts +58 -0
  672. package/src/pipeline/standard-pipeline.ts +232 -70
  673. package/src/pipeline/standard-post.ts +190 -27
  674. package/src/pipeline/standard-profile.ts +2 -1
  675. package/src/pipeline-builder.ts +28 -9
  676. package/src/pipeline-spec-types.ts +4 -0
  677. package/src/pipeline-spec.ts +37 -29
  678. package/src/plugin.ts +4 -0
  679. package/src/points-lines/standard-owner.ts +6 -14
  680. package/src/post-process-errors.ts +26 -18
  681. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  682. package/src/prepare/extended-lighting/resources.ts +3 -3
  683. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  684. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  685. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  686. package/src/record/__tests__/material-slot-plan.unit.test.ts +57 -0
  687. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  688. package/src/record/__tests__/recovery-pipeline.unit.test.ts +20 -1
  689. package/src/record/__tests__/sprite-material-abi.unit.test.ts +41 -6
  690. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  691. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  692. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  693. package/src/record/dynamic-geometry-consumption.ts +59 -0
  694. package/src/record/frame-lighting.ts +15 -12
  695. package/src/record/frame-snapshot.ts +146 -34
  696. package/src/record/frame-targets.ts +9 -0
  697. package/src/record/frame.ts +838 -170
  698. package/src/record/main-pass-geometry.ts +209 -103
  699. package/src/record/main-pass-material.ts +157 -40
  700. package/src/record/main-pass-sprite-draws.ts +16 -107
  701. package/src/record/main-pass.ts +141 -12
  702. package/src/record/material-uniforms.ts +1 -1
  703. package/src/record/mesh-ssbo.ts +59 -15
  704. package/src/record/prepared-material-bindings.ts +238 -0
  705. package/src/record/recovery-pipeline.ts +69 -90
  706. package/src/record/render-context.ts +123 -24
  707. package/src/record/shadow-pass.ts +1389 -230
  708. package/src/record/skybox-post-pass.ts +14 -3
  709. package/src/record/typed-frame-graph.ts +1064 -47
  710. package/src/record/view-ubo.ts +12 -1
  711. package/src/recovery/render-system-candidate.ts +135 -68
  712. package/src/recovery/render-system-roots.ts +113 -0
  713. package/src/recovery/types.ts +77 -0
  714. package/src/reflection/background.ts +151 -0
  715. package/src/reflection/filter.ts +3 -0
  716. package/src/reflection/projection.ts +16 -6
  717. package/src/reflection/record-owner.ts +308 -140
  718. package/src/render-contract.ts +237 -49
  719. package/src/render-graph-primitives.ts +34 -5
  720. package/src/render-pipeline.ts +90 -2
  721. package/src/render-system-extract-tail.ts +431 -162
  722. package/src/render-system-extract.ts +478 -119
  723. package/src/render-system-projections.ts +241 -0
  724. package/src/render-system.ts +715 -828
  725. package/src/scene/render-scene-types.ts +13 -4
  726. package/src/scene/render-scene.ts +577 -355
  727. package/src/scene/shadow-visibility.ts +21 -0
  728. package/src/ssao-config.ts +25 -8
  729. package/src/ssr/admission.ts +380 -14
  730. package/src/ssr/compose.ts +144 -0
  731. package/src/ssr/errors.ts +48 -0
  732. package/src/ssr/graph.ts +797 -0
  733. package/src/ssr/history.ts +436 -0
  734. package/src/ssr/hiz.ts +124 -0
  735. package/src/ssr/inspection.ts +124 -0
  736. package/src/ssr/resources.ts +202 -0
  737. package/src/ssr/temporal.ts +164 -0
  738. package/src/systems/skin-palette-allocator.ts +495 -148
  739. package/src/systems/skin-palette-types.ts +17 -0
  740. package/src/systems/transparent-dispatch.ts +90 -0
  741. package/src/targets/material-source.ts +34 -0
  742. package/src/temporal/coverage.ts +1 -1
  743. package/src/temporal/frame-coordinator.ts +23 -2
  744. package/src/temporal/gpu.ts +79 -12
  745. package/src/temporal/history.ts +3 -1
  746. package/src/temporal/inspection.ts +2 -1
  747. package/src/temporal/standard-scene-data.ts +10 -2
  748. package/src/temporal/target-coverage-attachment.ts +72 -0
  749. package/src/temporal/temporal-view.ts +11 -2
  750. package/src/temporal/view.ts +12 -2
  751. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +219 -139
  752. package/src/typed-render-graph-primitives.ts +304 -74
  753. package/src/typed-shadow-passes.ts +122 -12
  754. package/src/volume/component.ts +1 -0
  755. package/src/volume/passes.ts +3 -3
  756. package/src/volume/temporal.ts +10 -0
  757. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  758. package/dist/chunk-GF523LHF.mjs.map +0 -1
  759. package/dist/chunk-IQMKJLNU.mjs.map +0 -1
  760. package/dist/chunk-J52NMQKR.mjs.map +0 -1
  761. package/dist/chunk-J6KACNOH.mjs.map +0 -1
  762. package/dist/chunk-JAASCMXA.mjs.map +0 -1
  763. package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
  764. package/dist/chunk-MYJ5RPJO.mjs.map +0 -1
  765. package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
  766. package/dist/chunk-VSL23LZE.mjs.map +0 -1
  767. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  768. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -1,622 +1,617 @@
1
- import { CUBE_CAMERA_FACE_ORDER, createVisibilityBudget, PointShapeValue, pointShapeFromU32 } from './chunk-JAASCMXA.mjs';
2
- import { PointsLinesBudgetExceededError, PointsLinesStyleUnsupportedError, PointsLinesMaterialUnsupportedError, PointsLinesInvalidStyleError, PointsLinesTopologyMismatchError } from './chunk-J6KACNOH.mjs';
3
- import { ok, err } from '@forgeax/engine-types';
4
- import { mat4 } from '@forgeax/engine-math';
1
+ import { PointShapeValue, pointShapeFromU32 } from './chunk-S5UE2T5P.mjs';
2
+ import { PointsLinesBudgetExceededError, createVisibilityBudget, PointsLinesStyleUnsupportedError, PointsLinesMaterialUnsupportedError, PointsLinesInvalidStyleError, PointsLinesTopologyMismatchError } from './chunk-JRBDO2KB.mjs';
3
+ import { err, ok } from '@forgeax/engine-types';
5
4
  import { validateR32FloatReceipt } from '@forgeax/engine-rhi';
6
5
 
7
- var DynamicGeometryError = class extends Error {
8
- code;
9
- expected;
10
- hint;
11
- detail;
12
- constructor(code, expected, hint, detail = {}) {
13
- super(`${code}: ${expected}`);
14
- this.name = "DynamicGeometryError";
15
- this.code = code;
16
- this.expected = expected;
17
- this.hint = hint;
18
- this.detail = Object.freeze({ code, ...detail });
6
+ function invalidStyle(input, component, field, value, expected) {
7
+ return err(new PointsLinesInvalidStyleError({ entity: input.entity, component, field, value, expected }));
8
+ }
9
+ function topologyMismatch(input, submesh, expected, actual) {
10
+ return err(new PointsLinesTopologyMismatchError({ entity: input.entity, submesh, expected, actual }));
11
+ }
12
+ function checkStyle(input) {
13
+ const hasPoints = input.points !== void 0;
14
+ const hasLines = input.lines !== void 0;
15
+ if (hasPoints && hasLines) {
16
+ return invalidStyle(
17
+ input,
18
+ "Points/Lines",
19
+ "components",
20
+ "Points + Lines",
21
+ "exactly one style component"
22
+ );
19
23
  }
20
- };
21
- function sameCandidateCredential(candidate, committed) {
22
- return candidate.candidateId === committed.candidateId && candidate.owner === committed.owner && candidate.world === committed.world && candidate.generation === committed.generation && candidate.entity === committed.entity && candidate.physicsEntity === committed.physicsEntity && candidate.gpuReady === committed.gpuReady && candidate.meshBytes === committed.meshBytes && candidate.revision === committed.revision && candidate.topologyRevision === committed.topologyRevision && candidate.materialIdentity === committed.materialIdentity && candidate.meshHandle === committed.meshHandle && candidate.fixedStep === committed.fixedStep;
24
+ if (!hasPoints && !hasLines) {
25
+ return invalidStyle(input, "Points/Lines", "components", void 0, "one style component");
26
+ }
27
+ if (hasPoints) {
28
+ const sizePx = input.points?.sizePx ?? 4;
29
+ const shapeValue = input.points?.shape ?? PointShapeValue.square;
30
+ const shape = pointShapeFromU32(shapeValue);
31
+ if (!Number.isFinite(sizePx) || sizePx <= 0) {
32
+ return invalidStyle(input, "Points", "sizePx", sizePx, "finite sizePx > 0");
33
+ }
34
+ if (shape === void 0) {
35
+ return invalidStyle(input, "Points", "shape", shapeValue, "shape is 'square' or 'circle'");
36
+ }
37
+ return ok({ component: "Points", shape, sizePx });
38
+ }
39
+ const widthPx = input.lines?.widthPx ?? 1;
40
+ if (!Number.isFinite(widthPx) || widthPx <= 0) {
41
+ return invalidStyle(input, "Lines", "widthPx", widthPx, "finite widthPx > 0");
42
+ }
43
+ return ok({ component: "Lines", widthPx });
23
44
  }
24
- function cloneTypedArray(value) {
25
- return new value.constructor(value);
45
+ function checkTopology(input, component) {
46
+ const expected = component === "Points" ? "point-list" : "line-list";
47
+ let pointCount = 0;
48
+ let segmentCount = 0;
49
+ const acceptedSubmeshes = [];
50
+ let sawNonEmpty = false;
51
+ for (const [submeshIndex, submesh] of input.mesh.submeshes.entries()) {
52
+ const indexed = input.mesh.indices !== void 0 && submesh.indexCount > 0;
53
+ const elementCount = indexed ? submesh.indexCount : submesh.vertexCount;
54
+ if (elementCount === 0) continue;
55
+ sawNonEmpty = true;
56
+ if (component === "Lines" && submesh.topology === "line-strip") {
57
+ return err(
58
+ new PointsLinesStyleUnsupportedError({
59
+ lane: "admission",
60
+ field: "topology",
61
+ member: "line-strip",
62
+ supported: ["line-list"]
63
+ })
64
+ );
65
+ }
66
+ if (submesh.topology !== expected) {
67
+ return topologyMismatch(input, submeshIndex, expected, submesh.topology);
68
+ }
69
+ if (component === "Lines" && elementCount % 2 !== 0) {
70
+ return topologyMismatch(input, submeshIndex, "line-list pairs", "line-list odd tail");
71
+ }
72
+ acceptedSubmeshes.push(submeshIndex);
73
+ if (component === "Points") pointCount += elementCount;
74
+ else segmentCount += elementCount / 2;
75
+ }
76
+ if (!sawNonEmpty) return topologyMismatch(input, 0, expected, "empty-range");
77
+ return ok({ pointCount, segmentCount, submeshes: acceptedSubmeshes });
26
78
  }
27
- function cloneMesh(mesh) {
28
- const attributes = Object.fromEntries(
29
- Object.entries(mesh.attributes).map(([key, value]) => [
30
- key,
31
- value instanceof ArrayBuffer ? value.slice(0) : value === void 0 ? void 0 : cloneTypedArray(value)
32
- ])
79
+ function checkMaterial(input) {
80
+ const passes = input.material.passes ?? [];
81
+ const unlitModules = /* @__PURE__ */ new Set(["forgeax_material::unlit", "forgeax::default-unlit"]);
82
+ if (passes.length !== 1 || passes[0] === void 0) {
83
+ const pass2 = passes.find(
84
+ (candidate) => candidate.name === "deferred" || candidate.name === "shadow-caster"
85
+ ) ?? passes[0];
86
+ return err(
87
+ new PointsLinesMaterialUnsupportedError({
88
+ entity: input.entity,
89
+ material: input.materialId ?? "<anonymous>",
90
+ pass: pass2?.name ?? "<empty>",
91
+ module: pass2?.program.module ?? "<empty>",
92
+ reason: "points-lines admission requires one unlit forward pass"
93
+ })
94
+ );
95
+ }
96
+ const pass = passes[0];
97
+ const lightMode = pass.renderState?.tags?.LightMode;
98
+ if (!unlitModules.has(pass.program.module) || pass.name !== "forward" || lightMode === "ShadowCaster") {
99
+ return err(
100
+ new PointsLinesMaterialUnsupportedError({
101
+ entity: input.entity,
102
+ material: input.materialId ?? "<anonymous>",
103
+ pass: pass.name,
104
+ module: pass.program.module,
105
+ reason: "points-lines admission requires an engine-owned unlit forward pass"
106
+ })
107
+ );
108
+ }
109
+ return ok(void 0);
110
+ }
111
+ function admitPointsLines(input) {
112
+ const style = checkStyle(input);
113
+ if (!style.ok) return style;
114
+ const topology = checkTopology(input, style.value.component);
115
+ if (!topology.ok) return topology;
116
+ const material = checkMaterial(input);
117
+ if (!material.ok) return material;
118
+ if (style.value.component === "Points" && input.limits?.maxPoints !== void 0) {
119
+ if (topology.value.pointCount > input.limits.maxPoints) {
120
+ return err(
121
+ new PointsLinesBudgetExceededError({
122
+ lane: "admission",
123
+ requested: topology.value.pointCount,
124
+ limit: input.limits.maxPoints,
125
+ unit: "points"
126
+ })
127
+ );
128
+ }
129
+ }
130
+ if (style.value.component === "Lines" && input.limits?.maxSegments !== void 0) {
131
+ if (topology.value.segmentCount > input.limits.maxSegments) {
132
+ return err(
133
+ new PointsLinesBudgetExceededError({
134
+ lane: "admission",
135
+ requested: topology.value.segmentCount,
136
+ limit: input.limits.maxSegments,
137
+ unit: "segments"
138
+ })
139
+ );
140
+ }
141
+ }
142
+ return ok({ ...style.value, ...topology.value });
143
+ }
144
+
145
+ // src/point-shadow-inspection.ts
146
+ function inspectPointShadow(snapshots, shadowAtlasCapacity) {
147
+ const requested = snapshots.length;
148
+ const admitted = snapshots.reduce(
149
+ (count, snapshot) => snapshot.shadowAtlasLayer >= 0 && snapshot.shadowAtlasLayer < shadowAtlasCapacity ? count + 1 : count,
150
+ 0
33
151
  );
152
+ const status = requested === 0 ? "inactive" : requested > shadowAtlasCapacity || admitted !== requested ? "over-budget" : "ready";
34
153
  return Object.freeze({
35
- ...mesh,
36
- vertices: new Float32Array(mesh.vertices),
37
- ...mesh.indices === void 0 ? {} : { indices: cloneTypedArray(mesh.indices) },
38
- attributes,
39
- ...mesh.aabb === void 0 ? {} : { aabb: new Float32Array(mesh.aabb) },
40
- submeshes: Object.freeze(mesh.submeshes.map((submesh) => Object.freeze({ ...submesh }))),
41
- materialSlots: Object.freeze(mesh.materialSlots.map((slot) => Object.freeze({ ...slot })))
154
+ status,
155
+ requested,
156
+ admitted,
157
+ // A point shadow only samples an atlas after it owns an atlas layer. Keep
158
+ // these names explicit for AI diagnostics while deriving both from the
159
+ // one layer projection above.
160
+ shadowed: admitted,
161
+ shadowAtlasOccupancy: admitted,
162
+ shadowAtlasCapacity
42
163
  });
43
164
  }
44
- function cloneCandidate(candidate) {
45
- return Object.freeze({ ...candidate, mesh: cloneMesh(candidate.mesh) });
46
- }
47
- function validateMesh(mesh) {
48
- if (mesh.kind !== "mesh") return "MeshAsset.kind must be mesh";
49
- if (!(mesh.vertices instanceof Float32Array) || mesh.vertices.length === 0 || mesh.vertices.length % 3 !== 0) {
50
- return "MeshAsset.vertices must be a non-empty Float32Array with xyz triples";
51
- }
52
- if (mesh.indices !== void 0 && !(mesh.indices instanceof Uint16Array || mesh.indices instanceof Uint32Array)) {
53
- return "MeshAsset.indices must be Uint16Array or Uint32Array";
54
- }
55
- if (mesh.submeshes.length === 0)
56
- return "MeshAsset.submeshes must contain at least one topology range";
57
- if (mesh.materialSlots.length < mesh.submeshes.length) {
58
- return "MeshAsset.materialSlots must cover every submesh";
165
+ var SSR_FORMAT_PROFILE = "r32float-mip-sampled-storage";
166
+ var SSR_FORMAT_STAGES = Object.freeze([
167
+ "texture-create",
168
+ "mip-view",
169
+ "sampled-storage-bind-group",
170
+ "pipeline-bind",
171
+ "finish",
172
+ "submit",
173
+ "completion",
174
+ "readback"
175
+ ]);
176
+ var ZERO_WORK = Object.freeze({
177
+ attachmentCount: 0,
178
+ passCount: 0,
179
+ bindingCount: 0,
180
+ resourceCount: 0,
181
+ historyCount: 0,
182
+ temporalDemand: 0
183
+ });
184
+ var ADMITTED_WORK = Object.freeze({
185
+ attachmentCount: 1,
186
+ passCount: 1,
187
+ bindingCount: 1,
188
+ resourceCount: 1,
189
+ historyCount: 0,
190
+ temporalDemand: 0
191
+ });
192
+ var ZERO_BUDGET = Object.freeze({
193
+ probeExecutions: 0,
194
+ resetCount: 0,
195
+ rebuildCount: 0
196
+ });
197
+ var ADMITTED_BUDGET = Object.freeze({
198
+ probeExecutions: 1,
199
+ resetCount: 0,
200
+ rebuildCount: 0
201
+ });
202
+ function identityFieldMismatch(expected, actual) {
203
+ for (const field of ["sourceHead", "sourceTree", "lockSha256", "buildSha256"]) {
204
+ if (expected[field] !== actual[field]) return field;
59
205
  }
60
- if (mesh.vertices.some((value) => !Number.isFinite(value)))
61
- return "MeshAsset.vertices must be finite";
62
206
  return void 0;
63
207
  }
64
- function meshByteSize(mesh) {
65
- let bytes = mesh.vertices.byteLength + (mesh.indices?.byteLength ?? 0);
66
- for (const value of Object.values(mesh.attributes)) {
67
- if (value instanceof ArrayBuffer) bytes += value.byteLength;
68
- else if (value !== void 0 && ArrayBuffer.isView(value)) bytes += value.byteLength;
69
- }
70
- if (mesh.aabb !== void 0) bytes += mesh.aabb.byteLength;
71
- return bytes;
208
+ function blocked(identity, failure2, generation = 0) {
209
+ return Object.freeze({
210
+ status: "fallback-only",
211
+ identity,
212
+ generation,
213
+ work: ZERO_WORK,
214
+ budget: ZERO_BUDGET,
215
+ failure: failure2
216
+ });
72
217
  }
73
- function createDynamicGeometryLifecycle(maxCandidates = 32, maxMeshBytes = 64 * 1024 * 1024) {
74
- const records = /* @__PURE__ */ new Map();
75
- const owner = {};
76
- let sequence = 0;
77
- let currentGeneration = 0;
78
- let disposed = false;
79
- let historyInvalidations = 0;
80
- let latestRevision;
81
- let latestFrameId;
82
- let retired = 0;
83
- let invalidated = 0;
84
- let meshBytes = 0;
85
- const latestRevisionByWorld = /* @__PURE__ */ new WeakMap();
86
- const latestTopologyRevisionByWorld = /* @__PURE__ */ new WeakMap();
87
- const publishedReceipts = /* @__PURE__ */ new Map();
88
- const failure2 = (code, expected, hint, detail = {}) => err(new DynamicGeometryError(code, expected, hint, detail));
89
- const current = (candidate) => {
90
- const record = records.get(candidate.candidateId);
91
- if (record === void 0 || candidate.owner !== owner || record.candidate.owner !== candidate.owner || record.candidate.world !== candidate.world || record.candidate.generation !== candidate.generation)
92
- return void 0;
93
- return record;
94
- };
95
- return {
96
- prepare(input, generation) {
97
- if (disposed)
98
- return failure2("dynamic-geometry-disposed", "renderer is alive", "rebuild the Renderer");
99
- if (input.world === null || typeof input.world !== "object") {
100
- return failure2(
101
- "dynamic-geometry-world-not-attached",
102
- "candidate belongs to an attached World",
103
- "attach the World before preparing geometry"
104
- );
105
- }
106
- if (!Number.isInteger(input.revision) || input.revision < 0) {
107
- return failure2(
108
- "dynamic-geometry-invalid",
109
- "geometry revision is a non-negative integer",
110
- "advance the consumer revision monotonically",
111
- { revision: input.revision }
112
- );
113
- }
114
- if (generation !== currentGeneration && currentGeneration !== 0) {
115
- return failure2(
116
- "dynamic-geometry-generation-mismatch",
117
- "candidate uses the active renderer generation",
118
- "discard stale generation work and prepare again",
119
- { generation, actual: currentGeneration }
120
- );
121
- }
122
- if (records.size >= maxCandidates) {
123
- return failure2(
124
- "dynamic-geometry-budget-exceeded",
125
- "candidate count remains within the bounded renderer budget",
126
- "cancel or retire an earlier candidate before retrying",
127
- { actual: records.size }
128
- );
129
- }
130
- const invalid = validateMesh(input.mesh);
131
- if (invalid !== void 0)
132
- return failure2(
133
- "dynamic-geometry-invalid",
134
- "MeshAsset satisfies the standard geometry contract",
135
- invalid
136
- );
137
- const candidateBytes = meshByteSize(input.mesh);
138
- if (!Number.isSafeInteger(candidateBytes) || candidateBytes < 0 || meshBytes > maxMeshBytes - candidateBytes) {
139
- return failure2(
140
- "dynamic-geometry-budget-exceeded",
141
- "candidate mesh bytes remain within the bounded renderer resource budget",
142
- "cancel or retire an earlier candidate before retrying",
143
- { actual: { meshBytes, candidateBytes, maxMeshBytes } }
144
- );
145
- }
146
- const candidateId = `mesh:${generation}:${++sequence}:${input.revision}`;
147
- const candidate = Object.freeze({
148
- candidateId,
149
- generation,
150
- owner,
151
- world: input.world,
152
- ...input.entity === void 0 ? {} : { entity: input.entity },
153
- ...input.physicsEntity === void 0 ? {} : { physicsEntity: input.physicsEntity },
154
- gpuReady: input.meshHandle !== void 0,
155
- meshBytes: candidateBytes,
156
- revision: input.revision,
157
- topologyRevision: input.topologyRevision ?? input.revision,
158
- ...input.materialIdentity === void 0 ? {} : { materialIdentity: input.materialIdentity },
159
- ...input.meshHandle === void 0 ? {} : { meshHandle: input.meshHandle },
160
- ...input.fixedStep === void 0 ? {} : { fixedStep: input.fixedStep },
161
- mesh: cloneMesh(input.mesh),
162
- state: "prepared"
163
- });
164
- records.set(candidateId, {
165
- world: input.world,
166
- candidate,
167
- historyInvalidated: false
168
- });
169
- meshBytes += candidateBytes;
170
- currentGeneration = generation;
171
- return ok(cloneCandidate(candidate));
172
- },
173
- accept(candidate, ordering) {
174
- if (disposed)
175
- return failure2("dynamic-geometry-disposed", "renderer is alive", "rebuild the Renderer");
176
- const record = current(candidate);
177
- if (record === void 0)
178
- return failure2(
179
- "dynamic-geometry-candidate-not-found",
180
- "candidate is owned by this renderer",
181
- "discard the stale credential"
182
- );
183
- if (candidate.generation !== currentGeneration) {
184
- return failure2(
185
- "dynamic-geometry-generation-mismatch",
186
- "candidate generation matches the active renderer generation",
187
- "prepare against the current renderer generation",
188
- { candidateId: candidate.candidateId }
189
- );
190
- }
191
- if (record.candidate.state !== "prepared") {
192
- return failure2(
193
- "dynamic-geometry-candidate-state",
194
- "candidate is prepared exactly once before acceptance",
195
- "retain the accepted or published receipt",
196
- { candidateId: candidate.candidateId }
197
- );
198
- }
199
- if (!sameCandidateCredential(candidate, record.candidate)) {
200
- return failure2(
201
- "dynamic-geometry-receipt-mismatch",
202
- "acceptance uses the exact prepared candidate credential",
203
- "discard the altered credential and use the value returned by prepare",
204
- { candidateId: candidate.candidateId }
205
- );
206
- }
207
- if (ordering !== void 0) {
208
- if (ordering.world !== record.world || !Number.isInteger(ordering.fixedStep) || ordering.fixedStep < 0) {
209
- return failure2(
210
- "dynamic-geometry-ordering-required",
211
- "acceptance ordering names the candidate World and a non-negative fixed step",
212
- "submit the PhysicsWorld publication ordering for the same attached World",
213
- { candidateId: candidate.candidateId, actual: ordering }
214
- );
215
- }
216
- }
217
- const newest = [...records.values()].filter(
218
- (entry) => entry.candidate.candidateId !== candidate.candidateId && entry.world === record.world && entry.candidate.entity === record.candidate.entity && (entry.candidate.state === "prepared" || entry.candidate.state === "accepted")
219
- ).map((entry) => entry.candidate.revision).concat(latestRevisionByWorld.get(record.world)?.get(record.candidate.entity) ?? -1).sort((a, b) => b - a)[0];
220
- if (newest !== void 0 && record.candidate.revision <= newest) {
221
- return failure2(
222
- "dynamic-geometry-stale",
223
- "accepted geometry revision is newer than the active candidate",
224
- "advance topology revision before accepting",
225
- { candidateId: candidate.candidateId }
226
- );
227
- }
228
- const accepted = Object.freeze({
229
- ...record.candidate,
230
- ...ordering === void 0 ? {} : { fixedStep: ordering.fixedStep },
231
- state: "accepted"
232
- });
233
- const previousTopologies = [...records.values()].filter(
234
- (entry) => entry.candidate.candidateId !== candidate.candidateId && entry.world === record.world && entry.candidate.entity === record.candidate.entity
235
- ).map((entry) => entry.candidate.topologyRevision);
236
- const previousLatestTopology = latestTopologyRevisionByWorld.get(record.world)?.get(record.candidate.entity);
237
- const newestTopology = previousTopologies.concat(previousLatestTopology === void 0 ? [] : [previousLatestTopology]).sort((a, b) => b - a)[0];
238
- if (newestTopology !== void 0 && accepted.topologyRevision < newestTopology) {
239
- return failure2(
240
- "dynamic-geometry-stale",
241
- "accepted topology revision is not older than the active geometry history",
242
- "advance topology revision before accepting a replacement candidate",
243
- { candidateId: candidate.candidateId }
244
- );
245
- }
246
- if (newestTopology !== void 0 && accepted.topologyRevision > newestTopology) {
247
- historyInvalidations += 1;
248
- for (const previous of records.values()) {
249
- if (previous.world !== record.world || previous.candidate.entity !== record.candidate.entity || previous.candidate.candidateId === candidate.candidateId || previous.candidate.topologyRevision >= accepted.topologyRevision)
250
- continue;
251
- if (!previous.historyInvalidated) {
252
- previous.historyInvalidated = true;
253
- invalidated += 1;
254
- }
255
- }
256
- }
257
- record.candidate = accepted;
258
- return ok(cloneCandidate(accepted));
259
- },
260
- cancel(candidate, completion) {
261
- const record = current(candidate);
262
- if (record === void 0)
263
- return failure2(
264
- "dynamic-geometry-candidate-not-found",
265
- "candidate is owned by this renderer",
266
- "discard the stale credential"
267
- );
268
- if (!sameCandidateCredential(candidate, record.candidate))
269
- return failure2(
270
- "dynamic-geometry-receipt-mismatch",
271
- "cancellation uses the exact prepared candidate credential",
272
- "discard the altered credential and use the value returned by prepare",
273
- { candidateId: candidate.candidateId }
274
- );
275
- if (record.candidate.state !== "prepared" && record.candidate.state !== "accepted") {
276
- return failure2(
277
- "dynamic-geometry-candidate-state",
278
- "only prepared or accepted geometry can be cancelled once",
279
- "retire published geometry or await the existing terminal cleanup"
280
- );
281
- }
282
- record.candidate = Object.freeze({ ...record.candidate, state: "cancelled" });
283
- const release = () => {
284
- if (records.get(candidate.candidateId) !== record) return;
285
- records.delete(candidate.candidateId);
286
- meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
287
- };
288
- if (completion === void 0) release();
289
- else void completion.then(release, release);
290
- return ok(void 0);
291
- },
292
- retire(candidate) {
293
- const record = current(candidate);
294
- if (record === void 0)
295
- return failure2(
296
- "dynamic-geometry-candidate-not-found",
297
- "retirement uses a published candidate owned by this renderer",
298
- "discard the stale credential and do not evict any unrelated mesh",
299
- { candidateId: candidate.candidateId }
300
- );
301
- if (!sameCandidateCredential(candidate, record.candidate))
302
- return failure2(
303
- "dynamic-geometry-receipt-mismatch",
304
- "retirement uses the exact published candidate credential",
305
- "discard the altered credential and use the value returned by publish",
306
- { candidateId: candidate.candidateId }
307
- );
308
- if (record.candidate.state !== "published") {
309
- return failure2(
310
- "dynamic-geometry-candidate-state",
311
- "only published geometry can enter receipt-bound retirement",
312
- "publish the candidate from a submitted frame first"
313
- );
314
- }
315
- record.candidate = Object.freeze({ ...record.candidate, state: "retired" });
316
- publishedReceipts.delete(candidate.candidateId);
317
- retired += 1;
318
- return ok(void 0);
319
- },
320
- finalizeRetirement(candidate) {
321
- const record = current(candidate);
322
- if (record === void 0)
323
- return failure2(
324
- "dynamic-geometry-candidate-not-found",
325
- "retirement finalization uses a candidate retained by this lifecycle",
326
- "discard the stale credential or finish the current receipt-bound retirement"
327
- );
328
- if (!sameCandidateCredential(candidate, record.candidate))
329
- return failure2(
330
- "dynamic-geometry-receipt-mismatch",
331
- "retirement finalization uses the exact published candidate credential",
332
- "discard the altered credential and use the value returned by publication",
333
- { candidateId: candidate.candidateId }
334
- );
335
- if (record.candidate.state !== "retired")
336
- return failure2(
337
- "dynamic-geometry-candidate-state",
338
- "only a retired candidate can release its deferred budget",
339
- "retire the published candidate before finalizing its receipt-bound cleanup",
340
- { candidateId: candidate.candidateId }
341
- );
342
- records.delete(candidate.candidateId);
343
- meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
344
- return ok(void 0);
345
- },
346
- publishFrame(frame, worlds, fixedStep, canPublish) {
347
- if (disposed || frame.deviceGeneration !== currentGeneration) return [];
348
- const receipts = [];
349
- for (const record of records.values()) {
350
- const canRepeatPublished = record.candidate.state === "published" && // Attached Renderer publication revalidates the entity binding in
351
- // `canPublish`, so a history-invalidated candidate can still record
352
- // a real draw for its live entity. Detached lifecycle publication
353
- // remains one-shot once that history is invalidated.
354
- (canPublish !== void 0 || !record.historyInvalidated);
355
- if (record.candidate.state !== "accepted" && !canRepeatPublished) continue;
356
- if (worlds !== void 0 && !worlds.includes(record.world)) continue;
357
- if (record.candidate.fixedStep !== void 0 && (fixedStep === void 0 || record.candidate.fixedStep > fixedStep)) {
358
- continue;
359
- }
360
- if (canPublish !== void 0 && !canPublish(record.candidate)) continue;
361
- record.candidate = Object.freeze({ ...record.candidate, state: "published" });
362
- const receipt = Object.freeze({
363
- candidateId: record.candidate.candidateId,
364
- generation: record.candidate.generation,
365
- revision: record.candidate.revision,
366
- topologyRevision: record.candidate.topologyRevision,
367
- ...record.candidate.fixedStep === void 0 ? {} : { fixedStep: record.candidate.fixedStep },
368
- frameId: frame.frameId,
369
- deviceGeneration: frame.deviceGeneration,
370
- recordStageConsumed: canPublish !== void 0,
371
- ...fixedStep === void 0 ? {} : { publicationFixedStep: fixedStep },
372
- frame: Object.freeze({ ...frame })
373
- });
374
- receipts.push(receipt);
375
- publishedReceipts.set(record.candidate.candidateId, receipt);
376
- latestRevision = record.candidate.revision;
377
- latestFrameId = frame.frameId;
378
- if (!latestRevisionByWorld.has(record.world))
379
- latestRevisionByWorld.set(record.world, /* @__PURE__ */ new Map());
380
- latestRevisionByWorld.get(record.world)?.set(record.candidate.entity, record.candidate.revision);
381
- if (!latestTopologyRevisionByWorld.has(record.world))
382
- latestTopologyRevisionByWorld.set(record.world, /* @__PURE__ */ new Map());
383
- latestTopologyRevisionByWorld.get(record.world)?.set(record.candidate.entity, record.candidate.topologyRevision);
384
- }
385
- return receipts;
386
- },
387
- invalidateWorld(world, completion) {
388
- for (const [id, record] of records) {
389
- if (record.world !== world) continue;
390
- if (record.candidate.state === "cancelled" || record.candidate.state === "retired")
391
- continue;
392
- publishedReceipts.delete(id);
393
- record.candidate = Object.freeze({ ...record.candidate, state: "cancelled" });
394
- const release = () => {
395
- if (records.get(id) !== record) return;
396
- records.delete(id);
397
- meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
398
- };
399
- if (completion === void 0) release();
400
- else void completion.then(release, release);
401
- invalidated += 1;
402
- }
403
- latestRevisionByWorld.delete(world);
404
- latestTopologyRevisionByWorld.delete(world);
405
- },
406
- invalidateGeneration(generation) {
407
- if (generation === currentGeneration) return;
408
- currentGeneration = generation;
409
- const invalidatedWorlds = /* @__PURE__ */ new Set();
410
- for (const [id, record] of records) {
411
- if (record.candidate.generation !== generation) {
412
- records.delete(id);
413
- publishedReceipts.delete(id);
414
- meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
415
- invalidatedWorlds.add(record.world);
416
- invalidated += 1;
218
+ function failure(code, owner, hint, detail = {}) {
219
+ const action = recoveryActionFor(code);
220
+ return Object.freeze({
221
+ code,
222
+ expected: "all producer, format, and temporal receipts share one admitted identity",
223
+ hint,
224
+ detail: Object.freeze({ owner, action, ...detail })
225
+ });
226
+ }
227
+ function recoveryActionFor(code) {
228
+ switch (code) {
229
+ case "ssr-reflection-fallback-unavailable":
230
+ case "ssr-receipt-identity-mismatch":
231
+ return "rebuild";
232
+ case "ssr-not-requested":
233
+ case "ssr-format-unavailable":
234
+ case "ssr-temporal-unavailable":
235
+ case "ssr-receipt-stale":
236
+ return "retry";
237
+ }
238
+ }
239
+ function receiptFailure(input, receipt, owner) {
240
+ const field = identityFieldMismatch(input.identity, receipt.identity);
241
+ if (field === void 0) return void 0;
242
+ return blocked(
243
+ input.identity,
244
+ failure("ssr-receipt-identity-mismatch", owner, "rebuild the owner receipt for this identity", {
245
+ identityField: field
246
+ })
247
+ );
248
+ }
249
+ function validFallback(receipt) {
250
+ return receipt !== void 0 && receipt.candidateVisible === false && Number.isFinite(receipt.coverage) && receipt.coverage >= 0 && receipt.coverage <= 1 && (receipt.sourceKey === void 0 || receipt.sourceKey.length > 0) && (receipt.extent === void 0 || receipt.extent.length === 3 && receipt.extent.every((value) => Number.isFinite(value) && value > 0)) && Number.isInteger(receipt.sourceGeneration) && receipt.sourceGeneration >= 0 && Number.isInteger(receipt.projectionGeneration) && receipt.projectionGeneration >= 0 && Number.isInteger(receipt.deviceGeneration) && receipt.deviceGeneration >= 0 && receipt.brdfSignature === "standard-pbr-ibl-v1" && (receipt.source === "probe" && (receipt.state === "active" || receipt.state === "lkg") || receipt.source === "skylight" && (receipt.state === "active" || receipt.state === "lkg") || receipt.source === "neutral" && receipt.state === "neutral");
251
+ }
252
+ function validFormat(receipt) {
253
+ if (receipt?.profile !== SSR_FORMAT_PROFILE || receipt.verdict !== "admitted" || receipt.evidence !== "real" || !Number.isInteger(receipt.deviceGeneration) || receipt.deviceGeneration < 0) {
254
+ return false;
255
+ }
256
+ if (!SSR_FORMAT_STAGES.every(
257
+ (stage) => receipt.stages.some((entry) => entry.stage === stage && entry.verdict === "admitted")
258
+ )) {
259
+ return false;
260
+ }
261
+ return validateR32FloatReceipt(receipt).ok;
262
+ }
263
+ function validTemporal(receipt) {
264
+ return receipt?.successfulSubmit === true && Number.isInteger(receipt.generation) && receipt.generation >= 0;
265
+ }
266
+ function admitSsrM0(input) {
267
+ if (!input.requested) {
268
+ return blocked(
269
+ input.identity,
270
+ failure("ssr-not-requested", "consumer", "request SSR before evaluating M0 admission")
271
+ );
272
+ }
273
+ if (input.reflectionFallback === void 0) {
274
+ return blocked(
275
+ input.identity,
276
+ failure("ssr-reflection-fallback-unavailable", "producer", "use LKG, Skylight, or neutral")
277
+ );
278
+ }
279
+ const fallbackIdentityFailure = receiptFailure(input, input.reflectionFallback, "producer");
280
+ if (fallbackIdentityFailure !== void 0) return fallbackIdentityFailure;
281
+ if (!validFallback(input.reflectionFallback)) {
282
+ return blocked(
283
+ input.identity,
284
+ failure(
285
+ "ssr-reflection-fallback-unavailable",
286
+ "producer",
287
+ "inspect and rebuild the producer receipt"
288
+ ),
289
+ input.reflectionFallback.projectionGeneration
290
+ );
291
+ }
292
+ if (input.format === void 0) {
293
+ return blocked(
294
+ input.identity,
295
+ failure("ssr-format-unavailable", "format", "probe the exact format profile for this device"),
296
+ input.reflectionFallback.projectionGeneration
297
+ );
298
+ }
299
+ const formatIdentityFailure = receiptFailure(input, input.format, "format");
300
+ if (formatIdentityFailure !== void 0) return formatIdentityFailure;
301
+ if (!validFormat(input.format)) {
302
+ return blocked(
303
+ input.identity,
304
+ failure("ssr-format-unavailable", "format", "complete the full r32float profile probe"),
305
+ input.reflectionFallback.projectionGeneration
306
+ );
307
+ }
308
+ const temporalIdentityFailure = input.temporal === void 0 ? void 0 : receiptFailure(input, input.temporal, "temporal");
309
+ if (temporalIdentityFailure !== void 0) return temporalIdentityFailure;
310
+ if (input.temporal !== void 0 && !validTemporal(input.temporal)) {
311
+ return blocked(
312
+ input.identity,
313
+ failure("ssr-temporal-unavailable", "temporal", "inspect and rebuild the temporal receipt"),
314
+ input.reflectionFallback.projectionGeneration
315
+ );
316
+ }
317
+ if (input.previousGeneration !== void 0 && input.previousGeneration !== input.reflectionFallback.projectionGeneration) {
318
+ return blocked(
319
+ input.identity,
320
+ failure(
321
+ "ssr-receipt-stale",
322
+ "consumer",
323
+ "discard stale completion and reinspect the owners",
324
+ {
325
+ generation: input.reflectionFallback.projectionGeneration
417
326
  }
418
- }
419
- for (const world of invalidatedWorlds) {
420
- latestRevisionByWorld.delete(world);
421
- latestTopologyRevisionByWorld.delete(world);
422
- }
423
- },
424
- receipt(candidate) {
425
- const receipt = publishedReceipts.get(candidate.candidateId);
426
- const record = records.get(candidate.candidateId);
427
- if (record === void 0 || !sameCandidateCredential(candidate, record.candidate)) {
428
- return void 0;
429
- }
430
- return receipt?.generation === candidate.generation ? receipt : void 0;
431
- },
432
- inspect() {
433
- let prepared = 0;
434
- let accepted = 0;
435
- let published = 0;
436
- for (const record of records.values()) {
437
- if (record.candidate.state === "prepared") prepared += 1;
438
- else if (record.candidate.state === "accepted") accepted += 1;
439
- else if (record.candidate.state === "published") published += 1;
440
- }
441
- return Object.freeze({
442
- generation: currentGeneration,
443
- prepared,
444
- accepted,
445
- published,
446
- retired,
447
- ...latestRevision === void 0 ? {} : { latestRevision },
448
- ...latestFrameId === void 0 ? {} : { latestFrameId },
449
- historyInvalidations,
450
- invalidated,
451
- meshBytes,
452
- maxMeshBytes
453
- });
454
- },
455
- dispose() {
456
- disposed = true;
457
- records.clear();
458
- publishedReceipts.clear();
459
- meshBytes = 0;
460
- }
327
+ ),
328
+ input.reflectionFallback.projectionGeneration
329
+ );
330
+ }
331
+ return Object.freeze({
332
+ status: "admitted",
333
+ identity: input.identity,
334
+ generation: input.reflectionFallback.projectionGeneration,
335
+ work: ADMITTED_WORK,
336
+ budget: ADMITTED_BUDGET
337
+ });
338
+ }
339
+ function projectSsrDependencies(input) {
340
+ const identity = input.identity;
341
+ const reflectionFallback = identity === void 0 || input.reflectionFallback?.identity === void 0 ? void 0 : input.reflectionFallback;
342
+ const format = identity === void 0 || input.format === void 0 ? void 0 : { ...input.format, identity };
343
+ const temporal = identity === void 0 || input.temporal === void 0 ? void 0 : { identity, ...input.temporal };
344
+ const admission = identity === void 0 ? blocked(
345
+ void 0,
346
+ failure(
347
+ input.requested ? "ssr-receipt-identity-mismatch" : "ssr-not-requested",
348
+ "consumer",
349
+ input.requested ? "bind the exact source, tree, lock, and build identity before admission" : "request SSR before evaluating M0 admission",
350
+ input.requested ? { identityField: "sourceHead" } : {}
351
+ )
352
+ ) : admitSsrM0({
353
+ requested: input.requested,
354
+ identity,
355
+ ...reflectionFallback === void 0 ? {} : { reflectionFallback },
356
+ ...format === void 0 ? {} : { format },
357
+ ...temporal === void 0 ? {} : { temporal },
358
+ ...input.previousGeneration === void 0 ? {} : { previousGeneration: input.previousGeneration }
359
+ });
360
+ return Object.freeze({
361
+ status: admission.status,
362
+ identity,
363
+ requested: input.requested,
364
+ reflectionFallback: input.reflectionFallback,
365
+ format,
366
+ temporal,
367
+ admission,
368
+ work: admission.work,
369
+ budget: admission.budget,
370
+ failure: admission.failure
371
+ });
372
+ }
373
+ function zeroSsrAdmissionWork() {
374
+ return ZERO_WORK;
375
+ }
376
+ function resolveSsrAdmissionGeneration(previousGeneration, nextGeneration) {
377
+ return {
378
+ changed: previousGeneration !== void 0 && nextGeneration !== void 0 && previousGeneration !== nextGeneration,
379
+ generation: nextGeneration
461
380
  };
462
381
  }
463
- function invalidStyle(input, component, field, value, expected) {
464
- return err(new PointsLinesInvalidStyleError({ entity: input.entity, component, field, value, expected }));
382
+ var ZERO_SPATIAL_WORK = Object.freeze({
383
+ attachmentCount: 0,
384
+ passCount: 0,
385
+ bindingCount: 0,
386
+ resourceCount: 0,
387
+ historyCount: 0,
388
+ temporalDemand: 0
389
+ });
390
+ var ADMITTED_SPATIAL_WORK = Object.freeze({
391
+ attachmentCount: 3,
392
+ passCount: 4,
393
+ bindingCount: 4,
394
+ resourceCount: 3,
395
+ historyCount: 0,
396
+ temporalDemand: 0
397
+ });
398
+ function configRange(field, viewRange, maxDistance) {
399
+ switch (field) {
400
+ case "maxDistance":
401
+ return { min: 0, minInclusive: false, max: viewRange, maxInclusive: true };
402
+ case "thickness":
403
+ return { min: 0, minInclusive: false, max: maxDistance, maxInclusive: true };
404
+ case "maxRoughness":
405
+ return { min: 0, minInclusive: true, max: 1, maxInclusive: true };
406
+ }
465
407
  }
466
- function topologyMismatch(input, submesh, expected, actual) {
467
- return err(new PointsLinesTopologyMismatchError({ entity: input.entity, submesh, expected, actual }));
408
+ function configError(field, value, range) {
409
+ const left = range.minInclusive ? "[" : "(";
410
+ const right = range.maxInclusive ? "]" : ")";
411
+ return Object.freeze({
412
+ code: "ssr-config-invalid",
413
+ expected: `finite ${field} in ${left}${range.min}, ${range.max}${right}`,
414
+ hint: `set ${field} to a finite value inside the reported range before retrying`,
415
+ detail: Object.freeze({ field, value, range: Object.freeze(range) })
416
+ });
468
417
  }
469
- function checkStyle(input) {
470
- const hasPoints = input.points !== void 0;
471
- const hasLines = input.lines !== void 0;
472
- if (hasPoints && hasLines) {
473
- return invalidStyle(
474
- input,
475
- "Points/Lines",
476
- "components",
477
- "Points + Lines",
478
- "exactly one style component"
418
+ function validateScreenSpaceReflection(config, input) {
419
+ const viewRange = input.viewRange;
420
+ if (!Number.isFinite(viewRange) || viewRange <= 0) {
421
+ return err(
422
+ configError("maxDistance", config.maxDistance, configRange("maxDistance", viewRange, 0))
479
423
  );
480
424
  }
481
- if (!hasPoints && !hasLines) {
482
- return invalidStyle(input, "Points/Lines", "components", void 0, "one style component");
425
+ if (!Number.isFinite(config.maxDistance) || config.maxDistance <= 0 || config.maxDistance > viewRange) {
426
+ return err(
427
+ configError(
428
+ "maxDistance",
429
+ config.maxDistance,
430
+ configRange("maxDistance", viewRange, config.maxDistance)
431
+ )
432
+ );
483
433
  }
484
- if (hasPoints) {
485
- const sizePx = input.points?.sizePx ?? 4;
486
- const shapeValue = input.points?.shape ?? PointShapeValue.square;
487
- const shape = pointShapeFromU32(shapeValue);
488
- if (!Number.isFinite(sizePx) || sizePx <= 0) {
489
- return invalidStyle(input, "Points", "sizePx", sizePx, "finite sizePx > 0");
490
- }
491
- if (shape === void 0) {
492
- return invalidStyle(input, "Points", "shape", shapeValue, "shape is 'square' or 'circle'");
493
- }
494
- return ok({ component: "Points", shape, sizePx });
434
+ if (!Number.isFinite(config.thickness) || config.thickness <= 0 || config.thickness > config.maxDistance) {
435
+ return err(
436
+ configError(
437
+ "thickness",
438
+ config.thickness,
439
+ configRange("thickness", viewRange, config.maxDistance)
440
+ )
441
+ );
495
442
  }
496
- const widthPx = input.lines?.widthPx ?? 1;
497
- if (!Number.isFinite(widthPx) || widthPx <= 0) {
498
- return invalidStyle(input, "Lines", "widthPx", widthPx, "finite widthPx > 0");
443
+ if (!Number.isFinite(config.maxRoughness) || config.maxRoughness < 0 || config.maxRoughness > 1) {
444
+ return err(
445
+ configError(
446
+ "maxRoughness",
447
+ config.maxRoughness,
448
+ configRange("maxRoughness", viewRange, config.maxDistance)
449
+ )
450
+ );
499
451
  }
500
- return ok({ component: "Lines", widthPx });
452
+ return ok(
453
+ Object.freeze({
454
+ maxDistance: config.maxDistance,
455
+ thickness: config.thickness,
456
+ maxRoughness: config.maxRoughness
457
+ })
458
+ );
501
459
  }
502
- function checkTopology(input, component) {
503
- const expected = component === "Points" ? "point-list" : "line-list";
504
- let pointCount = 0;
505
- let segmentCount = 0;
506
- const acceptedSubmeshes = [];
507
- let sawNonEmpty = false;
508
- for (const [submeshIndex, submesh] of input.mesh.submeshes.entries()) {
509
- const indexed = input.mesh.indices !== void 0 && submesh.indexCount > 0;
510
- const elementCount = indexed ? submesh.indexCount : submesh.vertexCount;
511
- if (elementCount === 0) continue;
512
- sawNonEmpty = true;
513
- if (component === "Lines" && submesh.topology === "line-strip") {
514
- return err(
515
- new PointsLinesStyleUnsupportedError({
516
- lane: "admission",
517
- field: "topology",
518
- member: "line-strip",
519
- supported: ["line-list"]
520
- })
521
- );
522
- }
523
- if (submesh.topology !== expected) {
524
- return topologyMismatch(input, submeshIndex, expected, submesh.topology);
525
- }
526
- if (component === "Lines" && elementCount % 2 !== 0) {
527
- return topologyMismatch(input, submeshIndex, "line-list pairs", "line-list odd tail");
528
- }
529
- acceptedSubmeshes.push(submeshIndex);
530
- if (component === "Points") pointCount += elementCount;
531
- else segmentCount += elementCount / 2;
532
- }
533
- if (!sawNonEmpty) return topologyMismatch(input, 0, expected, "empty-range");
534
- return ok({ pointCount, segmentCount, submeshes: acceptedSubmeshes });
460
+ function unavailable(lane, reason, required, actual) {
461
+ const recovery = reason === "lane-unsupported" || reason === "projection-unsupported" ? "select a perspective clustered or deferred Standard lane" : reason === "reflection-fallback-unavailable" ? "repair the submitted reflection fallback owner receipt" : reason === "temporal-unavailable" ? "submit the matching temporal-v1 producer receipt" : reason === "recovery-unavailable" ? "complete device and producer recovery before retrying" : "restore the required scene, capability, or format input before retrying";
462
+ return Object.freeze({
463
+ code: "ssr-unavailable",
464
+ expected: "SSR spatial admission has a complete Standard input and capability set",
465
+ hint: recovery,
466
+ detail: Object.freeze({
467
+ lane,
468
+ reason,
469
+ required: Object.freeze([...required]),
470
+ actual: Object.freeze({ ...actual }),
471
+ recovery
472
+ })
473
+ });
535
474
  }
536
- function checkMaterial(input) {
537
- const passes = input.material.passes ?? [];
538
- const unlitModules = /* @__PURE__ */ new Set(["forgeax_material::unlit", "forgeax::default-unlit"]);
539
- if (passes.length !== 1 || passes[0] === void 0) {
540
- const pass2 = passes.find(
541
- (candidate) => candidate.name === "deferred" || candidate.name === "shadow-caster"
542
- ) ?? passes[0];
543
- return err(
544
- new PointsLinesMaterialUnsupportedError({
545
- entity: input.entity,
546
- material: input.materialId ?? "<anonymous>",
547
- pass: pass2?.name ?? "<empty>",
548
- module: pass2?.program.module ?? "<empty>",
549
- reason: "points-lines admission requires one unlit forward pass"
475
+ function unavailableResult(lane, viewRange, failure2) {
476
+ return Object.freeze({
477
+ status: "fallback-only",
478
+ lane,
479
+ config: void 0,
480
+ viewRange,
481
+ work: ZERO_SPATIAL_WORK,
482
+ failure: failure2
483
+ });
484
+ }
485
+ function admitSsrSpatial(input) {
486
+ const camera = input.camera;
487
+ const environment = input.environment;
488
+ const viewRange = camera.far - camera.near;
489
+ const config = camera.screenSpaceReflection;
490
+ if (config === void 0) {
491
+ return Object.freeze({
492
+ status: "not-requested",
493
+ lane: environment.lane,
494
+ config: void 0,
495
+ viewRange,
496
+ work: ZERO_SPATIAL_WORK
497
+ });
498
+ }
499
+ const valid = validateScreenSpaceReflection(config, { viewRange });
500
+ if (!valid.ok) {
501
+ return Object.freeze({
502
+ status: "fallback-only",
503
+ lane: environment.lane,
504
+ config,
505
+ viewRange,
506
+ work: ZERO_SPATIAL_WORK,
507
+ failure: valid.error
508
+ });
509
+ }
510
+ if (environment.m0.status !== "admitted") {
511
+ return unavailableResult(
512
+ environment.lane,
513
+ viewRange,
514
+ unavailable(
515
+ environment.lane,
516
+ "reflection-fallback-unavailable",
517
+ ["admitted M0 dependency receipt"],
518
+ { m0: false }
519
+ )
520
+ );
521
+ }
522
+ if (environment.lane !== "clustered" && environment.lane !== "deferred") {
523
+ return unavailableResult(
524
+ environment.lane,
525
+ viewRange,
526
+ unavailable(environment.lane, "lane-unsupported", ["clustered or deferred Standard lane"], {
527
+ lane: environment.lane
550
528
  })
551
529
  );
552
530
  }
553
- const pass = passes[0];
554
- const lightMode = pass.renderState?.tags?.LightMode;
555
- if (!unlitModules.has(pass.program.module) || pass.name !== "forward" || lightMode === "ShadowCaster") {
556
- return err(
557
- new PointsLinesMaterialUnsupportedError({
558
- entity: input.entity,
559
- material: input.materialId ?? "<anonymous>",
560
- pass: pass.name,
561
- module: pass.program.module,
562
- reason: "points-lines admission requires an engine-owned unlit forward pass"
531
+ if (camera.projection !== "perspective") {
532
+ return unavailableResult(
533
+ environment.lane,
534
+ viewRange,
535
+ unavailable(environment.lane, "projection-unsupported", ["perspective camera"], {
536
+ projection: camera.projection
563
537
  })
564
538
  );
565
539
  }
566
- return ok(void 0);
567
- }
568
- function admitPointsLines(input) {
569
- const style = checkStyle(input);
570
- if (!style.ok) return style;
571
- const topology = checkTopology(input, style.value.component);
572
- if (!topology.ok) return topology;
573
- const material = checkMaterial(input);
574
- if (!material.ok) return material;
575
- if (style.value.component === "Points" && input.limits?.maxPoints !== void 0) {
576
- if (topology.value.pointCount > input.limits.maxPoints) {
577
- return err(
578
- new PointsLinesBudgetExceededError({
579
- lane: "admission",
580
- requested: topology.value.pointCount,
581
- limit: input.limits.maxPoints,
582
- unit: "points"
583
- })
584
- );
585
- }
540
+ if (!environment.sceneInputs) {
541
+ return unavailableResult(
542
+ environment.lane,
543
+ viewRange,
544
+ unavailable(
545
+ environment.lane,
546
+ "scene-input-unavailable",
547
+ ["deferred Standard scene/material/fallback inputs"],
548
+ { sceneInputs: false }
549
+ )
550
+ );
586
551
  }
587
- if (style.value.component === "Lines" && input.limits?.maxSegments !== void 0) {
588
- if (topology.value.segmentCount > input.limits.maxSegments) {
589
- return err(
590
- new PointsLinesBudgetExceededError({
591
- lane: "admission",
592
- requested: topology.value.segmentCount,
593
- limit: input.limits.maxSegments,
594
- unit: "segments"
595
- })
596
- );
597
- }
552
+ if (!environment.temporal) {
553
+ return unavailableResult(
554
+ environment.lane,
555
+ viewRange,
556
+ unavailable(environment.lane, "temporal-unavailable", ["temporal-v1"], { temporal: false })
557
+ );
558
+ }
559
+ if (!environment.reflectionFallback) {
560
+ return unavailableResult(
561
+ environment.lane,
562
+ viewRange,
563
+ unavailable(
564
+ environment.lane,
565
+ "reflection-fallback-unavailable",
566
+ ["submitted BRDF-projected fallback"],
567
+ { reflectionFallback: false }
568
+ )
569
+ );
570
+ }
571
+ if (environment.recovery === false) {
572
+ return unavailableResult(
573
+ environment.lane,
574
+ viewRange,
575
+ unavailable(environment.lane, "recovery-unavailable", ["ready device and owners"], {
576
+ recovery: false
577
+ })
578
+ );
579
+ }
580
+ const capabilities = environment.capabilities;
581
+ if (!capabilities.compute || !capabilities.storageTexture || !capabilities.rgba16floatRenderable) {
582
+ return unavailableResult(
583
+ environment.lane,
584
+ viewRange,
585
+ unavailable(
586
+ environment.lane,
587
+ "capability-unavailable",
588
+ ["compute", "storageTexture", "rgba16floatRenderable"],
589
+ {
590
+ compute: capabilities.compute,
591
+ storageTexture: capabilities.storageTexture,
592
+ rgba16floatRenderable: capabilities.rgba16floatRenderable
593
+ }
594
+ )
595
+ );
596
+ }
597
+ if (!capabilities.r32floatSampledStorage) {
598
+ return unavailableResult(
599
+ environment.lane,
600
+ viewRange,
601
+ unavailable(
602
+ environment.lane,
603
+ "format-unavailable",
604
+ ["r32float sampled and storage mip chain"],
605
+ { r32floatSampledStorage: false }
606
+ )
607
+ );
598
608
  }
599
- return ok({ ...style.value, ...topology.value });
600
- }
601
-
602
- // src/point-shadow-inspection.ts
603
- function inspectPointShadow(snapshots, shadowAtlasCapacity) {
604
- const requested = snapshots.length;
605
- const admitted = snapshots.reduce(
606
- (count, snapshot) => snapshot.shadowAtlasLayer >= 0 && snapshot.shadowAtlasLayer < shadowAtlasCapacity ? count + 1 : count,
607
- 0
608
- );
609
- const status = requested === 0 ? "inactive" : requested > shadowAtlasCapacity || admitted !== requested ? "over-budget" : "ready";
610
609
  return Object.freeze({
611
- status,
612
- requested,
613
- admitted,
614
- // A point shadow only samples an atlas after it owns an atlas layer. Keep
615
- // these names explicit for AI diagnostics while deriving both from the
616
- // one layer projection above.
617
- shadowed: admitted,
618
- shadowAtlasOccupancy: admitted,
619
- shadowAtlasCapacity
610
+ status: "admitted",
611
+ lane: environment.lane,
612
+ config: valid.value,
613
+ viewRange,
614
+ work: ADMITTED_SPATIAL_WORK
620
615
  });
621
616
  }
622
617
 
@@ -651,48 +646,6 @@ function inspectVolumetricFog(input) {
651
646
  candidateSelectedLight: recovery?.candidateSelectedLight
652
647
  });
653
648
  }
654
- var FACE_ORIENTATION = [
655
- { direction: [1, 0, 0], up: [0, 1, 0] },
656
- { direction: [-1, 0, 0], up: [0, 1, 0] },
657
- { direction: [0, 1, 0], up: [0, 0, -1] },
658
- { direction: [0, -1, 0], up: [0, 0, 1] },
659
- { direction: [0, 0, 1], up: [0, 1, 0] },
660
- { direction: [0, 0, -1], up: [0, 1, 0] }
661
- ];
662
- function assertRange(near, far) {
663
- if (!Number.isFinite(near) || near <= 0 || !Number.isFinite(far) || far <= near) {
664
- throw new RangeError("CubeCamera requires finite near > 0 and far > near.");
665
- }
666
- }
667
- function buildCubeCameraFaceViews(input) {
668
- assertRange(input.near, input.far);
669
- const views = [];
670
- for (const [index, face] of CUBE_CAMERA_FACE_ORDER.entries()) {
671
- const orientation = FACE_ORIENTATION[index];
672
- if (orientation === void 0)
673
- throw new Error(`CubeCamera face orientation missing at ${index}`);
674
- const target = [
675
- (input.position[0] ?? 0) + orientation.direction[0],
676
- (input.position[1] ?? 0) + orientation.direction[1],
677
- (input.position[2] ?? 0) + orientation.direction[2]
678
- ];
679
- const view = mat4.lookAt(mat4.create(), input.position, target, orientation.up);
680
- const projection = mat4.perspective(mat4.create(), Math.PI / 2, 1, input.near, input.far);
681
- const viewProjection = mat4.multiply(mat4.create(), projection, view);
682
- views.push({
683
- position: input.position,
684
- face,
685
- direction: orientation.direction,
686
- up: orientation.up,
687
- near: input.near,
688
- far: input.far,
689
- view,
690
- projection,
691
- viewProjection
692
- });
693
- }
694
- return views;
695
- }
696
649
 
697
650
  // src/reflection/filter.ts
698
651
  function createProbeFilterState(input) {
@@ -733,6 +686,9 @@ function normalize(vector) {
733
686
  }
734
687
  function boxProjectReflectionDirection(direction, boxCenter, halfExtents, point) {
735
688
  const ray = normalize(direction);
689
+ for (const axis of [0, 1, 2]) {
690
+ if (Math.abs(point[axis] - boxCenter[axis]) >= halfExtents[axis]) return ray;
691
+ }
736
692
  let distance = Number.POSITIVE_INFINITY;
737
693
  for (let axis = 0; axis < 3; axis += 1) {
738
694
  const component = ray[axis] ?? 0;
@@ -852,14 +808,14 @@ function validateReflectionProbeInput(input) {
852
808
  }
853
809
  };
854
810
  }
855
- if (!Number.isInteger(input.resolution) || input.resolution <= 0) {
811
+ if (!Number.isInteger(input.resolution) || input.resolution < 16 || (input.resolution & input.resolution - 1) !== 0) {
856
812
  return {
857
813
  ok: false,
858
814
  error: {
859
815
  code: "reflection-probe-input-invalid",
860
816
  field: "resolution",
861
817
  value: input.resolution,
862
- expected: "a positive integer"
818
+ expected: "a power of two of at least 16 pixels"
863
819
  }
864
820
  };
865
821
  }
@@ -868,11 +824,12 @@ function validateReflectionProbeInput(input) {
868
824
  function estimateReflectionProbeBytes(resolution, limits = DEFAULT_REFLECTION_PROBE_LIMITS) {
869
825
  const maxResolution = limits.maxResolution ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxResolution;
870
826
  const clamped = Math.min(resolution, maxResolution);
871
- let mipTexels = 0;
872
- for (let size = clamped; size >= 1; size = Math.floor(size / 2)) {
873
- mipTexels += size * size;
827
+ let filteredTexels = 0;
828
+ for (let mip = 0; mip < 5; mip++) {
829
+ const size = Math.max(1, Math.floor(clamped / 2 ** mip));
830
+ filteredTexels += size * size;
874
831
  }
875
- return mipTexels * 6 * REFLECTION_PROBE_BYTES_PER_TEXEL;
832
+ return (clamped * clamped + 2 * filteredTexels) * 6 * REFLECTION_PROBE_BYTES_PER_TEXEL + 3 * clamped * clamped * 4;
876
833
  }
877
834
  function admitReflectionProbe(input, current, limits = DEFAULT_REFLECTION_PROBE_LIMITS) {
878
835
  const maxProbes = limits.maxProbes ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxProbes;
@@ -1225,235 +1182,532 @@ function consumeLodOcclusionInspection(inspection) {
1225
1182
  const action = error.code.startsWith("asset-") || reason === "producer-failed" ? "rebuild" : reason === "query-failed" || reason === "page-exhausted" || reason === "device-loss" ? "retry" : "cold-cook";
1226
1183
  return { action, sourceKey: inspection.root.sourceKey, reason };
1227
1184
  }
1228
- var SSR_FORMAT_PROFILE = "r32float-mip-sampled-storage";
1229
- var SSR_FORMAT_STAGES = Object.freeze([
1230
- "texture-create",
1231
- "mip-view",
1232
- "sampled-storage-bind-group",
1233
- "pipeline-bind",
1234
- "finish",
1235
- "submit",
1236
- "completion",
1237
- "readback"
1238
- ]);
1239
- var ZERO_WORK = Object.freeze({
1240
- attachmentCount: 0,
1241
- passCount: 0,
1242
- bindingCount: 0,
1243
- resourceCount: 0,
1244
- historyCount: 0,
1245
- temporalDemand: 0
1246
- });
1247
- var ADMITTED_WORK = Object.freeze({
1248
- attachmentCount: 1,
1249
- passCount: 1,
1250
- bindingCount: 1,
1251
- resourceCount: 1,
1252
- historyCount: 0,
1253
- temporalDemand: 0
1254
- });
1255
- var ZERO_BUDGET = Object.freeze({
1256
- probeExecutions: 0,
1257
- resetCount: 0,
1258
- rebuildCount: 0
1259
- });
1260
- var ADMITTED_BUDGET = Object.freeze({
1261
- probeExecutions: 1,
1262
- resetCount: 0,
1263
- rebuildCount: 0
1264
- });
1265
- function identityFieldMismatch(expected, actual) {
1266
- for (const field of ["sourceHead", "sourceTree", "lockSha256", "buildSha256"]) {
1267
- if (expected[field] !== actual[field]) return field;
1185
+
1186
+ // src/ssr/inspection.ts
1187
+ var SSR_INSPECTION_MAX_PASSES = 64;
1188
+ function nonNegativeSafeInteger(name, value) {
1189
+ if (!Number.isSafeInteger(value) || value < 0) {
1190
+ throw new Error(`${name} must be a non-negative safe integer`);
1268
1191
  }
1269
- return void 0;
1270
- }
1271
- function blocked(identity, failure2, generation = 0) {
1272
- return Object.freeze({
1273
- status: "fallback-only",
1274
- identity,
1275
- generation,
1276
- work: ZERO_WORK,
1277
- budget: ZERO_BUDGET,
1278
- failure: failure2
1279
- });
1192
+ return value;
1280
1193
  }
1281
- function failure(code, owner, hint, detail = {}) {
1282
- const action = recoveryActionFor(code);
1194
+ function copyHistory(history) {
1195
+ nonNegativeSafeInteger("SSR inspection history.bytes", history.bytes);
1196
+ nonNegativeSafeInteger("SSR inspection history.resetCount", history.resetCount);
1283
1197
  return Object.freeze({
1284
- code,
1285
- expected: "all producer, format, and temporal receipts share one admitted identity",
1286
- hint,
1287
- detail: Object.freeze({ owner, action, ...detail })
1198
+ state: history.state,
1199
+ bytes: history.bytes,
1200
+ resetCount: history.resetCount
1288
1201
  });
1289
1202
  }
1290
- function recoveryActionFor(code) {
1291
- switch (code) {
1292
- case "ssr-reflection-fallback-unavailable":
1293
- case "ssr-receipt-identity-mismatch":
1294
- return "rebuild";
1295
- case "ssr-not-requested":
1296
- case "ssr-format-unavailable":
1297
- case "ssr-temporal-unavailable":
1298
- case "ssr-receipt-stale":
1299
- return "retry";
1203
+ function copyCoverage(coverage) {
1204
+ const result = {
1205
+ hitCount: coverage?.hitCount ?? null,
1206
+ fallbackCount: coverage?.fallbackCount ?? null,
1207
+ excludedCount: coverage?.excludedCount ?? null
1208
+ };
1209
+ for (const [key, value] of Object.entries(result)) {
1210
+ if (value !== null) nonNegativeSafeInteger(`SSR inspection coverage.${key}`, value);
1300
1211
  }
1212
+ return Object.freeze(result);
1301
1213
  }
1302
- function receiptFailure(input, receipt, owner) {
1303
- const field = identityFieldMismatch(input.identity, receipt.identity);
1304
- if (field === void 0) return void 0;
1305
- return blocked(
1306
- input.identity,
1307
- failure("ssr-receipt-identity-mismatch", owner, "rebuild the owner receipt for this identity", {
1308
- identityField: field
1214
+ function copyPassRoster(passRoster) {
1215
+ return Object.freeze(
1216
+ [...passRoster ?? []].slice(0, SSR_INSPECTION_MAX_PASSES).map((name, index) => {
1217
+ if (typeof name !== "string" || name.length === 0) {
1218
+ throw new Error(`SSR inspection passRoster[${index}] must be a non-empty string`);
1219
+ }
1220
+ return name;
1309
1221
  })
1310
1222
  );
1311
1223
  }
1312
- function validFallback(receipt) {
1313
- return receipt !== void 0 && receipt.candidateVisible === false && Number.isFinite(receipt.coverage) && receipt.coverage >= 0 && receipt.coverage <= 1 && (receipt.sourceKey === void 0 || receipt.sourceKey.length > 0) && (receipt.extent === void 0 || receipt.extent.length === 3 && receipt.extent.every((value) => Number.isFinite(value) && value > 0)) && Number.isInteger(receipt.sourceGeneration) && receipt.sourceGeneration >= 0 && Number.isInteger(receipt.projectionGeneration) && receipt.projectionGeneration >= 0 && Number.isInteger(receipt.deviceGeneration) && receipt.deviceGeneration >= 0 && receipt.brdfSignature === "standard-pbr-ibl-v1" && (receipt.source === "probe" && (receipt.state === "active" || receipt.state === "lkg") || receipt.source === "skylight" && (receipt.state === "active" || receipt.state === "lkg") || receipt.source === "neutral" && receipt.state === "neutral");
1314
- }
1315
- function validFormat(receipt) {
1316
- if (receipt?.profile !== SSR_FORMAT_PROFILE || receipt.verdict !== "admitted" || receipt.evidence !== "real" || !Number.isInteger(receipt.deviceGeneration) || receipt.deviceGeneration < 0) {
1317
- return false;
1318
- }
1319
- if (!SSR_FORMAT_STAGES.every(
1320
- (stage) => receipt.stages.some((entry) => entry.stage === stage && entry.verdict === "admitted")
1321
- )) {
1322
- return false;
1323
- }
1324
- return validateR32FloatReceipt(receipt).ok;
1224
+ function projectSsrSpatialInspection(admission, projection = {}) {
1225
+ const config = admission.config;
1226
+ return Object.freeze({
1227
+ status: projection.status ?? admission.status,
1228
+ lane: admission.lane,
1229
+ config: config === void 0 ? void 0 : Object.freeze({
1230
+ maxDistance: config.maxDistance,
1231
+ thickness: config.thickness,
1232
+ maxRoughness: config.maxRoughness
1233
+ }),
1234
+ viewRange: admission.viewRange,
1235
+ coverage: copyCoverage(projection.coverage),
1236
+ history: copyHistory(
1237
+ projection.history ?? {
1238
+ state: "not-owned",
1239
+ bytes: 0,
1240
+ resetCount: 0
1241
+ }
1242
+ ),
1243
+ work: Object.freeze({ ...admission.work }),
1244
+ passRoster: copyPassRoster(projection.passRoster),
1245
+ fallbackSource: projection.fallbackSource,
1246
+ failure: projection.failure ?? admission.failure
1247
+ });
1325
1248
  }
1326
- function validTemporal(receipt) {
1327
- return receipt?.successfulSubmit === true && Number.isInteger(receipt.generation) && receipt.generation >= 0;
1249
+ function serializeSsrSpatialInspection(inspection) {
1250
+ return JSON.stringify(inspection);
1328
1251
  }
1329
- function admitSsrM0(input) {
1330
- if (!input.requested) {
1331
- return blocked(
1332
- input.identity,
1333
- failure("ssr-not-requested", "consumer", "request SSR before evaluating M0 admission")
1334
- );
1335
- }
1336
- if (input.reflectionFallback === void 0) {
1337
- return blocked(
1338
- input.identity,
1339
- failure("ssr-reflection-fallback-unavailable", "producer", "use LKG, Skylight, or neutral")
1340
- );
1341
- }
1342
- const fallbackIdentityFailure = receiptFailure(input, input.reflectionFallback, "producer");
1343
- if (fallbackIdentityFailure !== void 0) return fallbackIdentityFailure;
1344
- if (!validFallback(input.reflectionFallback)) {
1345
- return blocked(
1346
- input.identity,
1347
- failure(
1348
- "ssr-reflection-fallback-unavailable",
1349
- "producer",
1350
- "inspect and rebuild the producer receipt"
1351
- ),
1352
- input.reflectionFallback.projectionGeneration
1353
- );
1252
+ var DynamicGeometryError = class extends Error {
1253
+ code;
1254
+ expected;
1255
+ hint;
1256
+ detail;
1257
+ constructor(code, expected, hint, detail = {}) {
1258
+ super(`${code}: ${expected}`);
1259
+ this.name = "DynamicGeometryError";
1260
+ this.code = code;
1261
+ this.expected = expected;
1262
+ this.hint = hint;
1263
+ this.detail = Object.freeze({ code, ...detail });
1354
1264
  }
1355
- if (input.format === void 0) {
1356
- return blocked(
1357
- input.identity,
1358
- failure("ssr-format-unavailable", "format", "probe the exact format profile for this device"),
1359
- input.reflectionFallback.projectionGeneration
1360
- );
1265
+ };
1266
+ function sameCandidateCredential(candidate, committed) {
1267
+ return candidate.candidateId === committed.candidateId && candidate.owner === committed.owner && candidate.world === committed.world && candidate.generation === committed.generation && candidate.entity === committed.entity && candidate.physicsEntity === committed.physicsEntity && candidate.gpuReady === committed.gpuReady && candidate.meshBytes === committed.meshBytes && candidate.revision === committed.revision && candidate.topologyRevision === committed.topologyRevision && candidate.materialIdentity === committed.materialIdentity && candidate.meshHandle === committed.meshHandle && candidate.fixedStep === committed.fixedStep;
1268
+ }
1269
+ function cloneTypedArray(value) {
1270
+ return new value.constructor(value);
1271
+ }
1272
+ function cloneMesh(mesh) {
1273
+ const attributes = Object.fromEntries(
1274
+ Object.entries(mesh.attributes).map(([key, value]) => [
1275
+ key,
1276
+ value instanceof ArrayBuffer ? value.slice(0) : value === void 0 ? void 0 : cloneTypedArray(value)
1277
+ ])
1278
+ );
1279
+ return Object.freeze({
1280
+ ...mesh,
1281
+ vertices: new Float32Array(mesh.vertices),
1282
+ ...mesh.indices === void 0 ? {} : { indices: cloneTypedArray(mesh.indices) },
1283
+ attributes,
1284
+ ...mesh.aabb === void 0 ? {} : { aabb: new Float32Array(mesh.aabb) },
1285
+ submeshes: Object.freeze(mesh.submeshes.map((submesh) => Object.freeze({ ...submesh }))),
1286
+ materialSlots: Object.freeze(mesh.materialSlots.map((slot) => Object.freeze({ ...slot })))
1287
+ });
1288
+ }
1289
+ function cloneCandidate(candidate) {
1290
+ return Object.freeze({ ...candidate, mesh: cloneMesh(candidate.mesh) });
1291
+ }
1292
+ function validateMesh(mesh) {
1293
+ if (mesh.kind !== "mesh") return "MeshAsset.kind must be mesh";
1294
+ if (!(mesh.vertices instanceof Float32Array) || mesh.vertices.length === 0) {
1295
+ return "MeshAsset.vertices must be a non-empty Float32Array";
1361
1296
  }
1362
- const formatIdentityFailure = receiptFailure(input, input.format, "format");
1363
- if (formatIdentityFailure !== void 0) return formatIdentityFailure;
1364
- if (!validFormat(input.format)) {
1365
- return blocked(
1366
- input.identity,
1367
- failure("ssr-format-unavailable", "format", "complete the full r32float profile probe"),
1368
- input.reflectionFallback.projectionGeneration
1369
- );
1297
+ if (mesh.indices !== void 0 && !(mesh.indices instanceof Uint16Array || mesh.indices instanceof Uint32Array)) {
1298
+ return "MeshAsset.indices must be Uint16Array or Uint32Array";
1370
1299
  }
1371
- if (input.temporal === void 0) {
1372
- return blocked(
1373
- input.identity,
1374
- failure(
1375
- "ssr-temporal-unavailable",
1376
- "temporal",
1377
- "submit the matching temporal producer receipt"
1378
- ),
1379
- input.reflectionFallback.projectionGeneration
1380
- );
1300
+ if (mesh.submeshes.length === 0)
1301
+ return "MeshAsset.submeshes must contain at least one topology range";
1302
+ if (mesh.submeshes.some(
1303
+ (submesh) => !Number.isSafeInteger(submesh.materialSlot) || submesh.materialSlot < 0 || submesh.materialSlot >= mesh.materialSlots.length
1304
+ )) {
1305
+ return "MeshAsset.materialSlots must cover every referenced materialSlot";
1381
1306
  }
1382
- const temporalIdentityFailure = receiptFailure(input, input.temporal, "temporal");
1383
- if (temporalIdentityFailure !== void 0) return temporalIdentityFailure;
1384
- if (!validTemporal(input.temporal)) {
1385
- return blocked(
1386
- input.identity,
1387
- failure("ssr-temporal-unavailable", "temporal", "inspect and rebuild the temporal receipt"),
1388
- input.reflectionFallback.projectionGeneration
1389
- );
1307
+ if (mesh.vertices.some((value) => !Number.isFinite(value)))
1308
+ return "MeshAsset.vertices must be finite";
1309
+ return void 0;
1310
+ }
1311
+ function meshByteSize(mesh) {
1312
+ let bytes = mesh.vertices.byteLength + (mesh.indices?.byteLength ?? 0);
1313
+ for (const value of Object.values(mesh.attributes)) {
1314
+ if (value instanceof ArrayBuffer) bytes += value.byteLength;
1315
+ else if (value !== void 0 && ArrayBuffer.isView(value)) bytes += value.byteLength;
1390
1316
  }
1391
- if (input.previousGeneration !== void 0 && input.previousGeneration !== input.reflectionFallback.projectionGeneration) {
1392
- return blocked(
1393
- input.identity,
1394
- failure(
1395
- "ssr-receipt-stale",
1396
- "consumer",
1397
- "discard stale completion and reinspect the owners",
1398
- {
1399
- generation: input.reflectionFallback.projectionGeneration
1317
+ if (mesh.aabb !== void 0) bytes += mesh.aabb.byteLength;
1318
+ return bytes;
1319
+ }
1320
+ function createDynamicGeometryLifecycle(maxCandidates = 32, maxMeshBytes = 64 * 1024 * 1024) {
1321
+ const records = /* @__PURE__ */ new Map();
1322
+ const owner = {};
1323
+ let sequence = 0;
1324
+ let currentGeneration = 0;
1325
+ let disposed = false;
1326
+ let historyInvalidations = 0;
1327
+ let latestRevision;
1328
+ let latestFrameId;
1329
+ let retired = 0;
1330
+ let invalidated = 0;
1331
+ let meshBytes = 0;
1332
+ const latestRevisionByWorld = /* @__PURE__ */ new WeakMap();
1333
+ const latestTopologyRevisionByWorld = /* @__PURE__ */ new WeakMap();
1334
+ const publishedReceipts = /* @__PURE__ */ new Map();
1335
+ const failure2 = (code, expected, hint, detail = {}) => err(new DynamicGeometryError(code, expected, hint, detail));
1336
+ const current = (candidate) => {
1337
+ const record = records.get(candidate.candidateId);
1338
+ if (record === void 0 || candidate.owner !== owner || record.candidate.owner !== candidate.owner || record.candidate.world !== candidate.world || record.candidate.generation !== candidate.generation)
1339
+ return void 0;
1340
+ return record;
1341
+ };
1342
+ return {
1343
+ prepare(input, generation) {
1344
+ if (disposed)
1345
+ return failure2("dynamic-geometry-disposed", "renderer is alive", "rebuild the Renderer");
1346
+ if (input.world === null || typeof input.world !== "object") {
1347
+ return failure2(
1348
+ "dynamic-geometry-world-not-attached",
1349
+ "candidate belongs to an attached World",
1350
+ "attach the World before preparing geometry"
1351
+ );
1352
+ }
1353
+ if (!Number.isInteger(input.revision) || input.revision < 0) {
1354
+ return failure2(
1355
+ "dynamic-geometry-invalid",
1356
+ "geometry revision is a non-negative integer",
1357
+ "advance the consumer revision monotonically",
1358
+ { revision: input.revision }
1359
+ );
1360
+ }
1361
+ if (generation !== currentGeneration && currentGeneration !== 0) {
1362
+ return failure2(
1363
+ "dynamic-geometry-generation-mismatch",
1364
+ "candidate uses the active renderer generation",
1365
+ "discard stale generation work and prepare again",
1366
+ { generation, actual: currentGeneration }
1367
+ );
1368
+ }
1369
+ if (records.size >= maxCandidates) {
1370
+ return failure2(
1371
+ "dynamic-geometry-budget-exceeded",
1372
+ "candidate count remains within the bounded renderer budget",
1373
+ "cancel or retire an earlier candidate before retrying",
1374
+ { actual: records.size }
1375
+ );
1376
+ }
1377
+ const invalid = validateMesh(input.mesh);
1378
+ if (invalid !== void 0)
1379
+ return failure2(
1380
+ "dynamic-geometry-invalid",
1381
+ "MeshAsset satisfies the standard geometry contract",
1382
+ invalid
1383
+ );
1384
+ const candidateBytes = meshByteSize(input.mesh);
1385
+ if (!Number.isSafeInteger(candidateBytes) || candidateBytes < 0 || meshBytes > maxMeshBytes - candidateBytes) {
1386
+ return failure2(
1387
+ "dynamic-geometry-budget-exceeded",
1388
+ "candidate mesh bytes remain within the bounded renderer resource budget",
1389
+ "cancel or retire an earlier candidate before retrying",
1390
+ { actual: { meshBytes, candidateBytes, maxMeshBytes } }
1391
+ );
1392
+ }
1393
+ const candidateId = `mesh:${generation}:${++sequence}:${input.revision}`;
1394
+ const candidate = Object.freeze({
1395
+ candidateId,
1396
+ generation,
1397
+ owner,
1398
+ world: input.world,
1399
+ ...input.entity === void 0 ? {} : { entity: input.entity },
1400
+ ...input.physicsEntity === void 0 ? {} : { physicsEntity: input.physicsEntity },
1401
+ gpuReady: input.meshHandle !== void 0,
1402
+ meshBytes: candidateBytes,
1403
+ revision: input.revision,
1404
+ topologyRevision: input.topologyRevision ?? input.revision,
1405
+ ...input.materialIdentity === void 0 ? {} : { materialIdentity: input.materialIdentity },
1406
+ ...input.meshHandle === void 0 ? {} : { meshHandle: input.meshHandle },
1407
+ ...input.fixedStep === void 0 ? {} : { fixedStep: input.fixedStep },
1408
+ mesh: cloneMesh(input.mesh),
1409
+ state: "prepared"
1410
+ });
1411
+ records.set(candidateId, {
1412
+ world: input.world,
1413
+ candidate,
1414
+ historyInvalidated: false
1415
+ });
1416
+ meshBytes += candidateBytes;
1417
+ currentGeneration = generation;
1418
+ return ok(cloneCandidate(candidate));
1419
+ },
1420
+ accept(candidate, ordering) {
1421
+ if (disposed)
1422
+ return failure2("dynamic-geometry-disposed", "renderer is alive", "rebuild the Renderer");
1423
+ const record = current(candidate);
1424
+ if (record === void 0)
1425
+ return failure2(
1426
+ "dynamic-geometry-candidate-not-found",
1427
+ "candidate is owned by this renderer",
1428
+ "discard the stale credential"
1429
+ );
1430
+ if (candidate.generation !== currentGeneration) {
1431
+ return failure2(
1432
+ "dynamic-geometry-generation-mismatch",
1433
+ "candidate generation matches the active renderer generation",
1434
+ "prepare against the current renderer generation",
1435
+ { candidateId: candidate.candidateId }
1436
+ );
1437
+ }
1438
+ if (record.candidate.state !== "prepared") {
1439
+ return failure2(
1440
+ "dynamic-geometry-candidate-state",
1441
+ "candidate is prepared exactly once before acceptance",
1442
+ "retain the accepted or published receipt",
1443
+ { candidateId: candidate.candidateId }
1444
+ );
1445
+ }
1446
+ if (!sameCandidateCredential(candidate, record.candidate)) {
1447
+ return failure2(
1448
+ "dynamic-geometry-receipt-mismatch",
1449
+ "acceptance uses the exact prepared candidate credential",
1450
+ "discard the altered credential and use the value returned by prepare",
1451
+ { candidateId: candidate.candidateId }
1452
+ );
1453
+ }
1454
+ if (ordering !== void 0) {
1455
+ if (ordering.world !== record.world || !Number.isInteger(ordering.fixedStep) || ordering.fixedStep < 0) {
1456
+ return failure2(
1457
+ "dynamic-geometry-ordering-required",
1458
+ "acceptance ordering names the candidate World and a non-negative fixed step",
1459
+ "submit the PhysicsWorld publication ordering for the same attached World",
1460
+ { candidateId: candidate.candidateId, actual: ordering }
1461
+ );
1462
+ }
1463
+ }
1464
+ const newest = [...records.values()].filter(
1465
+ (entry) => entry.candidate.candidateId !== candidate.candidateId && entry.world === record.world && entry.candidate.entity === record.candidate.entity && (entry.candidate.state === "prepared" || entry.candidate.state === "accepted")
1466
+ ).map((entry) => entry.candidate.revision).concat(latestRevisionByWorld.get(record.world)?.get(record.candidate.entity) ?? -1).sort((a, b) => b - a)[0];
1467
+ if (newest !== void 0 && record.candidate.revision <= newest) {
1468
+ return failure2(
1469
+ "dynamic-geometry-stale",
1470
+ "accepted geometry revision is newer than the active candidate",
1471
+ "advance topology revision before accepting",
1472
+ { candidateId: candidate.candidateId }
1473
+ );
1474
+ }
1475
+ const accepted = Object.freeze({
1476
+ ...record.candidate,
1477
+ ...ordering === void 0 ? {} : { fixedStep: ordering.fixedStep },
1478
+ state: "accepted"
1479
+ });
1480
+ const previousTopologies = [...records.values()].filter(
1481
+ (entry) => entry.candidate.candidateId !== candidate.candidateId && entry.world === record.world && entry.candidate.entity === record.candidate.entity
1482
+ ).map((entry) => entry.candidate.topologyRevision);
1483
+ const previousLatestTopology = latestTopologyRevisionByWorld.get(record.world)?.get(record.candidate.entity);
1484
+ const newestTopology = previousTopologies.concat(previousLatestTopology === void 0 ? [] : [previousLatestTopology]).sort((a, b) => b - a)[0];
1485
+ if (newestTopology !== void 0 && accepted.topologyRevision < newestTopology) {
1486
+ return failure2(
1487
+ "dynamic-geometry-stale",
1488
+ "accepted topology revision is not older than the active geometry history",
1489
+ "advance topology revision before accepting a replacement candidate",
1490
+ { candidateId: candidate.candidateId }
1491
+ );
1492
+ }
1493
+ if (newestTopology !== void 0 && accepted.topologyRevision > newestTopology) {
1494
+ historyInvalidations += 1;
1495
+ for (const previous of records.values()) {
1496
+ if (previous.world !== record.world || previous.candidate.entity !== record.candidate.entity || previous.candidate.candidateId === candidate.candidateId || previous.candidate.topologyRevision >= accepted.topologyRevision)
1497
+ continue;
1498
+ if (!previous.historyInvalidated) {
1499
+ previous.historyInvalidated = true;
1500
+ invalidated += 1;
1501
+ }
1502
+ }
1503
+ }
1504
+ record.candidate = accepted;
1505
+ return ok(cloneCandidate(accepted));
1506
+ },
1507
+ cancel(candidate, completion) {
1508
+ const record = current(candidate);
1509
+ if (record === void 0)
1510
+ return failure2(
1511
+ "dynamic-geometry-candidate-not-found",
1512
+ "candidate is owned by this renderer",
1513
+ "discard the stale credential"
1514
+ );
1515
+ if (!sameCandidateCredential(candidate, record.candidate))
1516
+ return failure2(
1517
+ "dynamic-geometry-receipt-mismatch",
1518
+ "cancellation uses the exact prepared candidate credential",
1519
+ "discard the altered credential and use the value returned by prepare",
1520
+ { candidateId: candidate.candidateId }
1521
+ );
1522
+ if (record.candidate.state !== "prepared" && record.candidate.state !== "accepted") {
1523
+ return failure2(
1524
+ "dynamic-geometry-candidate-state",
1525
+ "only prepared or accepted geometry can be cancelled once",
1526
+ "retire published geometry or await the existing terminal cleanup"
1527
+ );
1528
+ }
1529
+ record.candidate = Object.freeze({ ...record.candidate, state: "cancelled" });
1530
+ const release = () => {
1531
+ if (records.get(candidate.candidateId) !== record) return;
1532
+ records.delete(candidate.candidateId);
1533
+ meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
1534
+ };
1535
+ if (completion === void 0) release();
1536
+ else void completion.then(release, release);
1537
+ return ok(void 0);
1538
+ },
1539
+ retire(candidate) {
1540
+ const record = current(candidate);
1541
+ if (record === void 0)
1542
+ return failure2(
1543
+ "dynamic-geometry-candidate-not-found",
1544
+ "retirement uses a published candidate owned by this renderer",
1545
+ "discard the stale credential and do not evict any unrelated mesh",
1546
+ { candidateId: candidate.candidateId }
1547
+ );
1548
+ if (!sameCandidateCredential(candidate, record.candidate))
1549
+ return failure2(
1550
+ "dynamic-geometry-receipt-mismatch",
1551
+ "retirement uses the exact published candidate credential",
1552
+ "discard the altered credential and use the value returned by publish",
1553
+ { candidateId: candidate.candidateId }
1554
+ );
1555
+ if (record.candidate.state !== "published") {
1556
+ return failure2(
1557
+ "dynamic-geometry-candidate-state",
1558
+ "only published geometry can enter receipt-bound retirement",
1559
+ "publish the candidate from a submitted frame first"
1560
+ );
1561
+ }
1562
+ record.candidate = Object.freeze({ ...record.candidate, state: "retired" });
1563
+ publishedReceipts.delete(candidate.candidateId);
1564
+ retired += 1;
1565
+ return ok(void 0);
1566
+ },
1567
+ finalizeRetirement(candidate) {
1568
+ const record = current(candidate);
1569
+ if (record === void 0)
1570
+ return failure2(
1571
+ "dynamic-geometry-candidate-not-found",
1572
+ "retirement finalization uses a candidate retained by this lifecycle",
1573
+ "discard the stale credential or finish the current receipt-bound retirement"
1574
+ );
1575
+ if (!sameCandidateCredential(candidate, record.candidate))
1576
+ return failure2(
1577
+ "dynamic-geometry-receipt-mismatch",
1578
+ "retirement finalization uses the exact published candidate credential",
1579
+ "discard the altered credential and use the value returned by publication",
1580
+ { candidateId: candidate.candidateId }
1581
+ );
1582
+ if (record.candidate.state !== "retired")
1583
+ return failure2(
1584
+ "dynamic-geometry-candidate-state",
1585
+ "only a retired candidate can release its deferred budget",
1586
+ "retire the published candidate before finalizing its receipt-bound cleanup",
1587
+ { candidateId: candidate.candidateId }
1588
+ );
1589
+ records.delete(candidate.candidateId);
1590
+ meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
1591
+ return ok(void 0);
1592
+ },
1593
+ publishFrame(frame, worlds, fixedStep, canPublish) {
1594
+ if (disposed || frame.deviceGeneration !== currentGeneration) return [];
1595
+ const receipts = [];
1596
+ for (const record of records.values()) {
1597
+ const canRepeatPublished = record.candidate.state === "published" && // Attached Renderer publication revalidates the entity binding in
1598
+ // `canPublish`, so a history-invalidated candidate can still record
1599
+ // a real draw for its live entity. Detached lifecycle publication
1600
+ // remains one-shot once that history is invalidated.
1601
+ (canPublish !== void 0 || !record.historyInvalidated);
1602
+ if (record.candidate.state !== "accepted" && !canRepeatPublished) continue;
1603
+ if (worlds !== void 0 && !worlds.includes(record.world)) continue;
1604
+ if (record.candidate.fixedStep !== void 0 && (fixedStep === void 0 || record.candidate.fixedStep > fixedStep)) {
1605
+ continue;
1400
1606
  }
1401
- ),
1402
- input.reflectionFallback.projectionGeneration
1403
- );
1404
- }
1405
- return Object.freeze({
1406
- status: "admitted",
1407
- identity: input.identity,
1408
- generation: input.reflectionFallback.projectionGeneration,
1409
- work: ADMITTED_WORK,
1410
- budget: ADMITTED_BUDGET
1411
- });
1412
- }
1413
- function projectSsrDependencies(input) {
1414
- const identity = input.identity;
1415
- const reflectionFallback = identity === void 0 || input.reflectionFallback?.identity === void 0 ? void 0 : input.reflectionFallback;
1416
- const format = identity === void 0 || input.format === void 0 ? void 0 : { ...input.format, identity };
1417
- const temporal = identity === void 0 || input.temporal === void 0 ? void 0 : { identity, ...input.temporal };
1418
- const admission = identity === void 0 ? blocked(
1419
- void 0,
1420
- failure(
1421
- input.requested ? "ssr-receipt-identity-mismatch" : "ssr-not-requested",
1422
- "consumer",
1423
- input.requested ? "bind the exact source, tree, lock, and build identity before admission" : "request SSR before evaluating M0 admission",
1424
- input.requested ? { identityField: "sourceHead" } : {}
1425
- )
1426
- ) : admitSsrM0({
1427
- requested: input.requested,
1428
- identity,
1429
- ...reflectionFallback === void 0 ? {} : { reflectionFallback },
1430
- ...format === void 0 ? {} : { format },
1431
- ...temporal === void 0 ? {} : { temporal },
1432
- ...input.previousGeneration === void 0 ? {} : { previousGeneration: input.previousGeneration }
1433
- });
1434
- return Object.freeze({
1435
- status: admission.status,
1436
- identity,
1437
- requested: input.requested,
1438
- reflectionFallback: input.reflectionFallback,
1439
- format,
1440
- temporal,
1441
- admission,
1442
- work: admission.work,
1443
- budget: admission.budget,
1444
- failure: admission.failure
1445
- });
1446
- }
1447
- function zeroSsrAdmissionWork() {
1448
- return ZERO_WORK;
1449
- }
1450
- function resolveSsrAdmissionGeneration(previousGeneration, nextGeneration) {
1451
- return {
1452
- changed: previousGeneration !== void 0 && nextGeneration !== void 0 && previousGeneration !== nextGeneration,
1453
- generation: nextGeneration
1607
+ if (canPublish !== void 0 && !canPublish(record.candidate)) continue;
1608
+ record.candidate = Object.freeze({ ...record.candidate, state: "published" });
1609
+ const receipt = Object.freeze({
1610
+ candidateId: record.candidate.candidateId,
1611
+ generation: record.candidate.generation,
1612
+ revision: record.candidate.revision,
1613
+ topologyRevision: record.candidate.topologyRevision,
1614
+ ...record.candidate.fixedStep === void 0 ? {} : { fixedStep: record.candidate.fixedStep },
1615
+ frameId: frame.frameId,
1616
+ deviceGeneration: frame.deviceGeneration,
1617
+ recordStageConsumed: canPublish !== void 0,
1618
+ ...fixedStep === void 0 ? {} : { publicationFixedStep: fixedStep },
1619
+ frame: Object.freeze({ ...frame })
1620
+ });
1621
+ receipts.push(receipt);
1622
+ publishedReceipts.set(record.candidate.candidateId, receipt);
1623
+ latestRevision = record.candidate.revision;
1624
+ latestFrameId = frame.frameId;
1625
+ if (!latestRevisionByWorld.has(record.world))
1626
+ latestRevisionByWorld.set(record.world, /* @__PURE__ */ new Map());
1627
+ latestRevisionByWorld.get(record.world)?.set(record.candidate.entity, record.candidate.revision);
1628
+ if (!latestTopologyRevisionByWorld.has(record.world))
1629
+ latestTopologyRevisionByWorld.set(record.world, /* @__PURE__ */ new Map());
1630
+ latestTopologyRevisionByWorld.get(record.world)?.set(record.candidate.entity, record.candidate.topologyRevision);
1631
+ }
1632
+ return receipts;
1633
+ },
1634
+ invalidateWorld(world, completion) {
1635
+ for (const [id, record] of records) {
1636
+ if (record.world !== world) continue;
1637
+ if (record.candidate.state === "cancelled" || record.candidate.state === "retired")
1638
+ continue;
1639
+ publishedReceipts.delete(id);
1640
+ record.candidate = Object.freeze({ ...record.candidate, state: "cancelled" });
1641
+ const release = () => {
1642
+ if (records.get(id) !== record) return;
1643
+ records.delete(id);
1644
+ meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
1645
+ };
1646
+ if (completion === void 0) release();
1647
+ else void completion.then(release, release);
1648
+ invalidated += 1;
1649
+ }
1650
+ latestRevisionByWorld.delete(world);
1651
+ latestTopologyRevisionByWorld.delete(world);
1652
+ },
1653
+ invalidateGeneration(generation) {
1654
+ if (generation === currentGeneration) return;
1655
+ currentGeneration = generation;
1656
+ const invalidatedWorlds = /* @__PURE__ */ new Set();
1657
+ for (const [id, record] of records) {
1658
+ if (record.candidate.generation !== generation) {
1659
+ records.delete(id);
1660
+ publishedReceipts.delete(id);
1661
+ meshBytes = Math.max(0, meshBytes - record.candidate.meshBytes);
1662
+ invalidatedWorlds.add(record.world);
1663
+ invalidated += 1;
1664
+ }
1665
+ }
1666
+ for (const world of invalidatedWorlds) {
1667
+ latestRevisionByWorld.delete(world);
1668
+ latestTopologyRevisionByWorld.delete(world);
1669
+ }
1670
+ },
1671
+ receipt(candidate) {
1672
+ const receipt = publishedReceipts.get(candidate.candidateId);
1673
+ const record = records.get(candidate.candidateId);
1674
+ if (record === void 0 || !sameCandidateCredential(candidate, record.candidate)) {
1675
+ return void 0;
1676
+ }
1677
+ return receipt?.generation === candidate.generation ? receipt : void 0;
1678
+ },
1679
+ inspect() {
1680
+ let prepared = 0;
1681
+ let accepted = 0;
1682
+ let published = 0;
1683
+ for (const record of records.values()) {
1684
+ if (record.candidate.state === "prepared") prepared += 1;
1685
+ else if (record.candidate.state === "accepted") accepted += 1;
1686
+ else if (record.candidate.state === "published") published += 1;
1687
+ }
1688
+ return Object.freeze({
1689
+ generation: currentGeneration,
1690
+ prepared,
1691
+ accepted,
1692
+ published,
1693
+ retired,
1694
+ ...latestRevision === void 0 ? {} : { latestRevision },
1695
+ ...latestFrameId === void 0 ? {} : { latestFrameId },
1696
+ historyInvalidations,
1697
+ invalidated,
1698
+ meshBytes,
1699
+ maxMeshBytes
1700
+ });
1701
+ },
1702
+ dispose() {
1703
+ disposed = true;
1704
+ records.clear();
1705
+ publishedReceipts.clear();
1706
+ meshBytes = 0;
1707
+ }
1454
1708
  };
1455
1709
  }
1456
1710
 
1457
- export { DEFAULT_REFLECTION_PROBE_LIMITS, DynamicGeometryError, LOD_OCCLUSION_INSPECTION_MAX_BYTES, LOD_OCCLUSION_INSPECTION_SCHEMA, ReflectionProbeProjection, SSR_FORMAT_PROFILE, SSR_FORMAT_STAGES, admitPointsLines, admitReflectionProbe, admitSsrM0, advanceProbeFilter, boxProjectReflectionDirection, buildCubeCameraFaceViews, buildReflectionProbeTable, commitProbeFilterStep, consumeLodOcclusionInspection, createDynamicGeometryLifecycle, createProbeFilterState, deriveReflectionFallbackProjection, estimateReflectionProbeBytes, inspectLodOcclusion, inspectPointShadow, inspectReflectionFallback, inspectVolumetricFog, probeFilterIsSteady, projectSsrDependencies, reflectionFallbackCoverage, reflectionFallbackProjectionSignature, reflectionFallbackSourceKey, reflectionProbeTableBytes, resolveReflectionFallbackSource, resolveSsrAdmissionGeneration, sameCandidateCredential, selectReflectionProbe, serializeLodOcclusionInspection, validateReflectionProbeInput, zeroSsrAdmissionWork };
1458
- //# sourceMappingURL=chunk-J52NMQKR.mjs.map
1459
- //# sourceMappingURL=chunk-J52NMQKR.mjs.map
1711
+ export { DEFAULT_REFLECTION_PROBE_LIMITS, DynamicGeometryError, LOD_OCCLUSION_INSPECTION_MAX_BYTES, LOD_OCCLUSION_INSPECTION_SCHEMA, ReflectionProbeProjection, SSR_FORMAT_PROFILE, SSR_FORMAT_STAGES, admitPointsLines, admitReflectionProbe, admitSsrM0, admitSsrSpatial, advanceProbeFilter, boxProjectReflectionDirection, buildReflectionProbeTable, commitProbeFilterStep, consumeLodOcclusionInspection, createDynamicGeometryLifecycle, createProbeFilterState, deriveReflectionFallbackProjection, estimateReflectionProbeBytes, inspectLodOcclusion, inspectPointShadow, inspectReflectionFallback, inspectVolumetricFog, probeFilterIsSteady, projectSsrDependencies, projectSsrSpatialInspection, reflectionFallbackCoverage, reflectionFallbackProjectionSignature, reflectionFallbackSourceKey, reflectionProbeTableBytes, resolveReflectionFallbackSource, resolveSsrAdmissionGeneration, sameCandidateCredential, selectReflectionProbe, serializeLodOcclusionInspection, serializeSsrSpatialInspection, validateReflectionProbeInput, validateScreenSpaceReflection, zeroSsrAdmissionWork };
1712
+ //# sourceMappingURL=chunk-7MQ3XBSP.mjs.map
1713
+ //# sourceMappingURL=chunk-7MQ3XBSP.mjs.map