@forgeax/engine-render 0.1.19 → 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 (452) 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 +34 -20
  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-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/chunk-FS2KNUQH.mjs +1294 -0
  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/components/spot-light.d.ts +12 -0
  42. package/dist/components/spot-light.d.ts.map +1 -1
  43. package/dist/construct-renderer.mjs +8552 -1612
  44. package/dist/construct-renderer.mjs.map +1 -1
  45. package/dist/device/gpu-residency.d.ts +19 -2
  46. package/dist/device/gpu-residency.d.ts.map +1 -1
  47. package/dist/environment/frame.d.ts.map +1 -1
  48. package/dist/environment/lifecycle.d.ts +5 -0
  49. package/dist/environment/lifecycle.d.ts.map +1 -1
  50. package/dist/errors/render.d.ts +209 -93
  51. package/dist/errors/render.d.ts.map +1 -1
  52. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  53. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  54. package/dist/extract/environment.d.ts +14 -0
  55. package/dist/extract/environment.d.ts.map +1 -1
  56. package/dist/extract/visibility.d.ts.map +1 -1
  57. package/dist/features/fullscreen.d.ts.map +1 -1
  58. package/dist/features/targets.d.ts.map +1 -1
  59. package/dist/features/types.d.ts +10 -0
  60. package/dist/features/types.d.ts.map +1 -1
  61. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  62. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  63. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  64. package/dist/gpu-driven/production-raster.d.ts +0 -1
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-scene.d.ts.map +1 -1
  67. package/dist/gpu-usage.d.ts +2 -0
  68. package/dist/gpu-usage.d.ts.map +1 -1
  69. package/dist/hdrp-buffers.d.ts +19 -17
  70. package/dist/hdrp-buffers.d.ts.map +1 -1
  71. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  72. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  73. package/dist/ibl/kernel-cache.d.ts +36 -0
  74. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  75. package/dist/index.d.ts +35 -4
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.mjs +4 -4
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/inspection-types.d.ts +51 -0
  80. package/dist/inspection-types.d.ts.map +1 -1
  81. package/dist/instances-derived-bounds.d.ts +50 -0
  82. package/dist/instances-derived-bounds.d.ts.map +1 -0
  83. package/dist/internal.mjs +1 -1
  84. package/dist/light-buffer-layout.d.ts +30 -13
  85. package/dist/light-buffer-layout.d.ts.map +1 -1
  86. package/dist/mesh-material-bindings.d.ts +54 -0
  87. package/dist/mesh-material-bindings.d.ts.map +1 -1
  88. package/dist/pbr-pipeline.d.ts +20 -7
  89. package/dist/pbr-pipeline.d.ts.map +1 -1
  90. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  93. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  95. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  97. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  99. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  101. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  103. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  104. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  105. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  106. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  107. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  108. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  109. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  110. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  111. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts.map +1 -1
  113. package/dist/pipeline/standard-profile.d.ts +12 -20
  114. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  115. package/dist/pipeline-spec.d.ts +40 -7
  116. package/dist/pipeline-spec.d.ts.map +1 -1
  117. package/dist/point-shadow-inspection.d.ts +21 -0
  118. package/dist/point-shadow-inspection.d.ts.map +1 -0
  119. package/dist/record/frame-lighting.d.ts +29 -32
  120. package/dist/record/frame-lighting.d.ts.map +1 -1
  121. package/dist/record/frame-snapshot.d.ts +65 -15
  122. package/dist/record/frame-snapshot.d.ts.map +1 -1
  123. package/dist/record/frame-targets.d.ts +5 -0
  124. package/dist/record/frame-targets.d.ts.map +1 -1
  125. package/dist/record/frame.d.ts +12 -5
  126. package/dist/record/frame.d.ts.map +1 -1
  127. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  128. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  130. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  131. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  132. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  133. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  134. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  135. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  136. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  137. package/dist/record/gpu-timing.d.ts +37 -0
  138. package/dist/record/gpu-timing.d.ts.map +1 -0
  139. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  140. package/dist/record/main-pass-material.d.ts +23 -2
  141. package/dist/record/main-pass-material.d.ts.map +1 -1
  142. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  143. package/dist/record/main-pass.d.ts +2 -0
  144. package/dist/record/main-pass.d.ts.map +1 -1
  145. package/dist/record/render-context.d.ts +48 -3
  146. package/dist/record/render-context.d.ts.map +1 -1
  147. package/dist/record/shadow-pass.d.ts.map +1 -1
  148. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  149. package/dist/record/typed-frame-graph.d.ts +81 -5
  150. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  151. package/dist/record/view-ubo.d.ts +7 -4
  152. package/dist/record/view-ubo.d.ts.map +1 -1
  153. package/dist/reflection/filter.d.ts +22 -0
  154. package/dist/reflection/filter.d.ts.map +1 -0
  155. package/dist/reflection/gpu-table.d.ts +25 -0
  156. package/dist/reflection/gpu-table.d.ts.map +1 -0
  157. package/dist/reflection/projection.d.ts +91 -0
  158. package/dist/reflection/projection.d.ts.map +1 -0
  159. package/dist/render-contract.d.ts +114 -7
  160. package/dist/render-contract.d.ts.map +1 -1
  161. package/dist/render-data.d.ts +10 -6
  162. package/dist/render-data.d.ts.map +1 -1
  163. package/dist/render-graph-primitives.d.ts +1 -0
  164. package/dist/render-graph-primitives.d.ts.map +1 -1
  165. package/dist/render-pipeline.d.ts +78 -2
  166. package/dist/render-pipeline.d.ts.map +1 -1
  167. package/dist/render-system-extract.d.ts +113 -20
  168. package/dist/render-system-extract.d.ts.map +1 -1
  169. package/dist/render-system.d.ts +24 -3
  170. package/dist/render-system.d.ts.map +1 -1
  171. package/dist/renderer-inspect.d.ts +29 -0
  172. package/dist/renderer-inspect.d.ts.map +1 -0
  173. package/dist/renderer.d.ts +43 -0
  174. package/dist/renderer.d.ts.map +1 -0
  175. package/dist/scene/render-scene.d.ts +14 -0
  176. package/dist/scene/render-scene.d.ts.map +1 -1
  177. package/dist/shadow-atlas.d.ts +3 -3
  178. package/dist/shadow-atlas.d.ts.map +1 -1
  179. package/dist/ssao-buffers.d.ts +3 -0
  180. package/dist/ssao-buffers.d.ts.map +1 -1
  181. package/dist/targets/contracts.d.ts +66 -0
  182. package/dist/targets/contracts.d.ts.map +1 -0
  183. package/dist/targets/graph-projection.d.ts +29 -0
  184. package/dist/targets/graph-projection.d.ts.map +1 -0
  185. package/dist/targets/material-source.d.ts +34 -0
  186. package/dist/targets/material-source.d.ts.map +1 -0
  187. package/dist/targets/owner.d.ts +32 -0
  188. package/dist/targets/owner.d.ts.map +1 -0
  189. package/dist/targets/physical.d.ts +18 -0
  190. package/dist/targets/physical.d.ts.map +1 -0
  191. package/dist/targets/readback.d.ts +39 -0
  192. package/dist/targets/readback.d.ts.map +1 -0
  193. package/dist/temporal/frame.d.ts +44 -0
  194. package/dist/temporal/frame.d.ts.map +1 -0
  195. package/dist/temporal/index.mjs +3 -3
  196. package/dist/typed-render-graph-primitives.d.ts +6 -1
  197. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  198. package/dist/typed-shadow-atlas.d.ts +10 -0
  199. package/dist/typed-shadow-atlas.d.ts.map +1 -0
  200. package/dist/typed-shadow-passes.d.ts +1 -1
  201. package/dist/typed-shadow-passes.d.ts.map +1 -1
  202. package/dist/volume/capability.d.ts +57 -0
  203. package/dist/volume/capability.d.ts.map +1 -0
  204. package/dist/volume/component.d.ts +61 -0
  205. package/dist/volume/component.d.ts.map +1 -0
  206. package/dist/volume/extract.d.ts +11 -0
  207. package/dist/volume/extract.d.ts.map +1 -0
  208. package/dist/volume/inspection.d.ts +38 -0
  209. package/dist/volume/inspection.d.ts.map +1 -0
  210. package/dist/volume/passes.d.ts +38 -0
  211. package/dist/volume/passes.d.ts.map +1 -0
  212. package/dist/volume/recovery.d.ts +38 -0
  213. package/dist/volume/recovery.d.ts.map +1 -0
  214. package/dist/volume/resources.d.ts +57 -0
  215. package/dist/volume/resources.d.ts.map +1 -0
  216. package/dist/volume/temporal.d.ts +35 -0
  217. package/dist/volume/temporal.d.ts.map +1 -0
  218. package/package.json +20 -20
  219. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  220. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  221. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  222. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  223. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  224. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  225. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  226. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  227. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  228. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  229. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  230. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  231. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  232. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  233. package/src/__tests__/fog-component.unit.test.ts +67 -0
  234. package/src/__tests__/fog.integration.test.ts +86 -0
  235. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  236. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  237. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  238. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  239. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  240. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  241. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  242. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  243. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  244. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  245. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  246. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  247. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  248. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  249. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  250. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  251. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  252. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
  253. package/src/__tests__/material-observation.integration.test.ts +101 -0
  254. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  255. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  256. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  257. package/src/__tests__/public-surface.test-d.ts +10 -0
  258. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  259. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  260. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  261. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  262. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  263. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  264. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  265. package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
  266. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  267. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  268. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  269. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  270. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  271. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  272. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  273. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  274. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  275. package/src/__tests__/render-target-public-schema.json +107 -0
  276. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  277. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  278. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  279. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  280. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  281. package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
  282. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  283. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  284. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  285. package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
  286. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  287. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  288. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  289. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  290. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  291. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  292. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  293. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  294. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  295. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  296. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  297. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
  298. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  299. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  300. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  301. package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
  302. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
  303. package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
  304. package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
  305. package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
  306. package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
  307. package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
  308. package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
  309. package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
  310. package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
  311. package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
  312. package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
  313. package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
  315. package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
  316. package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
  317. package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
  318. package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
  319. package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
  320. package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
  321. package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
  322. package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
  323. package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
  324. package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
  325. package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
  326. package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
  327. package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
  328. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
  329. package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
  330. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
  331. package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
  332. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
  333. package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
  334. package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
  335. package/src/assembly/device-feature-admission.ts +73 -0
  336. package/src/assembly/directional-shadow-inspection.ts +122 -0
  337. package/src/assembly/factory.ts +1093 -246
  338. package/src/assembly/host-contract.ts +25 -0
  339. package/src/assembly/render-target-host.ts +847 -0
  340. package/src/assets/asset-decoders.ts +1 -1
  341. package/src/assets/render-asset-port.ts +7 -1
  342. package/src/capture/cube-views.ts +69 -0
  343. package/src/capture/scheduler.ts +265 -0
  344. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  345. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  346. package/src/components/camera.ts +4 -0
  347. package/src/components/cube-camera.ts +52 -0
  348. package/src/components/directional-light.ts +22 -2
  349. package/src/components/directional-shadow-filter.ts +57 -0
  350. package/src/components/index.ts +2 -0
  351. package/src/components/light-helpers.ts +85 -7
  352. package/src/components/reflection-probe.ts +49 -0
  353. package/src/components/spot-light.ts +22 -3
  354. package/src/device/gpu-residency.ts +168 -58
  355. package/src/environment/frame.ts +6 -24
  356. package/src/environment/lifecycle.ts +12 -0
  357. package/src/errors/render.ts +405 -143
  358. package/src/extract/directional-shadow-projection.ts +61 -0
  359. package/src/extract/environment.ts +57 -0
  360. package/src/extract/visibility.ts +25 -1
  361. package/src/features/fullscreen.ts +3 -0
  362. package/src/features/targets.ts +4 -1
  363. package/src/features/types.ts +10 -0
  364. package/src/fullscreen-post-process-pass.ts +43 -2
  365. package/src/gpu-driven/batch-topology.ts +1 -0
  366. package/src/gpu-driven/production-raster.ts +1 -3
  367. package/src/gpu-scene.ts +8 -1
  368. package/src/gpu-usage.ts +2 -0
  369. package/src/hdrp-buffers.ts +165 -59
  370. package/src/ibl/IblPipelineCache.ts +11 -0
  371. package/src/ibl/kernel-cache.ts +88 -0
  372. package/src/index.ts +186 -1
  373. package/src/inspection-types.ts +56 -0
  374. package/src/instances-derived-bounds.ts +171 -0
  375. package/src/light-buffer-layout.ts +74 -26
  376. package/src/mesh-material-bindings.ts +132 -0
  377. package/src/pbr-pipeline.ts +139 -27
  378. package/src/pipeline/standard-forward-lane.ts +65 -15
  379. package/src/pipeline/standard-lighting/errors.ts +6 -0
  380. package/src/pipeline/standard-lighting/graph.ts +157 -0
  381. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  382. package/src/pipeline/standard-lighting/layout.ts +31 -0
  383. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  384. package/src/pipeline/standard-lighting/membership.ts +43 -0
  385. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  386. package/src/pipeline/standard-lighting/topology.ts +120 -0
  387. package/src/pipeline/standard-lighting/transport.ts +77 -0
  388. package/src/pipeline/standard-pipeline.ts +141 -192
  389. package/src/pipeline/standard-post.ts +26 -7
  390. package/src/pipeline/standard-profile.ts +23 -30
  391. package/src/pipeline-spec.ts +84 -21
  392. package/src/point-shadow-inspection.ts +55 -0
  393. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  394. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  395. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  396. package/src/record/frame-lighting.ts +470 -516
  397. package/src/record/frame-snapshot.ts +76 -28
  398. package/src/record/frame-targets.ts +23 -2
  399. package/src/record/frame.ts +1169 -79
  400. package/src/record/gpu-pass-timing/contract.ts +180 -0
  401. package/src/record/gpu-pass-timing/errors.ts +34 -0
  402. package/src/record/gpu-pass-timing/index.ts +37 -0
  403. package/src/record/gpu-pass-timing/parser.ts +97 -0
  404. package/src/record/gpu-pass-timing/session.ts +938 -0
  405. package/src/record/gpu-timing.ts +233 -0
  406. package/src/record/main-pass-geometry.ts +120 -80
  407. package/src/record/main-pass-material.ts +101 -11
  408. package/src/record/main-pass-sprite-draws.ts +54 -25
  409. package/src/record/main-pass.ts +71 -15
  410. package/src/record/render-context.ts +77 -0
  411. package/src/record/shadow-pass.ts +104 -66
  412. package/src/record/skybox-post-pass.ts +20 -4
  413. package/src/record/typed-frame-graph.ts +1016 -32
  414. package/src/record/view-ubo.ts +63 -28
  415. package/src/reflection/filter.ts +81 -0
  416. package/src/reflection/gpu-table.ts +44 -0
  417. package/src/reflection/projection.ts +281 -0
  418. package/src/render-contract.ts +147 -4
  419. package/src/render-data.ts +50 -22
  420. package/src/render-graph-primitives.ts +9 -4
  421. package/src/render-pipeline.ts +161 -2
  422. package/src/render-system-extract.ts +886 -103
  423. package/src/render-system.ts +1174 -66
  424. package/src/renderer-inspect.ts +66 -0
  425. package/src/renderer.ts +222 -0
  426. package/src/scene/render-scene.ts +117 -9
  427. package/src/shadow-atlas.ts +5 -5
  428. package/src/ssao-buffers.ts +9 -2
  429. package/src/targets/contracts.ts +182 -0
  430. package/src/targets/graph-projection.ts +169 -0
  431. package/src/targets/material-source.ts +143 -0
  432. package/src/targets/owner.ts +214 -0
  433. package/src/targets/physical.ts +18 -0
  434. package/src/targets/readback.ts +153 -0
  435. package/src/temporal/frame.ts +128 -0
  436. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
  437. package/src/typed-render-graph-primitives.ts +34 -2
  438. package/src/typed-shadow-atlas.ts +17 -0
  439. package/src/typed-shadow-passes.ts +47 -40
  440. package/src/volume/capability.ts +173 -0
  441. package/src/volume/component.ts +110 -0
  442. package/src/volume/extract.ts +21 -0
  443. package/src/volume/inspection.ts +78 -0
  444. package/src/volume/passes.ts +686 -0
  445. package/src/volume/recovery.ts +86 -0
  446. package/src/volume/resources.ts +236 -0
  447. package/src/volume/temporal.ts +89 -0
  448. package/dist/chunk-IPXCABEP.mjs.map +0 -1
  449. package/dist/chunk-LOSO4CTV.mjs.map +0 -1
  450. package/dist/chunk-RJRUS55L.mjs.map +0 -1
  451. package/dist/chunk-YTQ5C7YQ.mjs +0 -584
  452. package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
@@ -0,0 +1,173 @@
1
+ import { Entity, type EntityHandle, type World } from '@forgeax/engine-ecs';
2
+ import type { RhiCaps } from '@forgeax/engine-rhi';
3
+ import { Transform } from '@forgeax/engine-scene';
4
+ import { DirectionalLight } from '../components/directional-light';
5
+ import { PointLight } from '../components/point-light';
6
+ import { SpotLight } from '../components/spot-light';
7
+
8
+ /**
9
+ * The single capability predicate for the authored volumetric-fog producer.
10
+ * Shader sources are part of the device-bound bundle: compute/storage alone
11
+ * is not enough to claim that the three fused graph passes can execute.
12
+ */
13
+ export function hasVolumetricFogCapability(
14
+ caps: Pick<RhiCaps, 'compute' | 'storageTexture'>,
15
+ shaders: unknown,
16
+ ): boolean {
17
+ return caps.compute && caps.storageTexture && shaders !== undefined;
18
+ }
19
+
20
+ export type VolumetricFogLightKind = 'directional' | 'point' | 'spot';
21
+ // The exact parity authoring mode is the closed `point-spot` pair.
22
+
23
+ export type VolumetricFogLightResolution =
24
+ | {
25
+ readonly status: 'available';
26
+ readonly entity: EntityHandle;
27
+ readonly kind: VolumetricFogLightKind;
28
+ }
29
+ | {
30
+ readonly status: 'unresolved';
31
+ readonly reason: 'missing-entity' | 'wrong-component' | 'ambiguous';
32
+ readonly entity: EntityHandle;
33
+ readonly expected: 'DirectionalLight | PointLight | SpotLight';
34
+ readonly actual: string;
35
+ readonly hint: string;
36
+ };
37
+
38
+ export type VolumetricFogLightPairResolution =
39
+ | {
40
+ readonly status: 'available';
41
+ readonly mode: 'point-spot';
42
+ readonly point: EntityHandle;
43
+ readonly spot: EntityHandle;
44
+ }
45
+ | {
46
+ readonly status: 'unresolved';
47
+ readonly reason: 'missing-entity' | 'same-entity' | 'wrong-component';
48
+ readonly point: EntityHandle;
49
+ readonly spot: EntityHandle;
50
+ readonly expected: 'PointLight + SpotLight in the same World';
51
+ readonly actual: string;
52
+ readonly hint: string;
53
+ };
54
+
55
+ /** Resolve the narrow official Point+Spot pair without creating a light owner. */
56
+ export function resolveVolumetricFogLightPair(
57
+ world: World,
58
+ point: EntityHandle,
59
+ spot: EntityHandle,
60
+ ): VolumetricFogLightPairResolution {
61
+ const expected = 'PointLight + SpotLight in the same World' as const;
62
+ if (!world.get(point, Entity).ok || !world.get(spot, Entity).ok) {
63
+ return {
64
+ status: 'unresolved',
65
+ reason: 'missing-entity',
66
+ point,
67
+ spot,
68
+ expected,
69
+ actual: 'point or spot entity is absent from this World',
70
+ hint: 'assign two live entities from the same World and retry',
71
+ };
72
+ }
73
+ if (point === spot) {
74
+ return {
75
+ status: 'unresolved',
76
+ reason: 'same-entity',
77
+ point,
78
+ spot,
79
+ expected,
80
+ actual: 'PointLight and SpotLight share one EntityHandle',
81
+ hint: 'spawn PointLight and SpotLight on two different entities',
82
+ };
83
+ }
84
+ const pointValid = world.hasComponent(point, PointLight) && world.hasComponent(point, Transform);
85
+ const spotValid = world.hasComponent(spot, SpotLight) && world.hasComponent(spot, Transform);
86
+ if (!pointValid || !spotValid) {
87
+ return {
88
+ status: 'unresolved',
89
+ reason: 'wrong-component',
90
+ point,
91
+ spot,
92
+ expected,
93
+ actual: `pointValid=${pointValid}; spotValid=${spotValid}`,
94
+ hint: 'attach PointLight and SpotLight with Transform to separate same-World entities',
95
+ };
96
+ }
97
+ return { status: 'available', mode: 'point-spot', point, spot };
98
+ }
99
+
100
+ /**
101
+ * Resolve the required VolumetricFog.light reference in its owning World.
102
+ * PointLight is a valid primary selection for the exact Point+Spot pair.
103
+ * EntityHandle has no portable world tag, so a handle absent from this World
104
+ * (the same World contract) is reported as missing-entity;
105
+ * is reported as missing-entity; callers must not manufacture a light.
106
+ */
107
+ export function resolveSelectedVolumetricLight(
108
+ world: World,
109
+ entity: EntityHandle,
110
+ ): VolumetricFogLightResolution {
111
+ const expected = 'DirectionalLight | PointLight | SpotLight' as const;
112
+ if (!world.get(entity, Entity).ok) {
113
+ return {
114
+ status: 'unresolved',
115
+ reason: 'missing-entity',
116
+ entity,
117
+ expected,
118
+ actual: 'missing or foreign World entity',
119
+ hint: 'assign VolumetricFog.light to a live DirectionalLight or SpotLight in this World',
120
+ };
121
+ }
122
+ const hasDirectional = world.hasComponent(entity, DirectionalLight);
123
+ const hasSpot = world.hasComponent(entity, SpotLight);
124
+ if (hasDirectional && hasSpot) {
125
+ return {
126
+ status: 'unresolved',
127
+ reason: 'ambiguous',
128
+ entity,
129
+ expected,
130
+ actual: 'DirectionalLight + SpotLight',
131
+ hint: 'remove one mutually exclusive light component from the selected entity',
132
+ };
133
+ }
134
+ if (hasDirectional) return { status: 'available', entity, kind: 'directional' };
135
+ if (world.hasComponent(entity, PointLight) && world.hasComponent(entity, Transform)) {
136
+ return { status: 'available', entity, kind: 'point' };
137
+ }
138
+ if (hasSpot && world.hasComponent(entity, Transform)) {
139
+ return { status: 'available', entity, kind: 'spot' };
140
+ }
141
+ const actual = hasSpot
142
+ ? 'SpotLight without Transform'
143
+ : world.hasComponent(entity, PointLight)
144
+ ? 'PointLight'
145
+ : 'other component';
146
+ return {
147
+ status: 'unresolved',
148
+ reason: 'wrong-component',
149
+ entity,
150
+ expected,
151
+ actual,
152
+ hint: 'add exactly one supported light component and a Transform for PointLight or SpotLight in the same World',
153
+ };
154
+ }
155
+
156
+ export interface IntegratedVolumeResource {
157
+ /** Logical resolved-volume identity; this is not a physical graph resource. */
158
+ readonly identity: 'volume-integrated';
159
+ readonly format: 'rgba16float';
160
+ readonly stage: 'resolved';
161
+ }
162
+
163
+ export type VolumeConsumer = 'opaque' | 'transparent' | 'sprite' | 'vfx' | 'custom';
164
+
165
+ export function resolveIntegratedVolumeConsumer(
166
+ resource: IntegratedVolumeResource,
167
+ consumer: VolumeConsumer,
168
+ ): { readonly consumer: VolumeConsumer; readonly resource: IntegratedVolumeResource } {
169
+ // The volume owner supplies this prepared logical resource. Consumers only
170
+ // receive its identity and format; they never allocate a view or own the
171
+ // history lifetime here.
172
+ return { consumer, resource };
173
+ }
@@ -0,0 +1,110 @@
1
+ import { defineComponent, type EntityHandle } from '@forgeax/engine-ecs';
2
+ import { err, ok, type Result } from '@forgeax/engine-types';
3
+ import {
4
+ VolumeDensityShapeMismatchError,
5
+ type VolumeError,
6
+ VolumeInvalidBoundsError,
7
+ VolumeInvalidParametersError,
8
+ VolumeOwnerConflictError,
9
+ } from '../errors/render';
10
+
11
+ export interface VolumeDensityBinding {
12
+ readonly guid: string;
13
+ readonly generation: number;
14
+ readonly shape: {
15
+ readonly viewDimension: '2d' | '2d-array' | '3d';
16
+ readonly extent: {
17
+ readonly width: number;
18
+ readonly height: number;
19
+ readonly depth?: number;
20
+ readonly layers?: number;
21
+ };
22
+ };
23
+ readonly format: string;
24
+ readonly colorSpace?: 'linear' | 'srgb';
25
+ }
26
+
27
+ export interface VolumeBounds {
28
+ readonly min: readonly [number, number, number];
29
+ readonly max: readonly [number, number, number];
30
+ }
31
+
32
+ export interface VolumetricFogAuthoring {
33
+ /** Invalid authoring reports closed code, expected, hint, and detail fields. */
34
+ /** The selected DirectionalLight or PointLight in this World. */
35
+ readonly light: EntityHandle;
36
+ /** The optional same-World SpotLight paired with a PointLight. */
37
+ readonly spotLight?: EntityHandle;
38
+ readonly density: VolumeDensityBinding;
39
+ readonly bounds: VolumeBounds;
40
+ readonly extinction: readonly [number, number, number];
41
+ readonly albedo: readonly [number, number, number];
42
+ readonly emission: readonly [number, number, number];
43
+ readonly anisotropy: number;
44
+ readonly maxDistance: number;
45
+ readonly ownerCount?: number;
46
+ }
47
+
48
+ export type VolumetricFogLightSelection =
49
+ | { readonly light: EntityHandle; readonly spotLight?: undefined }
50
+ | { readonly light: EntityHandle; readonly spotLight: EntityHandle };
51
+
52
+ export interface ValidatedVolumetricFog extends VolumetricFogAuthoring {
53
+ readonly ownerCount: 1;
54
+ }
55
+
56
+ export const VolumetricFog = defineComponent('VolumetricFog', {
57
+ light: { type: 'entity' },
58
+ spotLight: { type: 'entity' },
59
+ density: { type: 'shared<TextureAsset>', simulationTransient: true },
60
+ boundsMin: { type: 'array<f32, 3>' },
61
+ boundsMax: { type: 'array<f32, 3>' },
62
+ extinction: { type: 'array<f32, 3>' },
63
+ albedo: { type: 'array<f32, 3>' },
64
+ emission: { type: 'array<f32, 3>' },
65
+ anisotropy: { type: 'f32', default: 0 },
66
+ maxDistance: { type: 'f32', default: 100 },
67
+ });
68
+
69
+ function finiteVector(value: readonly [number, number, number]): boolean {
70
+ return value.every(Number.isFinite);
71
+ }
72
+
73
+ function validBounds(bounds: VolumeBounds): boolean {
74
+ if (!finiteVector(bounds.min) || !finiteVector(bounds.max)) return false;
75
+ return bounds.max.every((value, index) => value > (bounds.min[index] ?? value));
76
+ }
77
+
78
+ function validRange(
79
+ value: readonly [number, number, number],
80
+ min: number,
81
+ max = Infinity,
82
+ ): boolean {
83
+ return value.every((entry) => Number.isFinite(entry) && entry >= min && entry <= max);
84
+ }
85
+
86
+ export function validateVolumetricFog(
87
+ input: VolumetricFogAuthoring,
88
+ ): Result<ValidatedVolumetricFog, VolumeError> {
89
+ const ownerCount = input.ownerCount ?? 1;
90
+ if (ownerCount !== 1) return err(new VolumeOwnerConflictError(ownerCount));
91
+ if (input.density.shape.viewDimension !== '3d' || input.density.colorSpace === 'srgb') {
92
+ return err(
93
+ new VolumeDensityShapeMismatchError(input.density.guid, input.density.shape.viewDimension),
94
+ );
95
+ }
96
+ if (!validBounds(input.bounds)) return err(new VolumeInvalidBoundsError(input.bounds));
97
+ if (
98
+ !validRange(input.extinction, 0) ||
99
+ !validRange(input.albedo, 0, 1) ||
100
+ !validRange(input.emission, 0) ||
101
+ !Number.isFinite(input.anisotropy) ||
102
+ input.anisotropy <= -1 ||
103
+ input.anisotropy >= 1 ||
104
+ !Number.isFinite(input.maxDistance) ||
105
+ input.maxDistance <= 0
106
+ ) {
107
+ return err(new VolumeInvalidParametersError(input));
108
+ }
109
+ return ok({ ...input, ownerCount: 1 });
110
+ }
@@ -0,0 +1,21 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import { type VolumeError, VolumeOwnerConflictError } from '../errors/render';
3
+ import {
4
+ type ValidatedVolumetricFog,
5
+ type VolumetricFogAuthoring,
6
+ validateVolumetricFog,
7
+ } from './component';
8
+
9
+ export type VolumetricFogExtract =
10
+ | { readonly status: 'off' }
11
+ | { readonly status: 'available'; readonly fog: ValidatedVolumetricFog };
12
+
13
+ export function extractVolumetricFog(
14
+ inputs: readonly VolumetricFogAuthoring[],
15
+ ): Result<VolumetricFogExtract, VolumeError> {
16
+ if (inputs.length === 0) return ok({ status: 'off' });
17
+ if (inputs.length !== 1) return err(new VolumeOwnerConflictError(inputs.length));
18
+ const validated = validateVolumetricFog(inputs[0] as VolumetricFogAuthoring);
19
+ if (!validated.ok) return validated;
20
+ return ok({ status: 'available', fog: validated.value });
21
+ }
@@ -0,0 +1,78 @@
1
+ import type { TextureFormat } from '@forgeax/engine-rhi';
2
+ import type { VolumeRecoveryState, VolumeSelectedLightFacts } from './recovery';
3
+ import type { VolumetricFogResourceFacts } from './resources';
4
+
5
+ export type VolumetricFogInspectionStatus = 'off' | 'available' | 'unavailable' | 'degraded';
6
+
7
+ export type VolumetricFogResourceStage = 'none' | 'candidate' | 'accepted' | 'lkg' | 'recovering';
8
+
9
+ export interface VolumetricFogInspection {
10
+ readonly status: VolumetricFogInspectionStatus;
11
+ readonly resourceStage: VolumetricFogResourceStage;
12
+ readonly guid: string | undefined;
13
+ readonly generation: number | undefined;
14
+ readonly digest: string | undefined;
15
+ readonly candidateGeneration: number | undefined;
16
+ readonly candidateDigest: string | undefined;
17
+ readonly lkgGeneration: number | undefined;
18
+ readonly candidateFailure: VolumeRecoveryState['candidateFailure'];
19
+ readonly deviceEpoch: number;
20
+ readonly format: TextureFormat | undefined;
21
+ readonly passCount: number;
22
+ readonly sampleCount: number;
23
+ readonly memoryBytes: number;
24
+ readonly resourceFacts: VolumetricFogResourceFacts | undefined;
25
+ readonly selectedLight: VolumeSelectedLightFacts | undefined;
26
+ readonly candidateSelectedLight: VolumeSelectedLightFacts | undefined;
27
+ }
28
+
29
+ export interface VolumetricFogInspectionInput {
30
+ readonly authored: boolean;
31
+ readonly capability: 'available' | 'unavailable';
32
+ readonly degraded?: boolean;
33
+ readonly recovery?: VolumeRecoveryState;
34
+ readonly acceptedDigest?: string;
35
+ readonly format?: TextureFormat;
36
+ readonly passCount?: number;
37
+ readonly sampleCount?: number;
38
+ readonly memoryBytes?: number;
39
+ readonly resourceFacts?: VolumetricFogResourceFacts;
40
+ }
41
+
42
+ function resourceStage(input: VolumetricFogInspectionInput): VolumetricFogResourceStage {
43
+ if (!input.authored || input.recovery === undefined) return 'none';
44
+ if (input.recovery.status === 'candidate') return 'candidate';
45
+ if (input.recovery.status === 'recovering') return 'recovering';
46
+ if (input.recovery.status === 'degraded') return 'lkg';
47
+ return 'accepted';
48
+ }
49
+
50
+ export function inspectVolumetricFog(input: VolumetricFogInspectionInput): VolumetricFogInspection {
51
+ const recovery = input.recovery;
52
+ const status: VolumetricFogInspectionStatus = !input.authored
53
+ ? 'off'
54
+ : input.capability === 'unavailable'
55
+ ? 'unavailable'
56
+ : input.degraded === true || recovery?.status === 'degraded'
57
+ ? 'degraded'
58
+ : 'available';
59
+ return Object.freeze({
60
+ status,
61
+ resourceStage: resourceStage(input),
62
+ guid: recovery?.guid,
63
+ generation: recovery?.generation,
64
+ digest: input.acceptedDigest,
65
+ candidateGeneration: recovery?.candidateGeneration,
66
+ candidateDigest: recovery?.candidateDigest,
67
+ lkgGeneration: recovery?.lkgGeneration,
68
+ candidateFailure: recovery?.candidateFailure,
69
+ deviceEpoch: recovery?.deviceEpoch ?? 0,
70
+ format: input.format,
71
+ passCount: input.passCount ?? 0,
72
+ sampleCount: input.sampleCount ?? 0,
73
+ memoryBytes: input.memoryBytes ?? 0,
74
+ resourceFacts: input.resourceFacts,
75
+ selectedLight: recovery?.selectedLight,
76
+ candidateSelectedLight: recovery?.candidateSelectedLight,
77
+ });
78
+ }