@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
@@ -76,7 +76,7 @@ function resolveMaterialWireRefs(
76
76
  value.parameters === undefined
77
77
  ? MATERIAL_TEXTURE_SLOTS
78
78
  : value.parameters
79
- .filter((parameter) => parameter.type === 'texture')
79
+ .filter((parameter) => parameter.type === 'texture' || parameter.type === 'texture_cube')
80
80
  .map((parameter) => parameter.name),
81
81
  );
82
82
  const values = { ...value.values };
@@ -31,7 +31,13 @@ export function createRenderAssetPort(
31
31
  const artifact = shaderRegistry.findMaterialArtifact(shaderId);
32
32
  if (!artifact.ok) return [];
33
33
  return artifact.value.paramSchema
34
- .filter((parameter) => parameter.type === 'texture2d')
34
+ .filter(
35
+ (parameter) =>
36
+ parameter.type === 'texture2d' ||
37
+ parameter.type === 'texture_cube' ||
38
+ parameter.type === 'texture_depth_2d' ||
39
+ parameter.type === 'texture_cube_array',
40
+ )
35
41
  .map((parameter) => parameter.name);
36
42
  },
37
43
  };
@@ -0,0 +1,69 @@
1
+ import { type Mat4, mat4, type Vec3Like } from '@forgeax/engine-math';
2
+ import { CUBE_CAMERA_FACE_ORDER, type CubeCameraFace } from '../components/cube-camera';
3
+
4
+ export interface CubeCameraFaceView {
5
+ readonly position: Vec3Like;
6
+ readonly face: CubeCameraFace;
7
+ readonly direction: readonly [number, number, number];
8
+ readonly up: readonly [number, number, number];
9
+ readonly near: number;
10
+ readonly far: number;
11
+ readonly view: Mat4;
12
+ readonly projection: Mat4;
13
+ readonly viewProjection: Mat4;
14
+ }
15
+
16
+ export interface CubeCameraFaceViewInput {
17
+ readonly position: Vec3Like;
18
+ readonly near: number;
19
+ readonly far: number;
20
+ }
21
+
22
+ const FACE_ORIENTATION: ReadonlyArray<{
23
+ readonly direction: readonly [number, number, number];
24
+ readonly up: readonly [number, number, number];
25
+ }> = [
26
+ { direction: [1, 0, 0], up: [0, 1, 0] },
27
+ { direction: [-1, 0, 0], up: [0, 1, 0] },
28
+ { direction: [0, 1, 0], up: [0, 0, -1] },
29
+ { direction: [0, -1, 0], up: [0, 0, 1] },
30
+ { direction: [0, 0, 1], up: [0, 1, 0] },
31
+ { direction: [0, 0, -1], up: [0, 1, 0] },
32
+ ];
33
+
34
+ function assertRange(near: number, far: number): void {
35
+ if (!Number.isFinite(near) || near <= 0 || !Number.isFinite(far) || far <= near) {
36
+ throw new RangeError('CubeCamera requires finite near > 0 and far > near.');
37
+ }
38
+ }
39
+
40
+ /** Build the only supported +X,-X,+Y,-Y,+Z,-Z cube orientation. */
41
+ export function buildCubeCameraFaceViews(input: CubeCameraFaceViewInput): CubeCameraFaceView[] {
42
+ assertRange(input.near, input.far);
43
+ const views: CubeCameraFaceView[] = [];
44
+ for (const [index, face] of CUBE_CAMERA_FACE_ORDER.entries()) {
45
+ const orientation = FACE_ORIENTATION[index];
46
+ if (orientation === undefined)
47
+ throw new Error(`CubeCamera face orientation missing at ${index}`);
48
+ const target: Vec3Like = [
49
+ (input.position[0] ?? 0) + orientation.direction[0],
50
+ (input.position[1] ?? 0) + orientation.direction[1],
51
+ (input.position[2] ?? 0) + orientation.direction[2],
52
+ ];
53
+ const view = mat4.lookAt(mat4.create(), input.position, target, orientation.up);
54
+ const projection = mat4.perspective(mat4.create(), Math.PI / 2, 1, input.near, input.far);
55
+ const viewProjection = mat4.multiply(mat4.create(), projection, view);
56
+ views.push({
57
+ position: input.position,
58
+ face,
59
+ direction: orientation.direction,
60
+ up: orientation.up,
61
+ near: input.near,
62
+ far: input.far,
63
+ view,
64
+ projection,
65
+ viewProjection,
66
+ });
67
+ }
68
+ return views;
69
+ }
@@ -0,0 +1,265 @@
1
+ import {
2
+ CUBE_CAMERA_FACE_ORDER,
3
+ type CubeCameraFace,
4
+ type CubeCameraUpdateIntent,
5
+ } from '../components/cube-camera';
6
+ import type { RenderError } from '../errors/render';
7
+ import { RenderTargetOperationFailedError, RenderTargetStateInvalidError } from '../errors/render';
8
+ import type { RenderResult } from '../render-contract';
9
+ import type { RenderTarget } from '../targets/contracts';
10
+ import { buildCubeCameraFaceViews, type CubeCameraFaceView } from './cube-views';
11
+
12
+ export interface CubeCaptureRequest {
13
+ readonly target: RenderTarget;
14
+ readonly position: readonly [number, number, number];
15
+ readonly near: number;
16
+ readonly far: number;
17
+ readonly updateIntent: CubeCameraUpdateIntent;
18
+ readonly requestVersion: number;
19
+ readonly faceBudget: number;
20
+ }
21
+
22
+ export interface CubeCaptureWork extends CubeCameraFaceView {
23
+ readonly target: RenderTarget;
24
+ readonly requestVersion: number;
25
+ readonly candidateGeneration: number;
26
+ }
27
+
28
+ export interface CubeCaptureInspection {
29
+ readonly target: RenderTarget;
30
+ readonly activeGeneration: number;
31
+ readonly candidateGeneration?: number;
32
+ readonly completedVersion: number;
33
+ readonly pendingFaces: readonly CubeCameraFace[];
34
+ readonly fallback: 'neutral' | 'previous-active';
35
+ readonly nestedRejections: number;
36
+ }
37
+
38
+ export interface CubeCaptureSchedulerOptions {
39
+ readonly maxFacesPerFrame?: number;
40
+ }
41
+
42
+ export type CubeCaptureRenderableKind = 'opaque' | 'transparent' | 'environment' | 'debug' | 'ui';
43
+
44
+ export interface CubeCaptureRenderable {
45
+ readonly kind: CubeCaptureRenderableKind;
46
+ readonly target?: RenderTarget;
47
+ }
48
+
49
+ /** Apply the Standard capture visibility boundary to one extracted scene. */
50
+ export function selectCubeCaptureRenderables(
51
+ renderables: readonly CubeCaptureRenderable[],
52
+ candidateTarget: RenderTarget,
53
+ ): readonly CubeCaptureRenderable[] {
54
+ return renderables.filter(
55
+ (renderable) =>
56
+ renderable.kind !== 'debug' &&
57
+ renderable.kind !== 'ui' &&
58
+ renderable.target !== candidateTarget,
59
+ );
60
+ }
61
+
62
+ export interface CubeCaptureScheduler {
63
+ beginFrame(): void;
64
+ request(request: CubeCaptureRequest): RenderResult<{ readonly scheduled: boolean }, RenderError>;
65
+ nextWork(): readonly CubeCaptureWork[];
66
+ completeSubmission(
67
+ submitted: boolean,
68
+ completed?: Promise<unknown>,
69
+ ): RenderResult<void, RenderError>;
70
+ inspect(target: RenderTarget): CubeCaptureInspection;
71
+ }
72
+
73
+ interface PendingCapture {
74
+ readonly request: CubeCaptureRequest;
75
+ readonly views: readonly CubeCameraFaceView[];
76
+ readonly candidateGeneration: number;
77
+ readonly written: Set<CubeCameraFace>;
78
+ inFlight: readonly CubeCaptureWork[];
79
+ }
80
+
81
+ interface CaptureState {
82
+ readonly target: RenderTarget;
83
+ activeGeneration: number;
84
+ completedVersion: number;
85
+ pending: PendingCapture | undefined;
86
+ nestedRejections: number;
87
+ }
88
+
89
+ function invalid(
90
+ reason: 'generation-mismatch' | 'uninitialized',
91
+ ): RenderResult<never, RenderError> {
92
+ return {
93
+ ok: false,
94
+ error: new RenderTargetStateInvalidError({
95
+ operation: 'source',
96
+ reason,
97
+ state: reason === 'uninitialized' ? 'uninitialized' : 'candidate',
98
+ generation: 0,
99
+ }),
100
+ };
101
+ }
102
+
103
+ function failed(generation: number, cause: unknown): RenderResult<never, RenderError> {
104
+ return {
105
+ ok: false,
106
+ error: new RenderTargetOperationFailedError({
107
+ operation: 'source',
108
+ stage: 'submit',
109
+ generation,
110
+ cause,
111
+ recovery: 'retain-last-known-good',
112
+ }),
113
+ };
114
+ }
115
+
116
+ function validateRequest(request: CubeCaptureRequest): RenderResult<void, RenderError> {
117
+ if (!Number.isInteger(request.requestVersion) || request.requestVersion < 0) {
118
+ return invalid('generation-mismatch');
119
+ }
120
+ if (!Number.isInteger(request.faceBudget) || request.faceBudget < 1 || request.faceBudget > 6) {
121
+ return invalid('uninitialized');
122
+ }
123
+ if (request.updateIntent === 'once' && request.requestVersion > 1) {
124
+ return invalid('generation-mismatch');
125
+ }
126
+ return { ok: true, value: undefined };
127
+ }
128
+
129
+ /**
130
+ * Schedules CubeCamera views inside the existing display frame. The scheduler
131
+ * never owns a World, encoder, or queue; callers contribute the returned work
132
+ * to the frame graph and report the one matching submission result.
133
+ */
134
+ export function createCubeCaptureScheduler(
135
+ options: CubeCaptureSchedulerOptions = {},
136
+ ): CubeCaptureScheduler {
137
+ const maxFacesPerFrame = Math.max(1, Math.min(6, Math.floor(options.maxFacesPerFrame ?? 1)));
138
+ const states = new WeakMap<object, CaptureState>();
139
+ let activeCapture: CaptureState | undefined;
140
+ let frameOpen = false;
141
+
142
+ const stateFor = (target: RenderTarget): CaptureState => {
143
+ const existing = states.get(target as object);
144
+ if (existing !== undefined) return existing;
145
+ const created: CaptureState = {
146
+ target,
147
+ activeGeneration: 0,
148
+ completedVersion: 0,
149
+ pending: undefined,
150
+ nestedRejections: 0,
151
+ };
152
+ states.set(target as object, created);
153
+ return created;
154
+ };
155
+
156
+ return {
157
+ beginFrame() {
158
+ frameOpen = true;
159
+ if (activeCapture?.pending !== undefined) activeCapture.pending.inFlight = [];
160
+ },
161
+
162
+ request(request) {
163
+ const valid = validateRequest(request);
164
+ if (!valid.ok) return valid;
165
+ const state = stateFor(request.target);
166
+ if (activeCapture?.pending !== undefined) {
167
+ state.nestedRejections += 1;
168
+ return invalid('generation-mismatch');
169
+ }
170
+ const shouldSchedule =
171
+ request.updateIntent === 'continuous' ||
172
+ state.activeGeneration === 0 ||
173
+ request.requestVersion > state.completedVersion;
174
+ if (!shouldSchedule) return { ok: true, value: { scheduled: false } };
175
+ const views = buildCubeCameraFaceViews({
176
+ position: request.position,
177
+ near: request.near,
178
+ far: request.far,
179
+ });
180
+ const pending: PendingCapture = {
181
+ request,
182
+ views,
183
+ candidateGeneration: state.activeGeneration + 1,
184
+ written: new Set(),
185
+ inFlight: [],
186
+ };
187
+ state.pending = pending;
188
+ activeCapture = state;
189
+ return { ok: true, value: { scheduled: true } };
190
+ },
191
+
192
+ nextWork() {
193
+ if (!frameOpen || activeCapture?.pending === undefined) return [];
194
+ const pending = activeCapture.pending;
195
+ if (pending.inFlight.length > 0) return pending.inFlight;
196
+ const remaining = pending.views.filter((view) => !pending.written.has(view.face));
197
+ const count = Math.min(maxFacesPerFrame, pending.request.faceBudget, remaining.length);
198
+ const work = remaining.slice(0, count).map((view) => ({
199
+ ...view,
200
+ target: pending.request.target,
201
+ requestVersion: pending.request.requestVersion,
202
+ candidateGeneration: pending.candidateGeneration,
203
+ }));
204
+ pending.inFlight = work;
205
+ return work;
206
+ },
207
+
208
+ completeSubmission(submitted, completed) {
209
+ const state = activeCapture;
210
+ const pending = state?.pending;
211
+ if (state === undefined || pending === undefined) return invalid('uninitialized');
212
+ if (!submitted) {
213
+ state.pending = undefined;
214
+ activeCapture = undefined;
215
+ return failed(pending.candidateGeneration, new Error('cube capture submission failed'));
216
+ }
217
+ const commit = (): void => {
218
+ if (activeCapture !== state || state.pending !== pending) return;
219
+ for (const work of pending.inFlight) pending.written.add(work.face);
220
+ pending.inFlight = [];
221
+ if (pending.written.size === CUBE_CAMERA_FACE_ORDER.length) {
222
+ state.activeGeneration = pending.candidateGeneration;
223
+ state.completedVersion = pending.request.requestVersion;
224
+ state.pending = undefined;
225
+ activeCapture = undefined;
226
+ }
227
+ };
228
+ if (completed === undefined) commit();
229
+ else
230
+ void completed.then(commit, () => {
231
+ if (activeCapture === state && state.pending === pending) {
232
+ state.pending = undefined;
233
+ activeCapture = undefined;
234
+ }
235
+ });
236
+ return { ok: true, value: undefined };
237
+ },
238
+
239
+ inspect(target) {
240
+ const state = stateFor(target);
241
+ const pending = state.pending;
242
+ const pendingFaces =
243
+ pending === undefined
244
+ ? []
245
+ : pending.views
246
+ .filter(
247
+ (view) =>
248
+ !pending.written.has(view.face) &&
249
+ !pending.inFlight.some((work) => work.face === view.face),
250
+ )
251
+ .map((view) => view.face);
252
+ return Object.freeze({
253
+ target: state.target,
254
+ activeGeneration: state.activeGeneration,
255
+ ...(state.pending === undefined
256
+ ? {}
257
+ : { candidateGeneration: state.pending.candidateGeneration }),
258
+ completedVersion: state.completedVersion,
259
+ pendingFaces,
260
+ fallback: state.activeGeneration === 0 ? 'neutral' : 'previous-active',
261
+ nestedRejections: state.nestedRejections,
262
+ });
263
+ },
264
+ };
265
+ }
@@ -5,6 +5,18 @@ describe('canonical render schema owners', () => {
5
5
  it('keeps mesh, light, and camera facts on their component owners', () => {
6
6
  expect(MeshFilter.fields.assetHandle.type).toBe('shared<MeshAsset>');
7
7
  expect(DirectionalLight.fields.direction.type).toBe('array<f32, 3>');
8
+ expect(DirectionalLight.fields.shadowFilter.type).toBe('enum');
9
+ expect(DirectionalLight.fields.shadowFilter.default).toBe(2);
10
+ expect(DirectionalLight.fields.shadowFilter.labels).toEqual({
11
+ pcf1: 1,
12
+ pcf3: 2,
13
+ pcf5: 3,
14
+ pcssMedium: 4,
15
+ pcssHigh: 5,
16
+ });
17
+ expect(DirectionalLight.fields.shadowAngularRadius.default).toBeCloseTo(0.00465, 8);
18
+ expect(DirectionalLight.fields.maxPenumbraTexels.default).toBe(32);
19
+ expect('pcfKernelSize' in DirectionalLight.fields).toBe(false);
8
20
  expect(Camera.fields.projection.default).toBe(0);
9
21
  expect(Camera.fields.antialias.default).toBe(0);
10
22
  expect(Camera.fields.historyVersion.default).toBe(0);
@@ -13,6 +13,15 @@ describe('render schema parity', () => {
13
13
  expect(MeshFilter.fields.assetHandle.type).toBe('shared<MeshAsset>');
14
14
  expect(DirectionalLight.fields.direction.type).toBe('array<f32, 3>');
15
15
  expect(DirectionalLight.fields.castShadow.default).toBe(true);
16
+ expect(DirectionalLight.fields.shadowFilter.labels).toEqual({
17
+ pcf1: 1,
18
+ pcf3: 2,
19
+ pcf5: 3,
20
+ pcssMedium: 4,
21
+ pcssHigh: 5,
22
+ });
23
+ expect(DirectionalLight.fields.shadowFilter.default).toBe(2);
24
+ expect('pcfKernelSize' in DirectionalLight.fields).toBe(false);
16
25
  expect(MeshRenderer.fields.materials.type).toBe('array<shared<MaterialAsset>>');
17
26
  });
18
27
 
@@ -320,6 +320,10 @@ export const Camera = defineComponent('Camera', {
320
320
  bloomThreshold: { type: 'f32', default: 1.0 },
321
321
  bloomIntensity: { type: 'f32', default: 1.0 },
322
322
  bloomBlurRadius: { type: 'f32', default: 4.0 },
323
+ // M1 target camera role: zero means this camera is eligible for display;
324
+ // non-zero shared targets are auxiliary producers whose views and receipt
325
+ // promotion remain owned by Renderer.
326
+ target: { type: 'shared<RenderTarget>', simulationTransient: true },
323
327
  // feat-20260709 M3 / D-3: clear-color is one inline `array<f32,4>` column.
324
328
  // The earlier 4-scalar form (clearR/G/B/A) was chosen when this was believed
325
329
  // to be the only SoA-safe shape; the Transform (pos/quat/scale) and light
@@ -0,0 +1,52 @@
1
+ // @forgeax/engine-render - CubeCamera capture vocabulary.
2
+ //
3
+ // CubeCamera is an ECS capture intent paired with Transform. GPU resources,
4
+ // face views, completed-receipt promotion, and publication remain renderer-owned.
5
+
6
+ import { defineComponent, type SchemaOf, type ShapeOf } from '@forgeax/engine-ecs';
7
+ import { RenderIntentInvalidError } from '../errors/render';
8
+
9
+ export const CUBE_CAMERA_UPDATE_ONCE = 0;
10
+ export const CUBE_CAMERA_UPDATE_ON_DEMAND = 1;
11
+ export const CUBE_CAMERA_UPDATE_CONTINUOUS = 2;
12
+
13
+ export type CubeCameraUpdateIntent = 'once' | 'on-demand' | 'continuous';
14
+
15
+ export const CUBE_CAMERA_FACE_ORDER = ['+X', '-X', '+Y', '-Y', '+Z', '-Z'] as const;
16
+ export type CubeCameraFace = (typeof CUBE_CAMERA_FACE_ORDER)[number];
17
+
18
+ export function cubeCameraUpdateIntentFromF32(value: number): CubeCameraUpdateIntent {
19
+ switch (value) {
20
+ case CUBE_CAMERA_UPDATE_ONCE:
21
+ return 'once';
22
+ case CUBE_CAMERA_UPDATE_ON_DEMAND:
23
+ return 'on-demand';
24
+ case CUBE_CAMERA_UPDATE_CONTINUOUS:
25
+ return 'continuous';
26
+ default:
27
+ throw new RenderIntentInvalidError('CubeCamera', value);
28
+ }
29
+ }
30
+
31
+ export function cubeCameraUpdateIntentToF32(intent: CubeCameraUpdateIntent): number {
32
+ switch (intent) {
33
+ case 'once':
34
+ return CUBE_CAMERA_UPDATE_ONCE;
35
+ case 'on-demand':
36
+ return CUBE_CAMERA_UPDATE_ON_DEMAND;
37
+ case 'continuous':
38
+ return CUBE_CAMERA_UPDATE_CONTINUOUS;
39
+ }
40
+ }
41
+
42
+ /** ECS declaration for a bounded, transient six-face capture request. */
43
+ export const CubeCamera = defineComponent('CubeCamera', {
44
+ target: { type: 'shared<RenderTarget>', simulationTransient: true },
45
+ near: { type: 'f32', default: 0.1 },
46
+ far: { type: 'f32', default: 100 },
47
+ updateIntent: { type: 'f32', default: CUBE_CAMERA_UPDATE_ONCE },
48
+ requestVersion: { type: 'u32', default: 0 },
49
+ faceBudget: { type: 'u32', default: 1 },
50
+ });
51
+
52
+ export type CubeCameraData = ShapeOf<SchemaOf<typeof CubeCamera>>;
@@ -31,6 +31,14 @@
31
31
  // with the shadow atlas owner.
32
32
 
33
33
  import { defineComponent } from '@forgeax/engine-ecs';
34
+ import { DirectionalShadowFilterValue } from './directional-shadow-filter';
35
+
36
+ export {
37
+ type DirectionalShadowFilterLabel,
38
+ DirectionalShadowFilterValue,
39
+ type DirectionalShadowQuality,
40
+ directionalShadowQualityFromF32,
41
+ } from './directional-shadow-filter';
34
42
 
35
43
  /**
36
44
  * Directional light (sun-like infinite light source) with merged shadow
@@ -64,7 +72,9 @@ import { defineComponent } from '@forgeax/engine-ecs';
64
72
  * plane (no separate near knob — any value other
65
73
  * than the camera near either drops near shadows
66
74
  * or wastes cascade-0 resolution).
67
- * pcfKernelSize odd >= 1 PCF kernel width (default 3)
75
+ * shadowFilter ∈ {pcf1, pcf3, pcf5, pcssMedium, pcssHigh} closed filter profile (default pcf3)
76
+ * shadowAngularRadius ∈ [0.0001, 0.05] radians — PCSS angular light radius (default 0.00465)
77
+ * maxPenumbraTexels ∈ [1, 64], finite integer — PCSS search/filter cap (default 32)
68
78
  *
69
79
  * @example Spawn a single directional light with default shadows:
70
80
  * world.spawn({ component: DirectionalLight, data: {
@@ -85,7 +95,11 @@ import { defineComponent } from '@forgeax/engine-ecs';
85
95
  * color: [1, 1, 1], intensity: 1, // color is [r, g, b]
86
96
  * cascadeCount: 4, splitLambda: 0.75, cascadeBlend: 0.2,
87
97
  * mapSize: 2048, shadowDistance: 200,
98
+ * shadowFilter: DirectionalShadowFilterValue.pcssHigh,
99
+ * shadowAngularRadius: 0.00465, maxPenumbraTexels: 32,
88
100
  * } });
101
+ * // shadowFilter uses the numeric DirectionalShadowFilterValue constant,
102
+ * // not the serialized label string 'pcssHigh'.
89
103
  *
90
104
  * @example 0-light scene must use an unlit shader (standard 0 light = physically correct black):
91
105
  * const world = new World();
@@ -116,5 +130,11 @@ export const DirectionalLight = defineComponent('DirectionalLight', {
116
130
  // reach. Default 200 world units (matches UE-style "dynamic shadow
117
131
  // distance"; the old farPlane default was 50).
118
132
  shadowDistance: { type: 'f32', default: 200 },
119
- pcfKernelSize: { type: 'f32', default: 3 },
133
+ shadowFilter: {
134
+ type: 'enum',
135
+ default: DirectionalShadowFilterValue.pcf3,
136
+ labels: DirectionalShadowFilterValue,
137
+ },
138
+ shadowAngularRadius: { type: 'f32', default: 0.00465 },
139
+ maxPenumbraTexels: { type: 'f32', default: 32 },
120
140
  });
@@ -0,0 +1,57 @@
1
+ // @forgeax/engine-render - closed Directional shadow filter vocabulary.
2
+
3
+ /** Stable serialized labels for Directional shadow filtering. */
4
+ export const DirectionalShadowFilterValue = Object.freeze({
5
+ pcf1: 1,
6
+ pcf3: 2,
7
+ pcf5: 3,
8
+ pcssMedium: 4,
9
+ pcssHigh: 5,
10
+ } as const);
11
+
12
+ export type DirectionalShadowFilterLabel = keyof typeof DirectionalShadowFilterValue;
13
+
14
+ /**
15
+ * Extract-side semantic projection of the serialized Directional filter.
16
+ * `shadowAngularRadius` is radians and `maxPenumbraTexels` is a finite integer.
17
+ */
18
+ export type DirectionalShadowQuality =
19
+ | { readonly kind: 'pcf'; readonly kernel: 1 | 3 | 5 }
20
+ | {
21
+ readonly kind: 'pcss';
22
+ readonly preset: 'medium' | 'high';
23
+ readonly angularRadiusRadians: number;
24
+ readonly maxPenumbraTexels: number;
25
+ };
26
+
27
+ /** Resolve the closed serialized label to the receiver-facing semantic union. */
28
+ export function directionalShadowQualityFromF32(
29
+ value: number,
30
+ angularRadiusRadians: number,
31
+ maxPenumbraTexels: number,
32
+ ): DirectionalShadowQuality | undefined {
33
+ switch (value) {
34
+ case DirectionalShadowFilterValue.pcf1:
35
+ return { kind: 'pcf', kernel: 1 };
36
+ case DirectionalShadowFilterValue.pcf3:
37
+ return { kind: 'pcf', kernel: 3 };
38
+ case DirectionalShadowFilterValue.pcf5:
39
+ return { kind: 'pcf', kernel: 5 };
40
+ case DirectionalShadowFilterValue.pcssMedium:
41
+ return {
42
+ kind: 'pcss',
43
+ preset: 'medium',
44
+ angularRadiusRadians,
45
+ maxPenumbraTexels,
46
+ };
47
+ case DirectionalShadowFilterValue.pcssHigh:
48
+ return {
49
+ kind: 'pcss',
50
+ preset: 'high',
51
+ angularRadiusRadians,
52
+ maxPenumbraTexels,
53
+ };
54
+ default:
55
+ return undefined;
56
+ }
57
+ }
@@ -1,5 +1,6 @@
1
1
  export * from './atmosphere';
2
2
  export * from './camera';
3
+ export * from './cube-camera';
3
4
  export * from './directional-light';
4
5
  export * from './fog';
5
6
  export { Instances, type InstancesData } from './instances';
@@ -17,6 +18,7 @@ export {
17
18
  pointShapeFromU32,
18
19
  } from './points';
19
20
  export { PostProcessParams } from './post-process-params';
21
+ export * from './reflection-probe';
20
22
  export {
21
23
  SceneInstance,
22
24
  type SceneInstanceOverrideRecord,