@forgeax/engine-render 0.1.20 → 0.1.21

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 (372) hide show
  1. package/README.md +215 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/assembly/device-feature-admission.d.ts +18 -0
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  5. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  7. package/dist/assembly/factory.d.ts +21 -18
  8. package/dist/assembly/factory.d.ts.map +1 -1
  9. package/dist/assembly/host-contract.d.ts +9 -0
  10. package/dist/assembly/host-contract.d.ts.map +1 -1
  11. package/dist/assembly/render-target-host.d.ts +46 -0
  12. package/dist/assembly/render-target-host.d.ts.map +1 -0
  13. package/dist/assets/render-asset-port.d.ts.map +1 -1
  14. package/dist/authoring.mjs +3 -0
  15. package/dist/authoring.mjs.map +1 -1
  16. package/dist/capture/cube-views.d.ts +21 -0
  17. package/dist/capture/cube-views.d.ts.map +1 -0
  18. package/dist/capture/scheduler.d.ts +54 -0
  19. package/dist/capture/scheduler.d.ts.map +1 -0
  20. package/dist/{chunk-4XINDLAY.mjs → chunk-5YADUCA7.mjs} +1552 -1361
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-TBQJOK2L.mjs → chunk-6OPXDQ2E.mjs} +364 -51
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-M2MP4ZOU.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/{chunk-CDTWTHZR.mjs → chunk-FS2KNUQH.mjs} +548 -6
  27. package/dist/chunk-FS2KNUQH.mjs.map +1 -0
  28. package/dist/components/camera.d.ts +1 -0
  29. package/dist/components/camera.d.ts.map +1 -1
  30. package/dist/components/cube-camera.d.ts +20 -0
  31. package/dist/components/cube-camera.d.ts.map +1 -0
  32. package/dist/components/directional-light.d.ts +11 -2
  33. package/dist/components/directional-light.d.ts.map +1 -1
  34. package/dist/components/directional-shadow-filter.d.ts +25 -0
  35. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/light-helpers.d.ts.map +1 -1
  39. package/dist/components/reflection-probe.d.ts +17 -0
  40. package/dist/components/reflection-probe.d.ts.map +1 -0
  41. package/dist/construct-renderer.mjs +5826 -1003
  42. package/dist/construct-renderer.mjs.map +1 -1
  43. package/dist/environment/frame.d.ts.map +1 -1
  44. package/dist/environment/lifecycle.d.ts +5 -0
  45. package/dist/environment/lifecycle.d.ts.map +1 -1
  46. package/dist/errors/render.d.ts +141 -93
  47. package/dist/errors/render.d.ts.map +1 -1
  48. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  49. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  50. package/dist/extract/environment.d.ts +14 -0
  51. package/dist/extract/environment.d.ts.map +1 -1
  52. package/dist/extract/visibility.d.ts.map +1 -1
  53. package/dist/features/fullscreen.d.ts.map +1 -1
  54. package/dist/features/targets.d.ts.map +1 -1
  55. package/dist/features/types.d.ts +10 -0
  56. package/dist/features/types.d.ts.map +1 -1
  57. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  58. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  59. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  60. package/dist/gpu-driven/production-raster.d.ts +0 -1
  61. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  62. package/dist/gpu-scene.d.ts.map +1 -1
  63. package/dist/hdrp-buffers.d.ts +19 -17
  64. package/dist/hdrp-buffers.d.ts.map +1 -1
  65. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  66. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  67. package/dist/ibl/kernel-cache.d.ts +36 -0
  68. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  69. package/dist/index.d.ts +28 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.mjs +4 -4
  72. package/dist/index.mjs.map +1 -1
  73. package/dist/inspection-types.d.ts +51 -0
  74. package/dist/inspection-types.d.ts.map +1 -1
  75. package/dist/instances-derived-bounds.d.ts +50 -0
  76. package/dist/instances-derived-bounds.d.ts.map +1 -0
  77. package/dist/internal.mjs +1 -1
  78. package/dist/light-buffer-layout.d.ts +10 -1
  79. package/dist/light-buffer-layout.d.ts.map +1 -1
  80. package/dist/mesh-material-bindings.d.ts +54 -0
  81. package/dist/mesh-material-bindings.d.ts.map +1 -1
  82. package/dist/pbr-pipeline.d.ts +14 -4
  83. package/dist/pbr-pipeline.d.ts.map +1 -1
  84. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  85. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  86. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  87. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  88. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  89. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  90. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  91. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  92. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  93. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  95. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  97. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  99. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  101. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  103. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  104. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  105. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  106. package/dist/pipeline/standard-post.d.ts.map +1 -1
  107. package/dist/pipeline/standard-profile.d.ts +5 -26
  108. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  109. package/dist/pipeline-spec.d.ts +40 -7
  110. package/dist/pipeline-spec.d.ts.map +1 -1
  111. package/dist/point-shadow-inspection.d.ts +21 -0
  112. package/dist/point-shadow-inspection.d.ts.map +1 -0
  113. package/dist/record/frame-lighting.d.ts +27 -32
  114. package/dist/record/frame-lighting.d.ts.map +1 -1
  115. package/dist/record/frame-snapshot.d.ts +28 -14
  116. package/dist/record/frame-snapshot.d.ts.map +1 -1
  117. package/dist/record/frame-targets.d.ts +5 -0
  118. package/dist/record/frame-targets.d.ts.map +1 -1
  119. package/dist/record/frame.d.ts +10 -4
  120. package/dist/record/frame.d.ts.map +1 -1
  121. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  122. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  123. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  124. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  125. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  126. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  127. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  128. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  130. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  131. package/dist/record/gpu-timing.d.ts +8 -3
  132. package/dist/record/gpu-timing.d.ts.map +1 -1
  133. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  134. package/dist/record/main-pass-material.d.ts +22 -1
  135. package/dist/record/main-pass-material.d.ts.map +1 -1
  136. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  137. package/dist/record/main-pass.d.ts +2 -0
  138. package/dist/record/main-pass.d.ts.map +1 -1
  139. package/dist/record/render-context.d.ts +43 -2
  140. package/dist/record/render-context.d.ts.map +1 -1
  141. package/dist/record/shadow-pass.d.ts.map +1 -1
  142. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  143. package/dist/record/typed-frame-graph.d.ts +72 -4
  144. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  145. package/dist/record/view-ubo.d.ts +7 -4
  146. package/dist/record/view-ubo.d.ts.map +1 -1
  147. package/dist/reflection/filter.d.ts +22 -0
  148. package/dist/reflection/filter.d.ts.map +1 -0
  149. package/dist/reflection/gpu-table.d.ts +25 -0
  150. package/dist/reflection/gpu-table.d.ts.map +1 -0
  151. package/dist/reflection/projection.d.ts +91 -0
  152. package/dist/reflection/projection.d.ts.map +1 -0
  153. package/dist/render-contract.d.ts +49 -7
  154. package/dist/render-contract.d.ts.map +1 -1
  155. package/dist/render-graph-primitives.d.ts +1 -0
  156. package/dist/render-graph-primitives.d.ts.map +1 -1
  157. package/dist/render-pipeline.d.ts +42 -2
  158. package/dist/render-pipeline.d.ts.map +1 -1
  159. package/dist/render-system-extract.d.ts +58 -17
  160. package/dist/render-system-extract.d.ts.map +1 -1
  161. package/dist/render-system.d.ts +17 -2
  162. package/dist/render-system.d.ts.map +1 -1
  163. package/dist/renderer.d.ts +43 -0
  164. package/dist/renderer.d.ts.map +1 -0
  165. package/dist/scene/render-scene.d.ts +14 -0
  166. package/dist/scene/render-scene.d.ts.map +1 -1
  167. package/dist/shadow-atlas.d.ts +3 -3
  168. package/dist/shadow-atlas.d.ts.map +1 -1
  169. package/dist/ssao-buffers.d.ts +3 -0
  170. package/dist/ssao-buffers.d.ts.map +1 -1
  171. package/dist/targets/contracts.d.ts +66 -0
  172. package/dist/targets/contracts.d.ts.map +1 -0
  173. package/dist/targets/graph-projection.d.ts +29 -0
  174. package/dist/targets/graph-projection.d.ts.map +1 -0
  175. package/dist/targets/material-source.d.ts +34 -0
  176. package/dist/targets/material-source.d.ts.map +1 -0
  177. package/dist/targets/owner.d.ts +32 -0
  178. package/dist/targets/owner.d.ts.map +1 -0
  179. package/dist/targets/physical.d.ts +18 -0
  180. package/dist/targets/physical.d.ts.map +1 -0
  181. package/dist/targets/readback.d.ts +39 -0
  182. package/dist/targets/readback.d.ts.map +1 -0
  183. package/dist/temporal/index.mjs +3 -3
  184. package/dist/typed-render-graph-primitives.d.ts +1 -1
  185. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  186. package/dist/typed-shadow-passes.d.ts +1 -1
  187. package/dist/typed-shadow-passes.d.ts.map +1 -1
  188. package/dist/volume/passes.d.ts +2 -2
  189. package/dist/volume/passes.d.ts.map +1 -1
  190. package/package.json +20 -20
  191. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  192. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  193. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  194. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  195. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  196. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  197. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  198. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  199. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  200. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  201. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  202. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  203. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  204. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  205. package/src/__tests__/fog-component.unit.test.ts +67 -0
  206. package/src/__tests__/fog.integration.test.ts +86 -0
  207. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  208. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  209. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  210. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  211. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  212. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  213. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  214. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  215. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  216. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  217. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  218. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  219. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  220. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  221. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  222. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  223. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  224. package/src/__tests__/material-observation.integration.test.ts +101 -0
  225. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  226. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  227. package/src/__tests__/public-surface.test-d.ts +10 -0
  228. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  229. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  230. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  231. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  232. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  233. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  234. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  235. package/src/__tests__/render-error-code-owner.test-d.ts +18 -3
  236. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  237. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  238. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  239. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  240. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  241. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  242. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  243. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  244. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  245. package/src/__tests__/render-target-public-schema.json +107 -0
  246. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  247. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  248. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  249. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  250. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +48 -0
  251. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  252. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  253. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  254. package/src/__tests__/skinned-shadow-caster.test.ts +11 -2
  255. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  256. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  257. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  258. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  259. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  260. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  261. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  262. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  263. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  264. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  265. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  266. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -38
  267. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  268. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  269. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  270. package/src/assembly/device-feature-admission.ts +73 -0
  271. package/src/assembly/directional-shadow-inspection.ts +122 -0
  272. package/src/assembly/factory.ts +877 -286
  273. package/src/assembly/host-contract.ts +25 -0
  274. package/src/assembly/render-target-host.ts +847 -0
  275. package/src/assets/asset-decoders.ts +1 -1
  276. package/src/assets/render-asset-port.ts +7 -1
  277. package/src/capture/cube-views.ts +69 -0
  278. package/src/capture/scheduler.ts +265 -0
  279. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  280. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  281. package/src/components/camera.ts +4 -0
  282. package/src/components/cube-camera.ts +52 -0
  283. package/src/components/directional-light.ts +22 -2
  284. package/src/components/directional-shadow-filter.ts +57 -0
  285. package/src/components/index.ts +2 -0
  286. package/src/components/light-helpers.ts +81 -7
  287. package/src/components/reflection-probe.ts +49 -0
  288. package/src/environment/frame.ts +6 -24
  289. package/src/environment/lifecycle.ts +12 -0
  290. package/src/errors/render.ts +286 -142
  291. package/src/extract/directional-shadow-projection.ts +61 -0
  292. package/src/extract/environment.ts +57 -0
  293. package/src/extract/visibility.ts +25 -1
  294. package/src/features/fullscreen.ts +3 -0
  295. package/src/features/targets.ts +4 -1
  296. package/src/features/types.ts +10 -0
  297. package/src/fullscreen-post-process-pass.ts +43 -2
  298. package/src/gpu-driven/batch-topology.ts +1 -0
  299. package/src/gpu-driven/production-raster.ts +1 -3
  300. package/src/gpu-scene.ts +8 -1
  301. package/src/hdrp-buffers.ts +165 -59
  302. package/src/ibl/IblPipelineCache.ts +11 -0
  303. package/src/ibl/kernel-cache.ts +88 -0
  304. package/src/index.ts +148 -0
  305. package/src/inspection-types.ts +56 -0
  306. package/src/instances-derived-bounds.ts +171 -0
  307. package/src/light-buffer-layout.ts +20 -5
  308. package/src/mesh-material-bindings.ts +132 -0
  309. package/src/pbr-pipeline.ts +106 -17
  310. package/src/pipeline/standard-forward-lane.ts +46 -16
  311. package/src/pipeline/standard-lighting/errors.ts +6 -0
  312. package/src/pipeline/standard-lighting/graph.ts +157 -0
  313. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  314. package/src/pipeline/standard-lighting/layout.ts +31 -0
  315. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  316. package/src/pipeline/standard-lighting/membership.ts +43 -0
  317. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  318. package/src/pipeline/standard-lighting/topology.ts +120 -0
  319. package/src/pipeline/standard-lighting/transport.ts +77 -0
  320. package/src/pipeline/standard-pipeline.ts +122 -193
  321. package/src/pipeline/standard-post.ts +26 -7
  322. package/src/pipeline/standard-profile.ts +17 -47
  323. package/src/pipeline-spec.ts +84 -21
  324. package/src/point-shadow-inspection.ts +55 -0
  325. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  326. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  327. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  328. package/src/record/frame-lighting.ts +367 -427
  329. package/src/record/frame-snapshot.ts +35 -27
  330. package/src/record/frame-targets.ts +17 -0
  331. package/src/record/frame.ts +261 -74
  332. package/src/record/gpu-pass-timing/contract.ts +180 -0
  333. package/src/record/gpu-pass-timing/errors.ts +34 -0
  334. package/src/record/gpu-pass-timing/index.ts +37 -0
  335. package/src/record/gpu-pass-timing/parser.ts +97 -0
  336. package/src/record/gpu-pass-timing/session.ts +938 -0
  337. package/src/record/gpu-timing.ts +21 -12
  338. package/src/record/main-pass-geometry.ts +120 -80
  339. package/src/record/main-pass-material.ts +95 -9
  340. package/src/record/main-pass-sprite-draws.ts +54 -25
  341. package/src/record/main-pass.ts +71 -15
  342. package/src/record/render-context.ts +72 -0
  343. package/src/record/shadow-pass.ts +17 -28
  344. package/src/record/skybox-post-pass.ts +20 -4
  345. package/src/record/typed-frame-graph.ts +893 -44
  346. package/src/record/view-ubo.ts +63 -28
  347. package/src/reflection/filter.ts +81 -0
  348. package/src/reflection/gpu-table.ts +44 -0
  349. package/src/reflection/projection.ts +281 -0
  350. package/src/render-contract.ts +76 -5
  351. package/src/render-graph-primitives.ts +9 -4
  352. package/src/render-pipeline.ts +117 -2
  353. package/src/render-system-extract.ts +557 -100
  354. package/src/render-system.ts +1095 -66
  355. package/src/renderer.ts +222 -0
  356. package/src/scene/render-scene.ts +115 -9
  357. package/src/shadow-atlas.ts +5 -5
  358. package/src/ssao-buffers.ts +9 -2
  359. package/src/targets/contracts.ts +182 -0
  360. package/src/targets/graph-projection.ts +169 -0
  361. package/src/targets/material-source.ts +143 -0
  362. package/src/targets/owner.ts +214 -0
  363. package/src/targets/physical.ts +18 -0
  364. package/src/targets/readback.ts +153 -0
  365. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
  366. package/src/typed-render-graph-primitives.ts +5 -3
  367. package/src/typed-shadow-passes.ts +46 -40
  368. package/src/volume/passes.ts +15 -9
  369. package/dist/chunk-4XINDLAY.mjs.map +0 -1
  370. package/dist/chunk-CDTWTHZR.mjs.map +0 -1
  371. package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
  372. package/dist/chunk-TBQJOK2L.mjs.map +0 -1
@@ -1,8 +1,10 @@
1
- import { PointsLinesBudgetExceededError, VolumeOwnerConflictError, VolumeDensityShapeMismatchError, VolumeInvalidBoundsError, VolumeInvalidParametersError, PointsLinesStyleUnsupportedError, PointsLinesMaterialUnsupportedError, PointsLinesInvalidStyleError, PointsLinesTopologyMismatchError } from './chunk-TBQJOK2L.mjs';
1
+ import { RenderIntentInvalidError, PointsLinesBudgetExceededError, VolumeOwnerConflictError, VolumeDensityShapeMismatchError, VolumeInvalidBoundsError, VolumeInvalidParametersError, PointsLinesStyleUnsupportedError, PointsLinesMaterialUnsupportedError, PointsLinesInvalidStyleError, PointsLinesTopologyMismatchError } from './chunk-6OPXDQ2E.mjs';
2
2
  import { defineComponent, Entity } from '@forgeax/engine-ecs';
3
3
  import { TONEMAP_SHADER_MODE } from '@forgeax/engine-shader';
4
4
  import { err, ok } from '@forgeax/engine-types';
5
+ import { mat4 } from '@forgeax/engine-math';
5
6
  import { Transform, projectHierarchy } from '@forgeax/engine-scene';
7
+ import { createWorldProjection } from '@forgeax/engine-ecs/projection';
6
8
 
7
9
  var Atmosphere = defineComponent("Atmosphere", {
8
10
  turbidity: { type: "f32", default: 2 },
@@ -106,6 +108,10 @@ var Camera = defineComponent("Camera", {
106
108
  bloomThreshold: { type: "f32", default: 1 },
107
109
  bloomIntensity: { type: "f32", default: 1 },
108
110
  bloomBlurRadius: { type: "f32", default: 4 },
111
+ // M1 target camera role: zero means this camera is eligible for display;
112
+ // non-zero shared targets are auxiliary producers whose views and receipt
113
+ // promotion remain owned by Renderer.
114
+ target: { type: "shared<RenderTarget>", simulationTransient: true },
109
115
  // feat-20260709 M3 / D-3: clear-color is one inline `array<f32,4>` column.
110
116
  // The earlier 4-scalar form (clearR/G/B/A) was chosen when this was believed
111
117
  // to be the only SoA-safe shape; the Transform (pos/quat/scale) and light
@@ -165,6 +171,75 @@ function orthographic(opts) {
165
171
  top: opts.top
166
172
  };
167
173
  }
174
+ var CUBE_CAMERA_UPDATE_ONCE = 0;
175
+ var CUBE_CAMERA_UPDATE_ON_DEMAND = 1;
176
+ var CUBE_CAMERA_UPDATE_CONTINUOUS = 2;
177
+ var CUBE_CAMERA_FACE_ORDER = ["+X", "-X", "+Y", "-Y", "+Z", "-Z"];
178
+ function cubeCameraUpdateIntentFromF32(value) {
179
+ switch (value) {
180
+ case CUBE_CAMERA_UPDATE_ONCE:
181
+ return "once";
182
+ case CUBE_CAMERA_UPDATE_ON_DEMAND:
183
+ return "on-demand";
184
+ case CUBE_CAMERA_UPDATE_CONTINUOUS:
185
+ return "continuous";
186
+ default:
187
+ throw new RenderIntentInvalidError("CubeCamera", value);
188
+ }
189
+ }
190
+ function cubeCameraUpdateIntentToF32(intent) {
191
+ switch (intent) {
192
+ case "once":
193
+ return CUBE_CAMERA_UPDATE_ONCE;
194
+ case "on-demand":
195
+ return CUBE_CAMERA_UPDATE_ON_DEMAND;
196
+ case "continuous":
197
+ return CUBE_CAMERA_UPDATE_CONTINUOUS;
198
+ }
199
+ }
200
+ var CubeCamera = defineComponent("CubeCamera", {
201
+ target: { type: "shared<RenderTarget>", simulationTransient: true },
202
+ near: { type: "f32", default: 0.1 },
203
+ far: { type: "f32", default: 100 },
204
+ updateIntent: { type: "f32", default: CUBE_CAMERA_UPDATE_ONCE },
205
+ requestVersion: { type: "u32", default: 0 },
206
+ faceBudget: { type: "u32", default: 1 }
207
+ });
208
+
209
+ // src/components/directional-shadow-filter.ts
210
+ var DirectionalShadowFilterValue = Object.freeze({
211
+ pcf1: 1,
212
+ pcf3: 2,
213
+ pcf5: 3,
214
+ pcssMedium: 4,
215
+ pcssHigh: 5
216
+ });
217
+ function directionalShadowQualityFromF32(value, angularRadiusRadians, maxPenumbraTexels) {
218
+ switch (value) {
219
+ case DirectionalShadowFilterValue.pcf1:
220
+ return { kind: "pcf", kernel: 1 };
221
+ case DirectionalShadowFilterValue.pcf3:
222
+ return { kind: "pcf", kernel: 3 };
223
+ case DirectionalShadowFilterValue.pcf5:
224
+ return { kind: "pcf", kernel: 5 };
225
+ case DirectionalShadowFilterValue.pcssMedium:
226
+ return {
227
+ kind: "pcss",
228
+ preset: "medium",
229
+ angularRadiusRadians,
230
+ maxPenumbraTexels
231
+ };
232
+ case DirectionalShadowFilterValue.pcssHigh:
233
+ return {
234
+ kind: "pcss",
235
+ preset: "high",
236
+ angularRadiusRadians,
237
+ maxPenumbraTexels
238
+ };
239
+ default:
240
+ return void 0;
241
+ }
242
+ }
168
243
  var DirectionalLight = defineComponent("DirectionalLight", {
169
244
  // direction is the ONLY field with no default (D-5): omitting it lands the
170
245
  // array layer-3 all-zero [0,0,0], which the renderer owner rejects -- there is no
@@ -188,7 +263,13 @@ var DirectionalLight = defineComponent("DirectionalLight", {
188
263
  // reach. Default 200 world units (matches UE-style "dynamic shadow
189
264
  // distance"; the old farPlane default was 50).
190
265
  shadowDistance: { type: "f32", default: 200 },
191
- pcfKernelSize: { type: "f32", default: 3 }
266
+ shadowFilter: {
267
+ type: "enum",
268
+ default: DirectionalShadowFilterValue.pcf3,
269
+ labels: DirectionalShadowFilterValue
270
+ },
271
+ shadowAngularRadius: { type: "f32", default: 465e-5 },
272
+ maxPenumbraTexels: { type: "f32", default: 32 }
192
273
  });
193
274
  var Fog = defineComponent("Fog", {
194
275
  color: { type: "array<f32, 3>", default: new Float32Array([0.5, 0.5, 0.5]) },
@@ -276,6 +357,39 @@ var schema = {
276
357
  data: "buffer"
277
358
  };
278
359
  var PostProcessParams = defineComponent("PostProcessParams", schema);
360
+ var REFLECTION_PROBE_UPDATE_ONCE = 0;
361
+ var REFLECTION_PROBE_UPDATE_ON_CHANGE = 1;
362
+ var REFLECTION_PROBE_UPDATE_CONTINUOUS = 2;
363
+ function reflectionProbeUpdateIntentFromF32(value) {
364
+ switch (value) {
365
+ case REFLECTION_PROBE_UPDATE_ONCE:
366
+ return "once";
367
+ case REFLECTION_PROBE_UPDATE_ON_CHANGE:
368
+ return "on-change";
369
+ case REFLECTION_PROBE_UPDATE_CONTINUOUS:
370
+ return "continuous";
371
+ default:
372
+ throw new RenderIntentInvalidError("ReflectionProbe", value);
373
+ }
374
+ }
375
+ function reflectionProbeUpdateIntentToF32(intent) {
376
+ switch (intent) {
377
+ case "once":
378
+ return REFLECTION_PROBE_UPDATE_ONCE;
379
+ case "on-change":
380
+ return REFLECTION_PROBE_UPDATE_ON_CHANGE;
381
+ case "continuous":
382
+ return REFLECTION_PROBE_UPDATE_CONTINUOUS;
383
+ }
384
+ }
385
+ var ReflectionProbe = defineComponent("ReflectionProbe", {
386
+ halfExtents: { type: "array<f32, 3>", default: new Float32Array([1, 1, 1]) },
387
+ priority: { type: "f32", default: 0 },
388
+ intensity: { type: "f32", default: 1 },
389
+ resolution: { type: "u32", default: 256 },
390
+ updateIntent: { type: "f32", default: REFLECTION_PROBE_UPDATE_ONCE },
391
+ invalidationVersion: { type: "u32", default: 0 }
392
+ });
279
393
  var SceneInstance = defineComponent(
280
394
  "SceneInstance",
281
395
  {
@@ -542,6 +656,179 @@ function inspectVolumetricFog(input) {
542
656
  candidateSelectedLight: recovery?.candidateSelectedLight
543
657
  });
544
658
  }
659
+ var FACE_ORIENTATION = [
660
+ { direction: [1, 0, 0], up: [0, 1, 0] },
661
+ { direction: [-1, 0, 0], up: [0, 1, 0] },
662
+ { direction: [0, 1, 0], up: [0, 0, -1] },
663
+ { direction: [0, -1, 0], up: [0, 0, 1] },
664
+ { direction: [0, 0, 1], up: [0, 1, 0] },
665
+ { direction: [0, 0, -1], up: [0, 1, 0] }
666
+ ];
667
+ function assertRange(near, far) {
668
+ if (!Number.isFinite(near) || near <= 0 || !Number.isFinite(far) || far <= near) {
669
+ throw new RangeError("CubeCamera requires finite near > 0 and far > near.");
670
+ }
671
+ }
672
+ function buildCubeCameraFaceViews(input) {
673
+ assertRange(input.near, input.far);
674
+ const views = [];
675
+ for (const [index, face] of CUBE_CAMERA_FACE_ORDER.entries()) {
676
+ const orientation = FACE_ORIENTATION[index];
677
+ if (orientation === void 0)
678
+ throw new Error(`CubeCamera face orientation missing at ${index}`);
679
+ const target = [
680
+ (input.position[0] ?? 0) + orientation.direction[0],
681
+ (input.position[1] ?? 0) + orientation.direction[1],
682
+ (input.position[2] ?? 0) + orientation.direction[2]
683
+ ];
684
+ const view = mat4.lookAt(mat4.create(), input.position, target, orientation.up);
685
+ const projection = mat4.perspective(mat4.create(), Math.PI / 2, 1, input.near, input.far);
686
+ const viewProjection = mat4.multiply(mat4.create(), projection, view);
687
+ views.push({
688
+ position: input.position,
689
+ face,
690
+ direction: orientation.direction,
691
+ up: orientation.up,
692
+ near: input.near,
693
+ far: input.far,
694
+ view,
695
+ projection,
696
+ viewProjection
697
+ });
698
+ }
699
+ return views;
700
+ }
701
+
702
+ // src/mesh-material-bindings.ts
703
+ var EMPTY_RESIDENCY = Object.freeze({
704
+ readiness: "pending",
705
+ samplers: Object.freeze([]),
706
+ textures: Object.freeze([])
707
+ });
708
+ function projectMeshMaterialBindingObservation(input) {
709
+ const residency = input.bindings.map((_, index) => {
710
+ const value = input.residency?.[index] ?? EMPTY_RESIDENCY;
711
+ return Object.freeze({
712
+ ...value,
713
+ samplers: Object.freeze(value.samplers.map((sampler) => Object.freeze({ ...sampler }))),
714
+ textures: Object.freeze(value.textures.map((texture) => Object.freeze({ ...texture }))),
715
+ ...value.preparationFailure === void 0 ? {} : {
716
+ preparationFailure: Object.freeze({
717
+ ...value.preparationFailure,
718
+ ...value.preparationFailure.detail === void 0 ? {} : { detail: Object.freeze({ ...value.preparationFailure.detail }) }
719
+ })
720
+ }
721
+ });
722
+ });
723
+ return {
724
+ worldId: input.worldId,
725
+ entityKey: input.entityKey,
726
+ bindings: Object.freeze([...input.bindings]),
727
+ diagnostics: Object.freeze([...input.diagnostics]),
728
+ residency: Object.freeze(residency)
729
+ };
730
+ }
731
+ function summarizeMeshMaterialBindings(observations) {
732
+ let ready = 0;
733
+ let pending = 0;
734
+ let failed = 0;
735
+ let lastKnownGood = 0;
736
+ let textureCount = 0;
737
+ let samplerCount = 0;
738
+ for (const observation of observations) {
739
+ for (const residency of observation.residency) {
740
+ switch (residency.readiness) {
741
+ case "ready":
742
+ ready += 1;
743
+ break;
744
+ case "pending":
745
+ pending += 1;
746
+ break;
747
+ case "failed":
748
+ failed += 1;
749
+ break;
750
+ case "last-known-good":
751
+ lastKnownGood += 1;
752
+ break;
753
+ }
754
+ textureCount += residency.textures.length;
755
+ samplerCount += residency.samplers.length;
756
+ }
757
+ }
758
+ return {
759
+ total: ready + pending + failed + lastKnownGood,
760
+ ready,
761
+ pending,
762
+ failed,
763
+ lastKnownGood,
764
+ textureCount,
765
+ samplerCount
766
+ };
767
+ }
768
+ function resolveMeshMaterialBindings(mesh, rendererOverrides, deps) {
769
+ const bindings = [];
770
+ const diagnostics = [];
771
+ if (!Array.isArray(mesh.materialSlots)) {
772
+ return { ok: false, code: "mesh-material-slots-missing" };
773
+ }
774
+ if (rendererOverrides.length > mesh.materialSlots.length) {
775
+ diagnostics.push({
776
+ code: "mesh-renderer-material-override-overflow",
777
+ slotIndex: mesh.materialSlots.length
778
+ });
779
+ }
780
+ for (let slotIndex = 0; slotIndex < mesh.materialSlots.length; slotIndex++) {
781
+ const override = rendererOverrides[slotIndex] ?? 0;
782
+ if (override !== 0 && deps.isValidOverride(override)) {
783
+ bindings.push({ handle: override, source: "renderer-override" });
784
+ continue;
785
+ }
786
+ if (override !== 0) {
787
+ diagnostics.push({
788
+ code: "mesh-renderer-material-override-invalid",
789
+ slotIndex,
790
+ handle: override
791
+ });
792
+ }
793
+ const declaredDefault = mesh.materialSlots[slotIndex]?.defaultMaterial;
794
+ if (declaredDefault !== void 0) {
795
+ const handle = deps.resolveMeshDefault(declaredDefault);
796
+ if (handle === void 0) {
797
+ return {
798
+ ok: false,
799
+ code: "mesh-default-material-not-ready",
800
+ slotIndex,
801
+ defaultMaterial: declaredDefault
802
+ };
803
+ }
804
+ bindings.push({ handle, source: "mesh-default" });
805
+ continue;
806
+ }
807
+ bindings.push({ handle: 0, source: "engine-default" });
808
+ }
809
+ return { ok: true, bindings, diagnostics };
810
+ }
811
+
812
+ // src/point-shadow-inspection.ts
813
+ function inspectPointShadow(snapshots, shadowAtlasCapacity) {
814
+ const requested = snapshots.length;
815
+ const admitted = snapshots.reduce(
816
+ (count, snapshot) => snapshot.shadowAtlasLayer >= 0 && snapshot.shadowAtlasLayer < shadowAtlasCapacity ? count + 1 : count,
817
+ 0
818
+ );
819
+ const status = requested === 0 ? "inactive" : requested > shadowAtlasCapacity || admitted !== requested ? "over-budget" : "ready";
820
+ return Object.freeze({
821
+ status,
822
+ requested,
823
+ admitted,
824
+ // A point shadow only samples an atlas after it owns an atlas layer. Keep
825
+ // these names explicit for AI diagnostics while deriving both from the
826
+ // one layer projection above.
827
+ shadowed: admitted,
828
+ shadowAtlasOccupancy: admitted,
829
+ shadowAtlasCapacity
830
+ });
831
+ }
545
832
  function hasVolumetricFogCapability(caps, shaders) {
546
833
  return caps.compute && caps.storageTexture && shaders !== void 0;
547
834
  }
@@ -628,7 +915,260 @@ function resolveSelectedVolumetricLight(world, entity) {
628
915
  function resolveIntegratedVolumeConsumer(resource, consumer) {
629
916
  return { consumer, resource };
630
917
  }
918
+
919
+ // src/reflection/filter.ts
920
+ function createProbeFilterState(input) {
921
+ return {
922
+ probeIndex: input.probeIndex,
923
+ faceCount: input.faceCount ?? 6,
924
+ mipCount: input.mipCount,
925
+ cursor: 0,
926
+ activeGeneration: input.activeGeneration ?? 0
927
+ };
928
+ }
929
+ function advanceProbeFilter(state) {
930
+ const total = state.faceCount * state.mipCount;
931
+ if (state.cursor >= total) return void 0;
932
+ return {
933
+ probeIndex: state.probeIndex,
934
+ faceIndex: state.cursor % state.faceCount,
935
+ mipLevel: Math.floor(state.cursor / state.faceCount)
936
+ };
937
+ }
938
+ function commitProbeFilterStep(state, success) {
939
+ if (!success) return state;
940
+ const nextCursor = state.cursor + 1;
941
+ const complete = nextCursor >= state.faceCount * state.mipCount;
942
+ return {
943
+ ...state,
944
+ cursor: nextCursor,
945
+ activeGeneration: complete ? state.activeGeneration + 1 : state.activeGeneration
946
+ };
947
+ }
948
+ function probeFilterIsSteady(state) {
949
+ return state.cursor >= state.faceCount * state.mipCount;
950
+ }
951
+ function normalize(vector) {
952
+ const length = Math.hypot(vector[0], vector[1], vector[2]);
953
+ if (length === 0) return [0, 0, 1];
954
+ return [vector[0] / length, vector[1] / length, vector[2] / length];
955
+ }
956
+ function boxProjectReflectionDirection(direction, boxCenter, halfExtents, point) {
957
+ const ray = normalize(direction);
958
+ let distance = Number.POSITIVE_INFINITY;
959
+ for (let axis = 0; axis < 3; axis += 1) {
960
+ const component = ray[axis] ?? 0;
961
+ if (component === 0) continue;
962
+ const extent = halfExtents[axis] ?? 0;
963
+ const edge = component > 0 ? (boxCenter[axis] ?? 0) + extent : (boxCenter[axis] ?? 0) - extent;
964
+ const candidate = (edge - (point[axis] ?? 0)) / component;
965
+ if (candidate > 0) distance = Math.min(distance, candidate);
966
+ }
967
+ if (!Number.isFinite(distance)) return ray;
968
+ return normalize([
969
+ (point[0] ?? 0) + ray[0] * distance - (boxCenter[0] ?? 0),
970
+ (point[1] ?? 0) + ray[1] * distance - (boxCenter[1] ?? 0),
971
+ (point[2] ?? 0) + ray[2] * distance - (boxCenter[2] ?? 0)
972
+ ]);
973
+ }
974
+
975
+ // src/reflection/gpu-table.ts
976
+ function buildReflectionProbeTable(rows) {
977
+ const ordered = rows.slice().sort((a, b) => a.index - b.index);
978
+ const indices = /* @__PURE__ */ new Map();
979
+ for (const row of ordered) {
980
+ if (row.primitiveKey !== void 0) indices.set(row.primitiveKey, row.index);
981
+ }
982
+ const indexFor = (primitiveKey2) => indices.get(primitiveKey2);
983
+ return {
984
+ rows: Object.freeze(ordered),
985
+ cpuIndexByPrimitive: indexFor,
986
+ gpuIndexByPrimitive: indexFor
987
+ };
988
+ }
989
+ function reflectionProbeTableBytes(table) {
990
+ return table.rows.length * 48;
991
+ }
992
+
993
+ // src/reflection/projection.ts
994
+ var REFLECTION_PROBE_BYTES_PER_TEXEL = 8;
995
+ var DEFAULT_REFLECTION_PROBE_LIMITS = Object.freeze({
996
+ maxProbes: 16,
997
+ maxResolution: 256,
998
+ maxBytes: 64 * 1024 * 1024
999
+ });
1000
+ function validateReflectionProbeInput(input) {
1001
+ for (let index = 0; index < input.halfExtents.length; index += 1) {
1002
+ const value = input.halfExtents[index];
1003
+ if (value === void 0 || !Number.isFinite(value) || value <= 0) {
1004
+ return {
1005
+ ok: false,
1006
+ error: {
1007
+ code: "reflection-probe-input-invalid",
1008
+ field: `halfExtents[${index}]`,
1009
+ value,
1010
+ expected: "a finite number greater than zero"
1011
+ }
1012
+ };
1013
+ }
1014
+ }
1015
+ if (!Number.isFinite(input.priority)) {
1016
+ return {
1017
+ ok: false,
1018
+ error: {
1019
+ code: "reflection-probe-input-invalid",
1020
+ field: "priority",
1021
+ value: input.priority,
1022
+ expected: "a finite number"
1023
+ }
1024
+ };
1025
+ }
1026
+ if (!Number.isFinite(input.intensity) || input.intensity < 0) {
1027
+ return {
1028
+ ok: false,
1029
+ error: {
1030
+ code: "reflection-probe-input-invalid",
1031
+ field: "intensity",
1032
+ value: input.intensity,
1033
+ expected: "a finite number greater than or equal to zero"
1034
+ }
1035
+ };
1036
+ }
1037
+ if (!Number.isInteger(input.resolution) || input.resolution <= 0) {
1038
+ return {
1039
+ ok: false,
1040
+ error: {
1041
+ code: "reflection-probe-input-invalid",
1042
+ field: "resolution",
1043
+ value: input.resolution,
1044
+ expected: "a positive integer"
1045
+ }
1046
+ };
1047
+ }
1048
+ return { ok: true };
1049
+ }
1050
+ function estimateReflectionProbeBytes(resolution, limits = DEFAULT_REFLECTION_PROBE_LIMITS) {
1051
+ const maxResolution = limits.maxResolution ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxResolution;
1052
+ const clamped = Math.min(resolution, maxResolution);
1053
+ let mipTexels = 0;
1054
+ for (let size = clamped; size >= 1; size = Math.floor(size / 2)) {
1055
+ mipTexels += size * size;
1056
+ }
1057
+ return mipTexels * 6 * REFLECTION_PROBE_BYTES_PER_TEXEL;
1058
+ }
1059
+ function admitReflectionProbe(input, current, limits = DEFAULT_REFLECTION_PROBE_LIMITS) {
1060
+ const maxProbes = limits.maxProbes ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxProbes;
1061
+ const maxBytes = limits.maxBytes ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxBytes;
1062
+ const maxResolution = limits.maxResolution ?? DEFAULT_REFLECTION_PROBE_LIMITS.maxResolution;
1063
+ const requested = estimateReflectionProbeBytes(input.resolution, { maxResolution });
1064
+ if (input.resolution > maxResolution || current.acceptedCount >= maxProbes || current.acceptedBytes + requested > maxBytes) {
1065
+ return {
1066
+ ok: false,
1067
+ error: {
1068
+ code: "reflection-probe-budget-exceeded",
1069
+ requested,
1070
+ activeCount: current.acceptedCount,
1071
+ activeBytes: current.acceptedBytes,
1072
+ maxProbes,
1073
+ maxBytes
1074
+ }
1075
+ };
1076
+ }
1077
+ return { ok: true, acceptedBytes: current.acceptedBytes + requested };
1078
+ }
1079
+ function contains(fact, point) {
1080
+ return fact.halfExtents.every((extent, axis) => {
1081
+ const center = fact.center[axis] ?? 0;
1082
+ const coordinate = point[axis] ?? 0;
1083
+ return Math.abs(coordinate - center) <= extent;
1084
+ });
1085
+ }
1086
+ function normalizedDistance(fact, point) {
1087
+ let squared = 0;
1088
+ for (let axis = 0; axis < 3; axis += 1) {
1089
+ const delta = (point[axis] ?? 0) - (fact.center[axis] ?? 0);
1090
+ const extent = fact.halfExtents[axis] ?? 1;
1091
+ squared += (delta / extent) ** 2;
1092
+ }
1093
+ return squared;
1094
+ }
1095
+ function isBetter(candidate, current, facts) {
1096
+ const candidateFact = facts.find(
1097
+ (fact) => fact.worldId === candidate.worldId && fact.entityKey === candidate.entityKey
1098
+ );
1099
+ const currentFact = facts.find(
1100
+ (fact) => fact.worldId === current.worldId && fact.entityKey === current.entityKey
1101
+ );
1102
+ if (candidateFact === void 0 || currentFact === void 0) return false;
1103
+ if (candidateFact.priority !== currentFact.priority)
1104
+ return candidateFact.priority > currentFact.priority;
1105
+ if (candidate.normalizedDistance !== current.normalizedDistance) {
1106
+ return candidate.normalizedDistance < current.normalizedDistance;
1107
+ }
1108
+ return candidate.worldId < current.worldId || candidate.worldId === current.worldId && candidate.entityKey < current.entityKey;
1109
+ }
1110
+ function selectReflectionProbe(facts, primitiveCenter) {
1111
+ let selected;
1112
+ for (const fact of facts) {
1113
+ if (!contains(fact, primitiveCenter)) continue;
1114
+ const candidate = {
1115
+ kind: "probe",
1116
+ worldId: fact.worldId,
1117
+ entityKey: fact.entityKey,
1118
+ normalizedDistance: normalizedDistance(fact, primitiveCenter)
1119
+ };
1120
+ if (selected === void 0 || isBetter(candidate, selected, facts)) selected = candidate;
1121
+ }
1122
+ return selected ?? { kind: "skylight" };
1123
+ }
1124
+ function primitiveKey(worldId, entityKey) {
1125
+ return `${worldId}:${entityKey}`;
1126
+ }
1127
+ var ReflectionProbeProjection = class {
1128
+ revision = 0;
1129
+ facts = [];
1130
+ selected = /* @__PURE__ */ new Map();
1131
+ signature = "";
1132
+ scannedPrimitives = 0;
1133
+ update(facts, primitives) {
1134
+ const nextFacts = facts.slice().sort((a, b) => a.worldId - b.worldId || a.entityKey - b.entityKey);
1135
+ const signature = JSON.stringify({ facts: nextFacts, primitives });
1136
+ if (signature === this.signature) return this.snapshot();
1137
+ this.signature = signature;
1138
+ this.facts = nextFacts;
1139
+ this.selected = /* @__PURE__ */ new Map();
1140
+ for (const primitive of primitives) {
1141
+ this.selected.set(
1142
+ primitiveKey(primitive.worldId, primitive.entityKey),
1143
+ selectReflectionProbe(nextFacts, primitive.center)
1144
+ );
1145
+ }
1146
+ this.scannedPrimitives = primitives.length;
1147
+ this.revision += 1;
1148
+ return this.snapshot();
1149
+ }
1150
+ snapshot() {
1151
+ return {
1152
+ revision: this.revision,
1153
+ facts: this.facts,
1154
+ selected: this.selected,
1155
+ scannedPrimitives: this.scannedPrimitives
1156
+ };
1157
+ }
1158
+ selection(worldId, entityKey) {
1159
+ return this.selected.get(primitiveKey(worldId, entityKey)) ?? { kind: "skylight" };
1160
+ }
1161
+ };
1162
+ var VISIBILITY_CACHE = /* @__PURE__ */ new WeakMap();
631
1163
  function resolveVisibility(world, hierarchy = projectHierarchy(world)) {
1164
+ const cached = VISIBILITY_CACHE.get(world);
1165
+ const changes = cached?.changes ?? createWorldProjection(world, { components: [Visibility] });
1166
+ if (cached !== void 0) {
1167
+ const evidence = changes.poll();
1168
+ if (evidence.status === "delta" && evidence.changes.length === 0 && cached.hierarchy === hierarchy) {
1169
+ return cached.snapshot;
1170
+ }
1171
+ }
632
1172
  const query = world.query({ read: [Visibility] });
633
1173
  const visitVisibilityRows = (visit) => {
634
1174
  if (!query.ok) return;
@@ -689,7 +1229,7 @@ function resolveVisibility(world, hierarchy = projectHierarchy(world)) {
689
1229
  return result;
690
1230
  };
691
1231
  };
692
- return {
1232
+ const snapshot = {
693
1233
  diagnostics: hierarchy.diagnostics,
694
1234
  hasAnyIntent: intentCount > 0,
695
1235
  hasAnyHiddenIntent,
@@ -702,6 +1242,8 @@ function resolveVisibility(world, hierarchy = projectHierarchy(world)) {
702
1242
  return resolveEntity?.(entity)?.effective ?? "visible";
703
1243
  }
704
1244
  };
1245
+ VISIBILITY_CACHE.set(world, { changes, hierarchy, snapshot });
1246
+ return snapshot;
705
1247
  }
706
1248
  var VolumetricFog = defineComponent("VolumetricFog", {
707
1249
  light: { type: "entity" },
@@ -747,6 +1289,6 @@ function extractVolumetricFog(inputs) {
747
1289
  return ok({ status: "available", fog: validated.value });
748
1290
  }
749
1291
 
750
- export { ANTIALIAS_FXAA, ANTIALIAS_MSAA, ANTIALIAS_NONE, ANTIALIAS_TAA, Atmosphere, BLOOM_DISABLED, BLOOM_ENABLED, CAMERA_PROJECTION_ORTHOGRAPHIC, CAMERA_PROJECTION_PERSPECTIVE, Camera, DirectionalLight, Fog, Instances, Layer, Lines, MeshFilter, MeshRenderer, MotionBlur, PointLight, PointLightShadow, PointShapeValue, Points, PostProcessParams, SKYBOX_MODE_CUBEMAP, SceneInstance, SkyboxBackground, Skylight, SortKey, SpotLight, TONEMAP_ACES_FILMIC, TONEMAP_AGX, TONEMAP_CINEON, TONEMAP_LINEAR, TONEMAP_NEUTRAL, TONEMAP_NONE, TONEMAP_REINHARD, TONEMAP_REINHARD_EXTENDED, Visibility, VisibilityStateValue, VolumetricFog, admitPointsLines, antialiasFromF32, bloomEnabledFromF32, cameraProjectionFromF32, extractVolumetricFog, hasVolumetricFogCapability, inspectVolumetricFog, orthographic, perspective, pointShapeFromU32, resolveIntegratedVolumeConsumer, resolveSelectedVolumetricLight, resolveVisibility, resolveVolumetricFogLightPair, tonemapFromF32, tonemapToU32, validateVolumetricFog, visibilityStateFromU32 };
751
- //# sourceMappingURL=chunk-CDTWTHZR.mjs.map
752
- //# sourceMappingURL=chunk-CDTWTHZR.mjs.map
1292
+ export { ANTIALIAS_FXAA, ANTIALIAS_MSAA, ANTIALIAS_NONE, ANTIALIAS_TAA, Atmosphere, BLOOM_DISABLED, BLOOM_ENABLED, CAMERA_PROJECTION_ORTHOGRAPHIC, CAMERA_PROJECTION_PERSPECTIVE, CUBE_CAMERA_FACE_ORDER, CUBE_CAMERA_UPDATE_CONTINUOUS, CUBE_CAMERA_UPDATE_ONCE, CUBE_CAMERA_UPDATE_ON_DEMAND, Camera, CubeCamera, DEFAULT_REFLECTION_PROBE_LIMITS, DirectionalLight, DirectionalShadowFilterValue, Fog, Instances, Layer, Lines, MeshFilter, MeshRenderer, MotionBlur, PointLight, PointLightShadow, PointShapeValue, Points, PostProcessParams, REFLECTION_PROBE_UPDATE_CONTINUOUS, REFLECTION_PROBE_UPDATE_ONCE, REFLECTION_PROBE_UPDATE_ON_CHANGE, ReflectionProbe, ReflectionProbeProjection, SKYBOX_MODE_CUBEMAP, SceneInstance, SkyboxBackground, Skylight, SortKey, SpotLight, TONEMAP_ACES_FILMIC, TONEMAP_AGX, TONEMAP_CINEON, TONEMAP_LINEAR, TONEMAP_NEUTRAL, TONEMAP_NONE, TONEMAP_REINHARD, TONEMAP_REINHARD_EXTENDED, Visibility, VisibilityStateValue, VolumetricFog, admitPointsLines, admitReflectionProbe, advanceProbeFilter, antialiasFromF32, bloomEnabledFromF32, boxProjectReflectionDirection, buildCubeCameraFaceViews, buildReflectionProbeTable, cameraProjectionFromF32, commitProbeFilterStep, createProbeFilterState, cubeCameraUpdateIntentFromF32, cubeCameraUpdateIntentToF32, directionalShadowQualityFromF32, estimateReflectionProbeBytes, extractVolumetricFog, hasVolumetricFogCapability, inspectPointShadow, inspectVolumetricFog, orthographic, perspective, pointShapeFromU32, probeFilterIsSteady, projectMeshMaterialBindingObservation, reflectionProbeTableBytes, reflectionProbeUpdateIntentFromF32, reflectionProbeUpdateIntentToF32, resolveIntegratedVolumeConsumer, resolveMeshMaterialBindings, resolveSelectedVolumetricLight, resolveVisibility, resolveVolumetricFogLightPair, selectReflectionProbe, summarizeMeshMaterialBindings, tonemapFromF32, tonemapToU32, validateReflectionProbeInput, validateVolumetricFog, visibilityStateFromU32 };
1293
+ //# sourceMappingURL=chunk-FS2KNUQH.mjs.map
1294
+ //# sourceMappingURL=chunk-FS2KNUQH.mjs.map