@forgeax/engine-render 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/README.md +215 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/assembly/device-feature-admission.d.ts +18 -0
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  5. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  7. package/dist/assembly/factory.d.ts +21 -18
  8. package/dist/assembly/factory.d.ts.map +1 -1
  9. package/dist/assembly/host-contract.d.ts +9 -0
  10. package/dist/assembly/host-contract.d.ts.map +1 -1
  11. package/dist/assembly/render-target-host.d.ts +46 -0
  12. package/dist/assembly/render-target-host.d.ts.map +1 -0
  13. package/dist/assets/render-asset-port.d.ts.map +1 -1
  14. package/dist/authoring.mjs +3 -0
  15. package/dist/authoring.mjs.map +1 -1
  16. package/dist/capture/cube-views.d.ts +21 -0
  17. package/dist/capture/cube-views.d.ts.map +1 -0
  18. package/dist/capture/scheduler.d.ts +54 -0
  19. package/dist/capture/scheduler.d.ts.map +1 -0
  20. package/dist/{chunk-4XINDLAY.mjs → chunk-5YADUCA7.mjs} +1552 -1361
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-TBQJOK2L.mjs → chunk-6OPXDQ2E.mjs} +364 -51
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-M2MP4ZOU.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/{chunk-CDTWTHZR.mjs → chunk-FS2KNUQH.mjs} +548 -6
  27. package/dist/chunk-FS2KNUQH.mjs.map +1 -0
  28. package/dist/components/camera.d.ts +1 -0
  29. package/dist/components/camera.d.ts.map +1 -1
  30. package/dist/components/cube-camera.d.ts +20 -0
  31. package/dist/components/cube-camera.d.ts.map +1 -0
  32. package/dist/components/directional-light.d.ts +11 -2
  33. package/dist/components/directional-light.d.ts.map +1 -1
  34. package/dist/components/directional-shadow-filter.d.ts +25 -0
  35. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/light-helpers.d.ts.map +1 -1
  39. package/dist/components/reflection-probe.d.ts +17 -0
  40. package/dist/components/reflection-probe.d.ts.map +1 -0
  41. package/dist/construct-renderer.mjs +5826 -1003
  42. package/dist/construct-renderer.mjs.map +1 -1
  43. package/dist/environment/frame.d.ts.map +1 -1
  44. package/dist/environment/lifecycle.d.ts +5 -0
  45. package/dist/environment/lifecycle.d.ts.map +1 -1
  46. package/dist/errors/render.d.ts +141 -93
  47. package/dist/errors/render.d.ts.map +1 -1
  48. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  49. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  50. package/dist/extract/environment.d.ts +14 -0
  51. package/dist/extract/environment.d.ts.map +1 -1
  52. package/dist/extract/visibility.d.ts.map +1 -1
  53. package/dist/features/fullscreen.d.ts.map +1 -1
  54. package/dist/features/targets.d.ts.map +1 -1
  55. package/dist/features/types.d.ts +10 -0
  56. package/dist/features/types.d.ts.map +1 -1
  57. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  58. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  59. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  60. package/dist/gpu-driven/production-raster.d.ts +0 -1
  61. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  62. package/dist/gpu-scene.d.ts.map +1 -1
  63. package/dist/hdrp-buffers.d.ts +19 -17
  64. package/dist/hdrp-buffers.d.ts.map +1 -1
  65. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  66. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  67. package/dist/ibl/kernel-cache.d.ts +36 -0
  68. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  69. package/dist/index.d.ts +28 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.mjs +4 -4
  72. package/dist/index.mjs.map +1 -1
  73. package/dist/inspection-types.d.ts +51 -0
  74. package/dist/inspection-types.d.ts.map +1 -1
  75. package/dist/instances-derived-bounds.d.ts +50 -0
  76. package/dist/instances-derived-bounds.d.ts.map +1 -0
  77. package/dist/internal.mjs +1 -1
  78. package/dist/light-buffer-layout.d.ts +10 -1
  79. package/dist/light-buffer-layout.d.ts.map +1 -1
  80. package/dist/mesh-material-bindings.d.ts +54 -0
  81. package/dist/mesh-material-bindings.d.ts.map +1 -1
  82. package/dist/pbr-pipeline.d.ts +14 -4
  83. package/dist/pbr-pipeline.d.ts.map +1 -1
  84. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  85. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  86. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  87. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  88. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  89. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  90. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  91. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  92. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  93. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  95. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  97. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  99. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  101. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  103. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  104. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  105. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  106. package/dist/pipeline/standard-post.d.ts.map +1 -1
  107. package/dist/pipeline/standard-profile.d.ts +5 -26
  108. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  109. package/dist/pipeline-spec.d.ts +40 -7
  110. package/dist/pipeline-spec.d.ts.map +1 -1
  111. package/dist/point-shadow-inspection.d.ts +21 -0
  112. package/dist/point-shadow-inspection.d.ts.map +1 -0
  113. package/dist/record/frame-lighting.d.ts +27 -32
  114. package/dist/record/frame-lighting.d.ts.map +1 -1
  115. package/dist/record/frame-snapshot.d.ts +28 -14
  116. package/dist/record/frame-snapshot.d.ts.map +1 -1
  117. package/dist/record/frame-targets.d.ts +5 -0
  118. package/dist/record/frame-targets.d.ts.map +1 -1
  119. package/dist/record/frame.d.ts +10 -4
  120. package/dist/record/frame.d.ts.map +1 -1
  121. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  122. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  123. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  124. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  125. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  126. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  127. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  128. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  130. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  131. package/dist/record/gpu-timing.d.ts +8 -3
  132. package/dist/record/gpu-timing.d.ts.map +1 -1
  133. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  134. package/dist/record/main-pass-material.d.ts +22 -1
  135. package/dist/record/main-pass-material.d.ts.map +1 -1
  136. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  137. package/dist/record/main-pass.d.ts +2 -0
  138. package/dist/record/main-pass.d.ts.map +1 -1
  139. package/dist/record/render-context.d.ts +43 -2
  140. package/dist/record/render-context.d.ts.map +1 -1
  141. package/dist/record/shadow-pass.d.ts.map +1 -1
  142. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  143. package/dist/record/typed-frame-graph.d.ts +72 -4
  144. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  145. package/dist/record/view-ubo.d.ts +7 -4
  146. package/dist/record/view-ubo.d.ts.map +1 -1
  147. package/dist/reflection/filter.d.ts +22 -0
  148. package/dist/reflection/filter.d.ts.map +1 -0
  149. package/dist/reflection/gpu-table.d.ts +25 -0
  150. package/dist/reflection/gpu-table.d.ts.map +1 -0
  151. package/dist/reflection/projection.d.ts +91 -0
  152. package/dist/reflection/projection.d.ts.map +1 -0
  153. package/dist/render-contract.d.ts +49 -7
  154. package/dist/render-contract.d.ts.map +1 -1
  155. package/dist/render-graph-primitives.d.ts +1 -0
  156. package/dist/render-graph-primitives.d.ts.map +1 -1
  157. package/dist/render-pipeline.d.ts +42 -2
  158. package/dist/render-pipeline.d.ts.map +1 -1
  159. package/dist/render-system-extract.d.ts +58 -17
  160. package/dist/render-system-extract.d.ts.map +1 -1
  161. package/dist/render-system.d.ts +17 -2
  162. package/dist/render-system.d.ts.map +1 -1
  163. package/dist/renderer.d.ts +43 -0
  164. package/dist/renderer.d.ts.map +1 -0
  165. package/dist/scene/render-scene.d.ts +14 -0
  166. package/dist/scene/render-scene.d.ts.map +1 -1
  167. package/dist/shadow-atlas.d.ts +3 -3
  168. package/dist/shadow-atlas.d.ts.map +1 -1
  169. package/dist/ssao-buffers.d.ts +3 -0
  170. package/dist/ssao-buffers.d.ts.map +1 -1
  171. package/dist/targets/contracts.d.ts +66 -0
  172. package/dist/targets/contracts.d.ts.map +1 -0
  173. package/dist/targets/graph-projection.d.ts +29 -0
  174. package/dist/targets/graph-projection.d.ts.map +1 -0
  175. package/dist/targets/material-source.d.ts +34 -0
  176. package/dist/targets/material-source.d.ts.map +1 -0
  177. package/dist/targets/owner.d.ts +32 -0
  178. package/dist/targets/owner.d.ts.map +1 -0
  179. package/dist/targets/physical.d.ts +18 -0
  180. package/dist/targets/physical.d.ts.map +1 -0
  181. package/dist/targets/readback.d.ts +39 -0
  182. package/dist/targets/readback.d.ts.map +1 -0
  183. package/dist/temporal/index.mjs +3 -3
  184. package/dist/typed-render-graph-primitives.d.ts +1 -1
  185. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  186. package/dist/typed-shadow-passes.d.ts +1 -1
  187. package/dist/typed-shadow-passes.d.ts.map +1 -1
  188. package/dist/volume/passes.d.ts +2 -2
  189. package/dist/volume/passes.d.ts.map +1 -1
  190. package/package.json +20 -20
  191. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  192. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  193. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  194. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  195. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  196. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  197. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  198. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  199. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  200. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  201. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  202. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  203. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  204. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  205. package/src/__tests__/fog-component.unit.test.ts +67 -0
  206. package/src/__tests__/fog.integration.test.ts +86 -0
  207. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  208. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  209. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  210. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  211. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  212. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  213. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  214. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  215. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  216. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  217. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  218. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  219. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  220. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  221. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  222. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  223. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  224. package/src/__tests__/material-observation.integration.test.ts +101 -0
  225. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  226. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  227. package/src/__tests__/public-surface.test-d.ts +10 -0
  228. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  229. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  230. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  231. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  232. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  233. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  234. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  235. package/src/__tests__/render-error-code-owner.test-d.ts +18 -3
  236. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  237. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  238. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  239. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  240. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  241. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  242. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  243. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  244. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  245. package/src/__tests__/render-target-public-schema.json +107 -0
  246. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  247. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  248. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  249. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  250. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +48 -0
  251. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  252. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  253. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  254. package/src/__tests__/skinned-shadow-caster.test.ts +11 -2
  255. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  256. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  257. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  258. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  259. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  260. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  261. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  262. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  263. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  264. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  265. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  266. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -38
  267. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  268. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  269. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  270. package/src/assembly/device-feature-admission.ts +73 -0
  271. package/src/assembly/directional-shadow-inspection.ts +122 -0
  272. package/src/assembly/factory.ts +877 -286
  273. package/src/assembly/host-contract.ts +25 -0
  274. package/src/assembly/render-target-host.ts +847 -0
  275. package/src/assets/asset-decoders.ts +1 -1
  276. package/src/assets/render-asset-port.ts +7 -1
  277. package/src/capture/cube-views.ts +69 -0
  278. package/src/capture/scheduler.ts +265 -0
  279. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  280. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  281. package/src/components/camera.ts +4 -0
  282. package/src/components/cube-camera.ts +52 -0
  283. package/src/components/directional-light.ts +22 -2
  284. package/src/components/directional-shadow-filter.ts +57 -0
  285. package/src/components/index.ts +2 -0
  286. package/src/components/light-helpers.ts +81 -7
  287. package/src/components/reflection-probe.ts +49 -0
  288. package/src/environment/frame.ts +6 -24
  289. package/src/environment/lifecycle.ts +12 -0
  290. package/src/errors/render.ts +286 -142
  291. package/src/extract/directional-shadow-projection.ts +61 -0
  292. package/src/extract/environment.ts +57 -0
  293. package/src/extract/visibility.ts +25 -1
  294. package/src/features/fullscreen.ts +3 -0
  295. package/src/features/targets.ts +4 -1
  296. package/src/features/types.ts +10 -0
  297. package/src/fullscreen-post-process-pass.ts +43 -2
  298. package/src/gpu-driven/batch-topology.ts +1 -0
  299. package/src/gpu-driven/production-raster.ts +1 -3
  300. package/src/gpu-scene.ts +8 -1
  301. package/src/hdrp-buffers.ts +165 -59
  302. package/src/ibl/IblPipelineCache.ts +11 -0
  303. package/src/ibl/kernel-cache.ts +88 -0
  304. package/src/index.ts +148 -0
  305. package/src/inspection-types.ts +56 -0
  306. package/src/instances-derived-bounds.ts +171 -0
  307. package/src/light-buffer-layout.ts +20 -5
  308. package/src/mesh-material-bindings.ts +132 -0
  309. package/src/pbr-pipeline.ts +106 -17
  310. package/src/pipeline/standard-forward-lane.ts +46 -16
  311. package/src/pipeline/standard-lighting/errors.ts +6 -0
  312. package/src/pipeline/standard-lighting/graph.ts +157 -0
  313. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  314. package/src/pipeline/standard-lighting/layout.ts +31 -0
  315. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  316. package/src/pipeline/standard-lighting/membership.ts +43 -0
  317. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  318. package/src/pipeline/standard-lighting/topology.ts +120 -0
  319. package/src/pipeline/standard-lighting/transport.ts +77 -0
  320. package/src/pipeline/standard-pipeline.ts +122 -193
  321. package/src/pipeline/standard-post.ts +26 -7
  322. package/src/pipeline/standard-profile.ts +17 -47
  323. package/src/pipeline-spec.ts +84 -21
  324. package/src/point-shadow-inspection.ts +55 -0
  325. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  326. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  327. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  328. package/src/record/frame-lighting.ts +367 -427
  329. package/src/record/frame-snapshot.ts +35 -27
  330. package/src/record/frame-targets.ts +17 -0
  331. package/src/record/frame.ts +261 -74
  332. package/src/record/gpu-pass-timing/contract.ts +180 -0
  333. package/src/record/gpu-pass-timing/errors.ts +34 -0
  334. package/src/record/gpu-pass-timing/index.ts +37 -0
  335. package/src/record/gpu-pass-timing/parser.ts +97 -0
  336. package/src/record/gpu-pass-timing/session.ts +938 -0
  337. package/src/record/gpu-timing.ts +21 -12
  338. package/src/record/main-pass-geometry.ts +120 -80
  339. package/src/record/main-pass-material.ts +95 -9
  340. package/src/record/main-pass-sprite-draws.ts +54 -25
  341. package/src/record/main-pass.ts +71 -15
  342. package/src/record/render-context.ts +72 -0
  343. package/src/record/shadow-pass.ts +17 -28
  344. package/src/record/skybox-post-pass.ts +20 -4
  345. package/src/record/typed-frame-graph.ts +893 -44
  346. package/src/record/view-ubo.ts +63 -28
  347. package/src/reflection/filter.ts +81 -0
  348. package/src/reflection/gpu-table.ts +44 -0
  349. package/src/reflection/projection.ts +281 -0
  350. package/src/render-contract.ts +76 -5
  351. package/src/render-graph-primitives.ts +9 -4
  352. package/src/render-pipeline.ts +117 -2
  353. package/src/render-system-extract.ts +557 -100
  354. package/src/render-system.ts +1095 -66
  355. package/src/renderer.ts +222 -0
  356. package/src/scene/render-scene.ts +115 -9
  357. package/src/shadow-atlas.ts +5 -5
  358. package/src/ssao-buffers.ts +9 -2
  359. package/src/targets/contracts.ts +182 -0
  360. package/src/targets/graph-projection.ts +169 -0
  361. package/src/targets/material-source.ts +143 -0
  362. package/src/targets/owner.ts +214 -0
  363. package/src/targets/physical.ts +18 -0
  364. package/src/targets/readback.ts +153 -0
  365. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
  366. package/src/typed-render-graph-primitives.ts +5 -3
  367. package/src/typed-shadow-passes.ts +46 -40
  368. package/src/volume/passes.ts +15 -9
  369. package/dist/chunk-4XINDLAY.mjs.map +0 -1
  370. package/dist/chunk-CDTWTHZR.mjs.map +0 -1
  371. package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
  372. package/dist/chunk-TBQJOK2L.mjs.map +0 -1
@@ -287,6 +287,69 @@ export function variantSetFromVertexLayoutProjection(
287
287
  return ok(parts.join('+'));
288
288
  }
289
289
 
290
+ /**
291
+ * Derive the capability axes shared by every Standard PBR draw owner.
292
+ *
293
+ * The all-true key is the canonical empty key used by the shader manifest;
294
+ * every other capability pair stays explicit so a no-local-light frame on a
295
+ * device without storage buffers cannot accidentally select a storage-backed
296
+ * PSO. Vertex-color is supplied here because the empty-key rule is only valid
297
+ * when that geometry-owned axis is also true.
298
+ */
299
+ export function standardCapabilityVariantSet(
300
+ clustered: boolean,
301
+ storageBuffer: boolean,
302
+ vertexColorAvailable: boolean,
303
+ ): string {
304
+ if (clustered && storageBuffer && vertexColorAvailable) return '';
305
+ return `CLUSTER_FORWARD_AVAILABLE=${clustered}+STORAGE_BUFFER_AVAILABLE=${storageBuffer}`;
306
+ }
307
+
308
+ /**
309
+ * Project the frame-owned Standard topology onto its material variant axes.
310
+ *
311
+ * `StandardTopologyInputValue.kind` is the only runtime authority for the
312
+ * cluster axis: a frame with local lights must request the clustered artifact,
313
+ * while the no-local-light topology requests the direct artifact. Keeping
314
+ * this projection beside the canonical key builder prevents PBR, skin, and
315
+ * sprite-lit record owners from independently inferring the active lane from
316
+ * whichever bind group happened to be constructed first.
317
+ */
318
+ export function standardTopologyVariantSet(
319
+ topology: { readonly kind: 'no-local-lights' | 'clustered' } | undefined,
320
+ storageBuffer: boolean,
321
+ vertexColorAvailable: boolean,
322
+ ): string {
323
+ return standardCapabilityVariantSet(
324
+ topology?.kind === 'clustered',
325
+ storageBuffer,
326
+ vertexColorAvailable,
327
+ );
328
+ }
329
+
330
+ /**
331
+ * Keep a clustered frame fail-closed when its unified group(2) resource is
332
+ * unavailable. A missing group is not evidence that the frame is direct; it
333
+ * is an invalid prepared resource state.
334
+ */
335
+ export function standardTopologyBindGroupReady(
336
+ topology: { readonly kind: 'no-local-lights' | 'clustered' } | undefined,
337
+ clusterBindGroup: unknown,
338
+ ): boolean {
339
+ return (
340
+ topology?.kind !== 'clustered' || (clusterBindGroup !== null && clusterBindGroup !== undefined)
341
+ );
342
+ }
343
+
344
+ /** Derive the storage axis for Standard-compatible unlit material draws. */
345
+ export function standardStorageVariantSet(
346
+ storageBuffer: boolean,
347
+ vertexColorAvailable: boolean,
348
+ ): string {
349
+ if (storageBuffer && vertexColorAvailable) return '';
350
+ return `STORAGE_BUFFER_AVAILABLE=${storageBuffer}+VERTEX_COLOR_AVAILABLE=${vertexColorAvailable}`;
351
+ }
352
+
290
353
  /**
291
354
  * Build a `GPURenderPipelineDescriptor` from a PipelineSpec + shader modules.
292
355
  *
@@ -925,14 +988,14 @@ const TRI_GEOMETRY_PBR = {
925
988
  shaderUvSetCount: 8,
926
989
  };
927
990
 
928
- // M6 fix-up: URP-variant key string for the standard PBR shader. Mirrors the
929
- // boot-time variantSet computed at createRenderer.ts step 1b when
930
- // `isHdrpActive=false` and `storageBufferCapable=true` (the URP default
931
- // surface). The URP record path requests this exact string at every
991
+ // M6 fix-up: non-clustered boot-variant key string for the standard PBR shader.
992
+ // Mirrors the boot-time variantSet computed at createRenderer.ts step 1b when
993
+ // clustered lighting is not yet admitted and `storageBufferCapable=true` (the
994
+ // surface). The default record path requests this exact string at every
932
995
  // `getMaterialShaderPipeline` call site, so seeding the table with these
933
- // variants keeps the URP cache lookup hot from frame 1 instead of
996
+ // variants keeps the default cache lookup hot from frame 1 instead of
934
997
  // skip-drawing the first ~1 frames while the async compile resolves.
935
- const URP_PBR_VARIANT_SET = 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true';
998
+ const STANDARD_BOOT_VARIANT_SET = standardCapabilityVariantSet(false, true, false);
936
999
 
937
1000
  /**
938
1001
  * Build the boot-time pre-warm table: 15 standard PipelineSpec variants.
@@ -944,22 +1007,22 @@ const URP_PBR_VARIANT_SET = 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAI
944
1007
  *
945
1008
  * Matrix:
946
1009
  * - 8 base material variants — {unlit, standard-pbr} x {LDR, HDR} x {S1, S4}
947
- * - 4 URP-variant standard-pbr — standard-pbr (variantSet=URP_PBR_VARIANT_SET)
948
- * x {LDR, HDR} x {S1, S4}; URP record path requests these specs by
1010
+ * - 4 non-clustered standard-pbr — standard-pbr (variantSet=STANDARD_BOOT_VARIANT_SET)
1011
+ * x {LDR, HDR} x {S1, S4}; the default record path requests these specs by
949
1012
  * `getMaterialShaderPipeline` keying off `cacheKeyOf` so the boot-time
950
1013
  * prewarm seeds `materialShaderPipelineCache` and avoids a 1-frame
951
- * async-compile skip-draw (M6 fix-up; see render-system-record.ts §URP)
1014
+ * async-compile skip-draw (M6 fix-up; see render-system-record.ts)
952
1015
  * - 3 fullscreen-post — tonemap (LDR S1) + skybox (HDR S1, HDR S4)
953
1016
  *
954
- * Total: 15. The URP variant is PBR-only because:
955
- * - unlit URP record path passes `variantSet=undefined` (the no-variant
1017
+ * Total: 15. The non-clustered variant is PBR-only because:
1018
+ * - unlit record path passes `variantSet=undefined` (the no-variant
956
1019
  * boot-default entries already cover it; createRenderer.ts §unlitRsp)
957
1020
  * - sprite goes through `getMaterialShaderPipeline('forgeax::sprite', ...)`
958
1021
  * lazily at first transparent-LDR-split draw — no boot-time pre-warm.
959
- * - HDRP variant (`variantSet=''` or compound `=true` form) is registered
1022
+ * - clustered variant (`variantSet=''` or compound `=true` form) is registered
960
1023
  * lazily when the clustered Standard profile activates, not at boot — adding clustered
961
1024
  * prewarm here would build PSOs against the URP layout (the boot-time
962
- * `pbrModule` is the URP variant when `isHdrpActive=false`)
1025
+ * `pbrModule` is the non-clustered variant before a frame admits local lights)
963
1026
  *
964
1027
  * `ldrViewFormat` parameterises the LDR color attachment format. Callers
965
1028
  * pass the runtime-resolved swap-chain view format (Channel 2 typically
@@ -1074,12 +1137,12 @@ export function buildSpecConstTable(
1074
1137
  renderState: undefined,
1075
1138
  },
1076
1139
 
1077
- // ── M6 fix-up: URP-variant standard-pbr prewarm ─────────────────────────
1078
- // URP record path (`getMaterialShaderPipeline`) requests
1079
- // `variantSet=URP_PBR_VARIANT_SET` for standard-shading entities; pre-M6
1140
+ // ── M6 fix-up: non-clustered standard-pbr prewarm ─────────────────────────
1141
+ // The default record path (`getMaterialShaderPipeline`) requests
1142
+ // `variantSet=STANDARD_BOOT_VARIANT_SET` for standard-shading entities; pre-M6
1080
1143
  // the silent `selectStandardFallbackPipeline` shim served the no-variant
1081
1144
  // boot prewarm during the 1-frame async-compile warmup. With M6's
1082
- // explicit-failure surface, those URP requests must hit the boot prewarm
1145
+ // explicit-failure surface, those requests must hit the boot prewarm
1083
1146
  // by their own variantSet — these 4 entries close that gap.
1084
1147
 
1085
1148
  // standard PBR URP LDR S1
@@ -1087,7 +1150,7 @@ export function buildSpecConstTable(
1087
1150
  shader: {
1088
1151
  id: 'forgeax::default-standard-pbr',
1089
1152
  passKind: 'forward',
1090
- variantSet: URP_PBR_VARIANT_SET,
1153
+ variantSet: STANDARD_BOOT_VARIANT_SET,
1091
1154
  },
1092
1155
  attachments: TRI_ATTACHMENTS_LDR_S1,
1093
1156
  geometry: TRI_GEOMETRY_PBR,
@@ -1098,7 +1161,7 @@ export function buildSpecConstTable(
1098
1161
  shader: {
1099
1162
  id: 'forgeax::default-standard-pbr',
1100
1163
  passKind: 'forward',
1101
- variantSet: URP_PBR_VARIANT_SET,
1164
+ variantSet: STANDARD_BOOT_VARIANT_SET,
1102
1165
  },
1103
1166
  attachments: TRI_ATTACHMENTS_LDR_S4,
1104
1167
  geometry: TRI_GEOMETRY_PBR,
@@ -1109,7 +1172,7 @@ export function buildSpecConstTable(
1109
1172
  shader: {
1110
1173
  id: 'forgeax::default-standard-pbr',
1111
1174
  passKind: 'forward',
1112
- variantSet: URP_PBR_VARIANT_SET,
1175
+ variantSet: STANDARD_BOOT_VARIANT_SET,
1113
1176
  },
1114
1177
  attachments: TRI_ATTACHMENTS_HDR_S1,
1115
1178
  geometry: TRI_GEOMETRY_PBR,
@@ -1120,7 +1183,7 @@ export function buildSpecConstTable(
1120
1183
  shader: {
1121
1184
  id: 'forgeax::default-standard-pbr',
1122
1185
  passKind: 'forward',
1123
- variantSet: URP_PBR_VARIANT_SET,
1186
+ variantSet: STANDARD_BOOT_VARIANT_SET,
1124
1187
  },
1125
1188
  attachments: TRI_ATTACHMENTS_HDR_S4,
1126
1189
  geometry: TRI_GEOMETRY_PBR,
@@ -0,0 +1,55 @@
1
+ import type { PointShadowSnapshot } from './render-system-extract';
2
+
3
+ /**
4
+ * Detached point-shadow budget facts from one completed extract/record frame.
5
+ *
6
+ * `requested` is the number of PointLight + PointLightShadow pairs. The
7
+ * renderer owns the bounded cube-array atlas, so `admitted`, `shadowed`, and
8
+ * `shadowAtlasOccupancy` are all derived from the layer sentinel emitted by
9
+ * the same extract owner. No consumer needs to maintain a second budget
10
+ * ledger.
11
+ */
12
+ export interface PointShadowInspection {
13
+ readonly status: 'inactive' | 'ready' | 'over-budget';
14
+ readonly requested: number;
15
+ readonly admitted: number;
16
+ readonly shadowed: number;
17
+ readonly shadowAtlasOccupancy: number;
18
+ readonly shadowAtlasCapacity: number;
19
+ }
20
+
21
+ /** Project point-shadow snapshots to the public, JSON-safe inspection shape. */
22
+ export function inspectPointShadow(
23
+ snapshots: readonly PointShadowSnapshot[],
24
+ shadowAtlasCapacity: number,
25
+ ): PointShadowInspection {
26
+ const requested = snapshots.length;
27
+ const admitted = snapshots.reduce(
28
+ (count, snapshot) =>
29
+ snapshot.shadowAtlasLayer >= 0 && snapshot.shadowAtlasLayer < shadowAtlasCapacity
30
+ ? count + 1
31
+ : count,
32
+ 0,
33
+ );
34
+ // Never publish a misleading `ready` state when any requested shadow owns
35
+ // no atlas layer. The extract sentinel is the single admission projection;
36
+ // a partial or all-sentinel frame is therefore a failed/over-budget
37
+ // admission, not an active shadow path with incomplete output.
38
+ const status =
39
+ requested === 0
40
+ ? ('inactive' as const)
41
+ : requested > shadowAtlasCapacity || admitted !== requested
42
+ ? ('over-budget' as const)
43
+ : ('ready' as const);
44
+ return Object.freeze({
45
+ status,
46
+ requested,
47
+ admitted,
48
+ // A point shadow only samples an atlas after it owns an atlas layer. Keep
49
+ // these names explicit for AI diagnostics while deriving both from the
50
+ // one layer projection above.
51
+ shadowed: admitted,
52
+ shadowAtlasOccupancy: admitted,
53
+ shadowAtlasCapacity,
54
+ });
55
+ }
@@ -2,7 +2,7 @@ import { vec3 } from '@forgeax/engine-math';
2
2
  import type { Buffer, RhiQueue } from '@forgeax/engine-rhi';
3
3
  import { describe, expect, it } from 'vitest';
4
4
  import type { CameraSnapshot } from '../../render-contract';
5
- import type { RenderableSnapshot } from '../../render-system-extract';
5
+ import type { RenderableSnapshot, SpotLightSnapshot } from '../../render-system-extract';
6
6
  import type { TemporalView } from '../../temporal/temporal-view';
7
7
  import type { ValidatedRenderable } from '../frame-snapshot';
8
8
  import { uploadMeshSsboBatch } from '../mesh-ssbo';
@@ -98,6 +98,47 @@ function temporalView(): TemporalView {
98
98
  }
99
99
 
100
100
  describe('temporal GPU payloads', () => {
101
+ it('publishes a projector-only SpotLight matrix into the explicit lane-0 contract', () => {
102
+ const { queue, uploads } = recordingQueue();
103
+ const projectorMatrix = translatedMatrix(9);
104
+ const projector: SpotLightSnapshot = {
105
+ kind: 'spot',
106
+ entity: 4,
107
+ position: vec3.create(0, 2, 0),
108
+ direction: vec3.create(0, -1, 0),
109
+ color: vec3.create(1, 1, 1),
110
+ intensity: 1,
111
+ invRangeSquared: 0.04,
112
+ cosInner: 0.95,
113
+ cosOuter: 0.8,
114
+ castShadow: false,
115
+ lightViewProj: projectorMatrix,
116
+ mapSize: 512,
117
+ nearPlane: 0.1,
118
+ farPlane: 25,
119
+ shadowAtlasTile: -1,
120
+ projectorAsset: { kind: 'texture' } as never,
121
+ };
122
+ writeViewUbo(
123
+ queue,
124
+ {} as Buffer,
125
+ camera(),
126
+ {
127
+ kind: 'directional',
128
+ direction: vec3.create(0, -1, 0),
129
+ color: vec3.create(1, 1, 1),
130
+ intensity: 1,
131
+ },
132
+ { point: [], spot: [projector] } as never,
133
+ [projector],
134
+ undefined,
135
+ undefined,
136
+ 0,
137
+ );
138
+ const payload = new Float32Array(uploads[0]?.buffer ?? new ArrayBuffer(0));
139
+ expect(payload[132 + 12]).toBe(9);
140
+ });
141
+
101
142
  it('writes temporal current/previous projection after the spot-light lanes', () => {
102
143
  const { queue, uploads } = recordingQueue();
103
144
  writeViewUbo(
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { selectPipelineLayoutForVariant } from '../../assembly/factory';
3
+ import { resolvePipelineGroup2Contract } from '../../pbr-pipeline';
4
+ import { projectDeviceOwnedBindGroup } from '../frame-lighting';
5
+ import { selectMaterialGroup2 } from '../main-pass-material';
6
+
7
+ const meshGroup = { label: 'pbr-mesh-bg' } as never;
8
+ const clusterGroup = { label: 'hdrp-unified-bg-group2' } as never;
9
+
10
+ describe('transparent material group 2 selection', () => {
11
+ it('uses the shared cluster layout only for standard materials', () => {
12
+ expect(selectMaterialGroup2(clusterGroup, meshGroup, 'cluster')).toBe(clusterGroup);
13
+ expect(selectMaterialGroup2(clusterGroup, meshGroup, 'mesh')).toBe(meshGroup);
14
+ });
15
+
16
+ it('returns null when a non-standard material lacks its ordinary mesh group', () => {
17
+ expect(selectMaterialGroup2(clusterGroup, null, 'mesh')).toBeNull();
18
+ });
19
+
20
+ it('resolves mesh, skin, and clustered skin from the composed shader artifact', () => {
21
+ expect(
22
+ resolvePipelineGroup2Contract('@group(2) @binding(0) var<storage> mesh: array<u32>;'),
23
+ ).toBe('mesh');
24
+ expect(
25
+ resolvePipelineGroup2Contract(
26
+ '@group(2) @binding(0) var<storage> mesh: array<u32>; @group(2) @binding(1) var<uniform> palette: mat4x4<f32>;',
27
+ ),
28
+ ).toBe('skin');
29
+ expect(
30
+ resolvePipelineGroup2Contract(
31
+ '@group(2) @binding(0) var<storage> mesh: array<u32>; @group(2) @binding(1) var<storage> palette: array<u32>; @group(2) @binding(4) var<storage> lights: array<u32>;',
32
+ ),
33
+ ).toBe('skin-cluster');
34
+ });
35
+
36
+ it('lets the resolved clustered contract select the unified group', () => {
37
+ expect(selectMaterialGroup2(clusterGroup, meshGroup, 'cluster')).toBe(clusterGroup);
38
+ expect(selectMaterialGroup2(clusterGroup, meshGroup, 'skin')).toBeNull();
39
+ // A skin-cluster PSO cannot consume the ordinary HDRP group. The caller
40
+ // must provide the dedicated skin bind group through the skin path; when
41
+ // it is absent, fail-stop instead of submitting a layout-invalid draw.
42
+ expect(selectMaterialGroup2(clusterGroup, meshGroup, 'skin-cluster')).toBeNull();
43
+ });
44
+
45
+ it('keeps a mesh contract on the mesh pipeline despite the HDRP variant key', () => {
46
+ const pbrPipelineLayout = { label: 'pbr-pl' } as never;
47
+ const hdrpPipelineLayout = { label: 'hdrp-pbr-pl' } as never;
48
+ expect(
49
+ selectPipelineLayoutForVariant(
50
+ {
51
+ pbrPipelineLayout,
52
+ hdrpPbrPipelineLayout: hdrpPipelineLayout,
53
+ pbrSkinPipelineLayout: null,
54
+ hdrpSkinPipelineLayout: null,
55
+ },
56
+ '',
57
+ 'pbr',
58
+ ),
59
+ ).toBe(pbrPipelineLayout);
60
+ });
61
+
62
+ it('rejects membership bindings from a retired device or layout', () => {
63
+ const deviceA = {} as never;
64
+ const deviceB = {} as never;
65
+ const layoutA = {} as never;
66
+ const layoutB = {} as never;
67
+ const bindGroup = {} as never;
68
+ const state = { device: deviceA, layout: layoutA, bindGroup };
69
+ expect(projectDeviceOwnedBindGroup(state, deviceA, layoutA)).toBe(bindGroup);
70
+ expect(projectDeviceOwnedBindGroup(state, deviceB, layoutA)).toBeNull();
71
+ expect(projectDeviceOwnedBindGroup(state, deviceA, layoutB)).toBeNull();
72
+ });
73
+ });
@@ -0,0 +1,40 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ const viewUboSrc = readFileSync(fileURLToPath(new URL('../view-ubo.ts', import.meta.url)), 'utf8');
6
+ const commonWgslSrc = readFileSync(
7
+ fileURLToPath(new URL('../../../..//shader/src/common.wgsl', import.meta.url)),
8
+ 'utf8',
9
+ );
10
+
11
+ describe('View UBO directional shadow ABI', () => {
12
+ it('keeps the 960 B payload inside the existing 1024 B slot', () => {
13
+ expect(viewUboSrc).toMatch(/VIEW_UNIFORM_BYTES\s*=\s*960/);
14
+ expect(viewUboSrc).toMatch(/VIEW_UNIFORM_SLOT_STRIDE\s*=\s*1024/);
15
+ expect(viewUboSrc).toMatch(/VIEW_PAYLOAD_FLOATS\s*=\s*240/);
16
+ });
17
+
18
+ it('packs all four cascade metrics into the existing vec4 lanes', () => {
19
+ expect(viewUboSrc).toMatch(/viewPayload\[108 \+ s \* 4 \+ lane\]/);
20
+ expect(viewUboSrc).not.toMatch(/viewPayload\[108 \+ s \* 4\]\s*=\s*lights\.splitPlanes/);
21
+ });
22
+
23
+ it('keeps bias at [126]/[127], directional filter at [128..131], and Spot at 132', () => {
24
+ expect(viewUboSrc).toMatch(/viewPayload\[126\]\s*=\s*lights\.depthBias/);
25
+ expect(viewUboSrc).toMatch(/viewPayload\[127\]\s*=\s*lights\.normalBias/);
26
+ expect(viewUboSrc).toMatch(/viewPayload\[128\]/);
27
+ expect(viewUboSrc).toMatch(/viewPayload\[129\]/);
28
+ expect(viewUboSrc).toMatch(/viewPayload\[130\]/);
29
+ expect(viewUboSrc).toMatch(/viewPayload\[131\]/);
30
+ expect(viewUboSrc).toMatch(/SPOT_LVP_BASE_FLOAT\s*=\s*132/);
31
+ expect(viewUboSrc).not.toMatch(/lights\.pcfKernelSize/);
32
+ });
33
+
34
+ it('declares one shared View binding with a vec4 directional filter carrier', () => {
35
+ const viewStruct = commonWgslSrc.match(/struct View \{[\s\S]*?\n\};/)?.[0] ?? '';
36
+ expect(viewStruct).toMatch(/directionalShadowFilter\s*:\s*vec4<f32>/);
37
+ expect(viewStruct).not.toMatch(/pcfKernelSize/);
38
+ expect(commonWgslSrc.match(/@group\(0\) @binding\(0\) var<uniform> view/g)).toHaveLength(1);
39
+ });
40
+ });