@forgeax/engine-render 0.1.21 → 0.1.24

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 (584) hide show
  1. package/README.md +281 -38
  2. package/dist/assembly/backend-contract.d.ts +13 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/bundler-contract.d.ts +9 -0
  5. package/dist/assembly/bundler-contract.d.ts.map +1 -0
  6. package/dist/assembly/device-feature-admission.d.ts +8 -0
  7. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  8. package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
  9. package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
  10. package/dist/assembly/factory.d.ts +7 -235
  11. package/dist/assembly/factory.d.ts.map +1 -1
  12. package/dist/assembly/host-contract.d.ts +10 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +3 -2
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
  17. package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
  18. package/dist/assembly/material-shader-policy.d.ts +168 -0
  19. package/dist/assembly/material-shader-policy.d.ts.map +1 -0
  20. package/dist/assembly/material-shader-prewarm.d.ts +21 -0
  21. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
  22. package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
  23. package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
  25. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
  26. package/dist/assembly/recovery/generation.d.ts +46 -0
  27. package/dist/assembly/recovery/generation.d.ts.map +1 -0
  28. package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
  29. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
  30. package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
  31. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
  32. package/dist/assembly/renderer-facade.d.ts +10 -0
  33. package/dist/assembly/renderer-facade.d.ts.map +1 -0
  34. package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
  35. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  36. package/dist/assembly/renderer-helpers.d.ts +19 -0
  37. package/dist/assembly/renderer-helpers.d.ts.map +1 -0
  38. package/dist/assembly/renderer-lifecycle.d.ts +34 -0
  39. package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
  40. package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
  41. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
  42. package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
  43. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
  44. package/dist/assembly/webgpu-ready.d.ts +55 -0
  45. package/dist/assembly/webgpu-ready.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-renderer.d.ts +152 -0
  47. package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
  48. package/dist/authoring.mjs +1 -1
  49. package/dist/{chunk-PCHBPYML.mjs → chunk-GE3SDD72.mjs} +37 -5
  50. package/dist/chunk-GE3SDD72.mjs.map +1 -0
  51. package/dist/chunk-KZFTK6DO.mjs +1191 -0
  52. package/dist/chunk-KZFTK6DO.mjs.map +1 -0
  53. package/dist/{chunk-FS2KNUQH.mjs → chunk-Q752SHI5.mjs} +332 -568
  54. package/dist/chunk-Q752SHI5.mjs.map +1 -0
  55. package/dist/{chunk-6OPXDQ2E.mjs → chunk-RR5L4SRS.mjs} +33 -294
  56. package/dist/chunk-RR5L4SRS.mjs.map +1 -0
  57. package/dist/chunk-TFH5I7JJ.mjs +296 -0
  58. package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
  59. package/dist/chunk-UQYS7FRM.mjs +1003 -0
  60. package/dist/chunk-UQYS7FRM.mjs.map +1 -0
  61. package/dist/chunk-YKB5DQV7.mjs +345 -0
  62. package/dist/chunk-YKB5DQV7.mjs.map +1 -0
  63. package/dist/{chunk-5YADUCA7.mjs → chunk-YRUYGA4A.mjs} +1189 -1217
  64. package/dist/chunk-YRUYGA4A.mjs.map +1 -0
  65. package/dist/chunk-Z3YYH2MB.mjs +5082 -0
  66. package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
  67. package/dist/cluster-binner.d.ts +5 -0
  68. package/dist/cluster-binner.d.ts.map +1 -1
  69. package/dist/components/index.d.ts +3 -0
  70. package/dist/components/index.d.ts.map +1 -1
  71. package/dist/components/light-helpers.d.ts +4 -0
  72. package/dist/components/light-helpers.d.ts.map +1 -1
  73. package/dist/components/light-probe.d.ts +9 -0
  74. package/dist/components/light-probe.d.ts.map +1 -0
  75. package/dist/components/rect-area-light.d.ts +12 -0
  76. package/dist/components/rect-area-light.d.ts.map +1 -0
  77. package/dist/components/scene-instance.d.ts +4 -0
  78. package/dist/components/scene-instance.d.ts.map +1 -1
  79. package/dist/components/spot-light.d.ts +3 -0
  80. package/dist/components/spot-light.d.ts.map +1 -1
  81. package/dist/construct-renderer.mjs +27276 -23232
  82. package/dist/construct-renderer.mjs.map +1 -1
  83. package/dist/device/device-scope.d.ts +2 -0
  84. package/dist/device/device-scope.d.ts.map +1 -1
  85. package/dist/device/gpu-residency.d.ts +32 -5
  86. package/dist/device/gpu-residency.d.ts.map +1 -1
  87. package/dist/device/lifecycle-transaction.d.ts +2 -0
  88. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  89. package/dist/environment/frame.d.ts +5 -0
  90. package/dist/environment/frame.d.ts.map +1 -1
  91. package/dist/environment/inspection.d.ts +7 -0
  92. package/dist/environment/inspection.d.ts.map +1 -1
  93. package/dist/environment/lifecycle.d.ts +20 -2
  94. package/dist/environment/lifecycle.d.ts.map +1 -1
  95. package/dist/errors/gpu-driven.d.ts +26 -0
  96. package/dist/errors/gpu-driven.d.ts.map +1 -0
  97. package/dist/errors/index.d.ts +1 -0
  98. package/dist/errors/index.d.ts.map +1 -1
  99. package/dist/errors/recover.d.ts +67 -3
  100. package/dist/errors/recover.d.ts.map +1 -1
  101. package/dist/errors/render.d.ts +39 -1
  102. package/dist/errors/render.d.ts.map +1 -1
  103. package/dist/extract/contracts.d.ts +899 -0
  104. package/dist/extract/contracts.d.ts.map +1 -0
  105. package/dist/extract/gpu-driven.d.ts +50 -0
  106. package/dist/extract/gpu-driven.d.ts.map +1 -0
  107. package/dist/extract/visibility.d.ts.map +1 -1
  108. package/dist/features/host.d.ts +2 -0
  109. package/dist/features/host.d.ts.map +1 -1
  110. package/dist/features/prepared-gpu-work.d.ts +3 -0
  111. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  112. package/dist/features/prepared-graphics-store.d.ts +2 -0
  113. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  114. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  115. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  116. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  117. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  118. package/dist/gpu-driven/production-raster.d.ts +126 -2
  119. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  120. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  121. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  122. package/dist/gpu-scene-schema.d.ts +14 -0
  123. package/dist/gpu-scene-schema.d.ts.map +1 -1
  124. package/dist/gpu-scene.d.ts +9 -1
  125. package/dist/gpu-scene.d.ts.map +1 -1
  126. package/dist/gpu-usage.d.ts +0 -1
  127. package/dist/gpu-usage.d.ts.map +1 -1
  128. package/dist/hdrp-buffers.d.ts +3 -3
  129. package/dist/hdrp-buffers.d.ts.map +1 -1
  130. package/dist/ibl/IblPipelineCache.d.ts +7 -6
  131. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  132. package/dist/ibl/skylight-bind-group.d.ts +7 -1
  133. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  134. package/dist/index.d.ts +13 -2
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.mjs +90 -5
  137. package/dist/index.mjs.map +1 -1
  138. package/dist/inspection-types.d.ts +163 -1
  139. package/dist/inspection-types.d.ts.map +1 -1
  140. package/dist/internal.d.ts +9 -0
  141. package/dist/internal.d.ts.map +1 -1
  142. package/dist/internal.mjs +23 -2
  143. package/dist/internal.mjs.map +1 -1
  144. package/dist/light-buffer-layout.d.ts +60 -148
  145. package/dist/light-buffer-layout.d.ts.map +1 -1
  146. package/dist/materials.d.ts +34 -10
  147. package/dist/materials.d.ts.map +1 -1
  148. package/dist/mesh-material-bindings.d.ts +56 -0
  149. package/dist/mesh-material-bindings.d.ts.map +1 -1
  150. package/dist/occlusion-proxy.d.ts +4 -0
  151. package/dist/occlusion-proxy.d.ts.map +1 -0
  152. package/dist/pbr-pipeline.d.ts +58 -21
  153. package/dist/pbr-pipeline.d.ts.map +1 -1
  154. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  155. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
  156. package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
  157. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
  158. package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
  159. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
  160. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
  161. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  162. package/dist/pipeline-builder.d.ts +2 -0
  163. package/dist/pipeline-builder.d.ts.map +1 -1
  164. package/dist/pipeline-spec.d.ts +1 -1
  165. package/dist/pipeline-spec.d.ts.map +1 -1
  166. package/dist/plugin.d.ts.map +1 -1
  167. package/dist/points-lines/prepare.d.ts +3 -0
  168. package/dist/points-lines/prepare.d.ts.map +1 -1
  169. package/dist/points-lines/standard-owner.d.ts +33 -0
  170. package/dist/points-lines/standard-owner.d.ts.map +1 -0
  171. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  172. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  173. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  174. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  175. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  176. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  177. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  178. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  179. package/dist/record/frame-lighting.d.ts +8 -6
  180. package/dist/record/frame-lighting.d.ts.map +1 -1
  181. package/dist/record/frame-snapshot.d.ts +55 -10
  182. package/dist/record/frame-snapshot.d.ts.map +1 -1
  183. package/dist/record/frame-targets.d.ts.map +1 -1
  184. package/dist/record/frame.d.ts +21 -5
  185. package/dist/record/frame.d.ts.map +1 -1
  186. package/dist/record/gpu-timing.d.ts +19 -7
  187. package/dist/record/gpu-timing.d.ts.map +1 -1
  188. package/dist/record/helpers.d.ts +0 -20
  189. package/dist/record/helpers.d.ts.map +1 -1
  190. package/dist/record/main-pass-geometry.d.ts +20 -2
  191. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  192. package/dist/record/main-pass-material.d.ts +10 -18
  193. package/dist/record/main-pass-material.d.ts.map +1 -1
  194. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  195. package/dist/record/main-pass.d.ts.map +1 -1
  196. package/dist/record/mesh-ssbo.d.ts +11 -3
  197. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  198. package/dist/record/recovery-pipeline.d.ts +30 -0
  199. package/dist/record/recovery-pipeline.d.ts.map +1 -0
  200. package/dist/record/render-context.d.ts +82 -9
  201. package/dist/record/render-context.d.ts.map +1 -1
  202. package/dist/record/shadow-pass.d.ts.map +1 -1
  203. package/dist/record/typed-frame-graph.d.ts +49 -2
  204. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  205. package/dist/record/view-ubo.d.ts +1 -2
  206. package/dist/record/view-ubo.d.ts.map +1 -1
  207. package/dist/recovery/render-system-candidate.d.ts +65 -0
  208. package/dist/recovery/render-system-candidate.d.ts.map +1 -0
  209. package/dist/reflection/inspection.d.ts +10 -0
  210. package/dist/reflection/inspection.d.ts.map +1 -0
  211. package/dist/reflection/projection.d.ts +49 -0
  212. package/dist/reflection/projection.d.ts.map +1 -1
  213. package/dist/reflection/record-owner.d.ts +60 -0
  214. package/dist/reflection/record-owner.d.ts.map +1 -0
  215. package/dist/render-contract.d.ts +78 -15
  216. package/dist/render-contract.d.ts.map +1 -1
  217. package/dist/render-pipeline.d.ts +7 -0
  218. package/dist/render-pipeline.d.ts.map +1 -1
  219. package/dist/render-system-extract-tail.d.ts +12 -0
  220. package/dist/render-system-extract-tail.d.ts.map +1 -0
  221. package/dist/render-system-extract.d.ts +252 -30
  222. package/dist/render-system-extract.d.ts.map +1 -1
  223. package/dist/render-system.d.ts +140 -5
  224. package/dist/render-system.d.ts.map +1 -1
  225. package/dist/scene/probe-blend-record.d.ts +22 -0
  226. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  227. package/dist/scene/probe-blend.d.ts +142 -0
  228. package/dist/scene/probe-blend.d.ts.map +1 -0
  229. package/dist/scene/render-scene-types.d.ts +0 -6
  230. package/dist/scene/render-scene-types.d.ts.map +1 -1
  231. package/dist/scene/render-scene.d.ts +122 -9
  232. package/dist/scene/render-scene.d.ts.map +1 -1
  233. package/dist/scene/visibility/bounds.d.ts +20 -0
  234. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  235. package/dist/scene/visibility/budget.d.ts +16 -0
  236. package/dist/scene/visibility/budget.d.ts.map +1 -0
  237. package/dist/scene/visibility/facet.d.ts +73 -0
  238. package/dist/scene/visibility/facet.d.ts.map +1 -0
  239. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  240. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  241. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  242. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  243. package/dist/scene/visibility/inspection.d.ts +132 -0
  244. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  245. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  246. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  247. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  248. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  249. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  250. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  251. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  252. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  253. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  254. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  255. package/dist/scene/visibility/types.d.ts +34 -0
  256. package/dist/scene/visibility/types.d.ts.map +1 -0
  257. package/dist/ssr/admission.d.ts +122 -0
  258. package/dist/ssr/admission.d.ts.map +1 -0
  259. package/dist/ssr/composition.d.ts +32 -0
  260. package/dist/ssr/composition.d.ts.map +1 -0
  261. package/dist/ssr/errors.d.ts +39 -0
  262. package/dist/ssr/errors.d.ts.map +1 -0
  263. package/dist/ssr/identity.d.ts +13 -0
  264. package/dist/ssr/identity.d.ts.map +1 -0
  265. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  266. package/dist/temporal/frame-coordinator.d.ts +13 -0
  267. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  268. package/dist/temporal/frame.d.ts +2 -0
  269. package/dist/temporal/frame.d.ts.map +1 -1
  270. package/dist/temporal/index.mjs +6 -5
  271. package/dist/temporal/taa-history-store.d.ts +15 -1
  272. package/dist/temporal/taa-history-store.d.ts.map +1 -1
  273. package/dist/temporal/transaction.d.ts +5 -0
  274. package/dist/temporal/transaction.d.ts.map +1 -1
  275. package/dist/temporal/view.d.ts +7 -0
  276. package/dist/temporal/view.d.ts.map +1 -1
  277. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  278. package/dist/typed-render-graph-primitives.d.ts +4 -0
  279. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  280. package/dist/volume/passes.d.ts +8 -4
  281. package/dist/volume/passes.d.ts.map +1 -1
  282. package/package.json +20 -20
  283. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
  284. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  285. package/src/__tests__/device-feature-admission.unit.test.ts +19 -1
  286. package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
  287. package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
  288. package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
  289. package/src/__tests__/environment-generation.integration.test.ts +39 -0
  290. package/src/__tests__/evidence-identity.ts +13 -0
  291. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  292. package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
  293. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  294. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  295. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  296. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  297. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  298. package/src/__tests__/factory-contract.integration.test.ts +154 -6
  299. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
  300. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  301. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  302. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
  303. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
  304. package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
  305. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  306. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  307. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
  308. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  309. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  310. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  311. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  312. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  313. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  314. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  315. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  316. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  317. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  318. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  319. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  320. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  321. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  322. package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
  323. package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
  324. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  325. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  326. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  327. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  328. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  329. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  330. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  331. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  332. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  333. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  334. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  335. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  336. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  337. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  338. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  339. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  340. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  341. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  342. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  343. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  344. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  345. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  346. package/src/__tests__/material-contract-inventory.unit.test.ts +41 -9
  347. package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
  348. package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
  349. package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
  350. package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
  351. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  352. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  353. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  354. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  355. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  356. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  357. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  358. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  359. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  360. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  361. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  362. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  363. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  364. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  365. package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
  366. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  367. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
  368. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  369. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  370. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  371. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  372. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  373. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  374. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  375. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  376. package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
  377. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
  378. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  379. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  380. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  381. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  382. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  383. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  384. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  385. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  386. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  387. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  388. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  389. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  390. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  391. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +160 -17
  392. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
  393. package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
  394. package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
  395. package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
  396. package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
  397. package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
  398. package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
  399. package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
  400. package/src/__tests__/shader-manifest-fixture.ts +13 -16
  401. package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
  402. package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
  403. package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
  404. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  405. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  406. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  407. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  408. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  409. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
  410. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
  411. package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
  412. package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
  413. package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
  414. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  415. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  416. package/src/__tests__/transmission-prewarm.unit.test.ts +111 -32
  417. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  418. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  419. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  420. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  421. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  422. package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
  423. package/src/assembly/backend-contract.ts +13 -0
  424. package/src/assembly/bundler-contract.ts +9 -0
  425. package/src/assembly/device-feature-admission.ts +26 -9
  426. package/src/assembly/extended-lighting-fallback.ts +216 -0
  427. package/src/assembly/factory.ts +81 -9634
  428. package/src/assembly/host-contract.ts +10 -0
  429. package/src/assembly/material/assembly.ts +18 -2
  430. package/src/assembly/material/standard-layer-projection.ts +16 -0
  431. package/src/assembly/material-shader-policy.ts +854 -0
  432. package/src/assembly/material-shader-prewarm.ts +88 -0
  433. package/src/assembly/mesh-ssbo-grow.ts +270 -0
  434. package/src/assembly/recovery/device-loss-fanout.ts +89 -0
  435. package/src/assembly/recovery/generation.ts +141 -0
  436. package/src/assembly/recovery/recovery-attempt.ts +800 -0
  437. package/src/assembly/recovery/renderer-recover.ts +906 -0
  438. package/src/assembly/renderer-facade.ts +342 -0
  439. package/src/assembly/renderer-frame-transaction.ts +45 -0
  440. package/src/assembly/renderer-helpers.ts +99 -0
  441. package/src/assembly/renderer-lifecycle.ts +159 -0
  442. package/src/assembly/shader-prewarm-policy.ts +157 -0
  443. package/src/assembly/webgpu-ready-contract.ts +14 -0
  444. package/src/assembly/webgpu-ready.ts +4079 -0
  445. package/src/assembly/webgpu-renderer.ts +4095 -0
  446. package/src/cluster-binner.ts +31 -0
  447. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  448. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  449. package/src/components/camera.ts +1 -1
  450. package/src/components/index.ts +3 -0
  451. package/src/components/light-helpers.ts +52 -1
  452. package/src/components/light-probe.ts +13 -0
  453. package/src/components/rect-area-light.ts +15 -0
  454. package/src/components/scene-instance.ts +6 -0
  455. package/src/components/spot-light.ts +3 -0
  456. package/src/debug-draw-glue.ts +1 -1
  457. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  458. package/src/device/device-scope.ts +35 -6
  459. package/src/device/gpu-residency.ts +334 -35
  460. package/src/device/lifecycle-transaction.ts +12 -0
  461. package/src/environment/frame.ts +6 -0
  462. package/src/environment/inspection.ts +10 -0
  463. package/src/environment/lifecycle.ts +122 -9
  464. package/src/errors/gpu-driven.ts +92 -0
  465. package/src/errors/index.ts +1 -0
  466. package/src/errors/recover.ts +108 -5
  467. package/src/errors/render.ts +72 -1
  468. package/src/extract/camera.ts +3 -3
  469. package/src/extract/contracts.ts +974 -0
  470. package/src/extract/gpu-driven.ts +108 -0
  471. package/src/extract/visibility.ts +0 -23
  472. package/src/features/host.ts +16 -0
  473. package/src/features/prepared-gpu-work.ts +20 -2
  474. package/src/features/prepared-graphics-store.ts +17 -0
  475. package/src/gpu-driven/batch-topology.ts +206 -28
  476. package/src/gpu-driven/prepared-draw.ts +208 -0
  477. package/src/gpu-driven/production-raster.ts +1046 -39
  478. package/src/gpu-driven/view-gpu.ts +411 -29
  479. package/src/gpu-scene-schema.ts +13 -0
  480. package/src/gpu-scene.ts +137 -67
  481. package/src/gpu-usage.ts +0 -1
  482. package/src/hdrp-buffers.ts +6 -6
  483. package/src/ibl/IblPipelineCache.ts +134 -50
  484. package/src/ibl/skylight-bind-group.ts +26 -0
  485. package/src/index.ts +83 -1
  486. package/src/inspection-types.ts +220 -1
  487. package/src/internal.ts +38 -0
  488. package/src/light-buffer-layout.ts +157 -324
  489. package/src/materials.ts +278 -47
  490. package/src/mesh-material-bindings.ts +59 -0
  491. package/src/occlusion-proxy.ts +64 -0
  492. package/src/pbr-pipeline.ts +290 -60
  493. package/src/pipeline/standard-forward-lane.ts +47 -0
  494. package/src/pipeline/standard-lighting/graph.ts +2 -1
  495. package/src/pipeline/standard-lighting/light-frame.ts +3 -2
  496. package/src/pipeline/standard-lighting/topology.ts +1 -1
  497. package/src/pipeline/standard-lighting/transport.ts +2 -1
  498. package/src/pipeline/standard-pipeline.ts +2 -0
  499. package/src/pipeline-builder.ts +5 -2
  500. package/src/pipeline-spec.ts +12 -1
  501. package/src/plugin.ts +4 -0
  502. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
  503. package/src/points-lines/prepare.ts +9 -0
  504. package/src/points-lines/standard-owner.ts +403 -0
  505. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  506. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  507. package/src/prepare/extended-lighting/resources.ts +389 -0
  508. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  509. package/src/prepare/extended-lighting/state.ts +92 -0
  510. package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
  511. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  512. package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
  513. package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
  514. package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
  515. package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
  516. package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
  517. package/src/record/__tests__/temporal-payload.unit.test.ts +29 -28
  518. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +21 -2
  519. package/src/record/frame-lighting.ts +252 -53
  520. package/src/record/frame-snapshot.ts +72 -12
  521. package/src/record/frame-targets.ts +11 -1
  522. package/src/record/frame.ts +416 -95
  523. package/src/record/gpu-timing.ts +108 -44
  524. package/src/record/helpers.ts +1 -59
  525. package/src/record/main-pass-geometry.ts +434 -44
  526. package/src/record/main-pass-material.ts +324 -210
  527. package/src/record/main-pass-sprite-draws.ts +58 -92
  528. package/src/record/main-pass.ts +94 -6
  529. package/src/record/mesh-ssbo.ts +79 -46
  530. package/src/record/recovery-pipeline.ts +695 -0
  531. package/src/record/render-context.ts +99 -7
  532. package/src/record/shadow-pass.ts +66 -40
  533. package/src/record/typed-frame-graph.ts +270 -84
  534. package/src/record/view-ubo.ts +17 -27
  535. package/src/recovery/render-system-candidate.ts +839 -0
  536. package/src/reflection/inspection.ts +67 -0
  537. package/src/reflection/projection.ts +196 -1
  538. package/src/reflection/record-owner.ts +1283 -0
  539. package/src/render-contract.ts +82 -12
  540. package/src/render-pipeline.ts +5 -0
  541. package/src/render-system-extract-tail.ts +2983 -0
  542. package/src/render-system-extract.ts +290 -2784
  543. package/src/render-system.ts +1597 -1192
  544. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  545. package/src/scene/probe-blend-record.ts +54 -0
  546. package/src/scene/probe-blend.ts +813 -0
  547. package/src/scene/render-scene-types.ts +0 -7
  548. package/src/scene/render-scene.ts +972 -184
  549. package/src/scene/visibility/bounds.ts +57 -0
  550. package/src/scene/visibility/budget.ts +40 -0
  551. package/src/scene/visibility/facet.ts +400 -0
  552. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  553. package/src/scene/visibility/gpu-lod.ts +119 -0
  554. package/src/scene/visibility/inspection.ts +313 -0
  555. package/src/scene/visibility/lod-selector.ts +84 -0
  556. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  557. package/src/scene/visibility/occlusion-pass.ts +165 -0
  558. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  559. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  560. package/src/scene/visibility/types.ts +50 -0
  561. package/src/ssr/admission.ts +451 -0
  562. package/src/ssr/composition.ts +73 -0
  563. package/src/ssr/errors.ts +76 -0
  564. package/src/ssr/identity.ts +12 -0
  565. package/src/systems/skin-palette-allocator.ts +1 -1
  566. package/src/temporal/frame-coordinator.ts +30 -1
  567. package/src/temporal/frame.ts +14 -1
  568. package/src/temporal/taa-history-store.ts +46 -2
  569. package/src/temporal/temporal-view.ts +1 -1
  570. package/src/temporal/transaction.ts +9 -0
  571. package/src/temporal/view.ts +11 -0
  572. package/src/tilemap-chunk-extract-system.ts +5 -5
  573. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
  574. package/src/typed-render-graph-primitives.ts +48 -0
  575. package/src/volume/passes.ts +46 -49
  576. package/dist/.tsbuildinfo +0 -1
  577. package/dist/chunk-5YADUCA7.mjs.map +0 -1
  578. package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
  579. package/dist/chunk-BXBQQKFQ.mjs +0 -67
  580. package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
  581. package/dist/chunk-FS2KNUQH.mjs.map +0 -1
  582. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  583. package/dist/chunk-VFPLTKCU.mjs +0 -192
  584. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -2,12 +2,13 @@ import type { Mat4, Vec3 } from '@forgeax/engine-math';
2
2
  import type {
3
3
  DirectionalLightSnapshot,
4
4
  PointLightSnapshot,
5
+ RectAreaDirectLightSnapshot,
5
6
  SpotLightSnapshot,
6
7
  } from '../../render-system-extract';
7
8
  import type { StandardLightCount } from '../standard-profile';
8
9
 
9
10
  export interface StandardLocalLightInput {
10
- readonly kind: 'point' | 'spot';
11
+ readonly kind: 'point' | 'spot' | 'rect-area';
11
12
  readonly position: Vec3;
12
13
  readonly range: number;
13
14
  /** Whether the shadow producer admitted this local light to its atlas. */
@@ -17,7 +18,7 @@ export interface StandardLocalLightInput {
17
18
  * it on the POD frame prevents Forward/Deferred from rebuilding a second
18
19
  * light list while leaving hand-authored unit fixtures source-free.
19
20
  */
20
- readonly source?: PointLightSnapshot | SpotLightSnapshot;
21
+ readonly source?: PointLightSnapshot | SpotLightSnapshot | RectAreaDirectLightSnapshot;
21
22
  }
22
23
 
23
24
  export interface StandardLightFrame {
@@ -2,7 +2,7 @@ import { err, ok, type Result } from '@forgeax/engine-types';
2
2
  import type { PreparedStandardLighting } from './prepare';
3
3
  import type { StandardClusterTransport } from './transport';
4
4
 
5
- /** A prepared frame with no local lights on a non-storage direct backend. */
5
+ /** A prepared frame with no local lights on a non-storage backend. */
6
6
  export interface StandardNoLocalTopologyInput {
7
7
  readonly kind: 'no-local-lights';
8
8
  readonly prepared: PreparedStandardLighting;
@@ -1,5 +1,6 @@
1
1
  import { err, ok, type Result } from '@forgeax/engine-types';
2
2
  import { type RenderError, StandardClusterTransportUnavailableError } from '../../errors/render';
3
+ import { BYTES_PER_DIRECT_LIGHT_SLOT } from '../../light-buffer-layout';
3
4
  import type { PreparedStandardLighting } from './prepare';
4
5
 
5
6
  export interface StandardClusterCapabilities {
@@ -71,7 +72,7 @@ export function selectStandardClusterTransport(
71
72
  occupiedClusterCount: occupiedClusterCount(prepared),
72
73
  clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
73
74
  lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
74
- lightDataBytes: requested * 64,
75
+ lightDataBytes: requested * BYTES_PER_DIRECT_LIGHT_SLOT,
75
76
  lightBoundsBytes: prepared.lightBounds.byteLength,
76
77
  });
77
78
  }
@@ -312,6 +312,7 @@ function buildStandardDeferredLane(
312
312
  ...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
313
313
  passKind: 'forward',
314
314
  ...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
315
+ ...(context.occlusion === undefined ? {} : { occlusion: context.occlusion }),
315
316
  extraAccesses: forwardExtraAccesses,
316
317
  });
317
318
  if (!forward.ok) return forward;
@@ -403,6 +404,7 @@ function buildStandardDeferredLane(
403
404
  depthSample.value,
404
405
  shadows.value.directional?.view,
405
406
  shadows.value.spot.view,
407
+ buffers.value,
406
408
  );
407
409
  if (!volume.ok) return volume;
408
410
  }
@@ -122,6 +122,8 @@ export interface PipelineBuilderContext {
122
122
  * tonemap field (M9 keeps the LDR shape; HDR variants are OOS-M9).
123
123
  */
124
124
  readonly colorFormat: GPUTextureFormat;
125
+ /** Additional color targets for an MRT pass; the first target is colorFormat. */
126
+ readonly colorFormats?: readonly GPUTextureFormat[] | undefined;
125
127
  /** Depth attachment format, or `undefined` for a color-only pass. */
126
128
  readonly depthFormat: GPUTextureFormat | undefined;
127
129
  /**
@@ -324,7 +326,8 @@ export function buildPipelineForMaterialShader(
324
326
  // layout. The skinned variant additionally reads JOINTS_0 / WEIGHTS_0;
325
327
  // both layouts come from the same geometry projection used by the main
326
328
  // pass, so shadow rendering cannot silently reinterpret an 18F stream.
327
- if (colorFormatsForPassKind(passKind, ctx.colorFormat).length === 0) {
329
+ const attachmentFormats = ctx.colorFormats ?? colorFormatsForPassKind(passKind, ctx.colorFormat);
330
+ if (attachmentFormats.length === 0) {
328
331
  // bug-20260619-csm RC-3 (AC-10): a material may supply a custom
329
332
  // ShadowCaster pass shader that carries a fragment stage (e.g. an
330
333
  // alpha-test cutout that calls `discard` and returns
@@ -399,7 +402,7 @@ export function buildPipelineForMaterialShader(
399
402
  const forwardSpec: PipelineSpec = {
400
403
  shader: { id, passKind, variantSet: undefined },
401
404
  attachments: {
402
- colorFormats: colorFormatsForPassKind(passKind, ctx.colorFormat),
405
+ colorFormats: attachmentFormats,
403
406
  depthFormat: ctx.depthFormat,
404
407
  sampleCount: (sampleCount === 4 ? 4 : 1) as 1 | 4,
405
408
  },
@@ -319,12 +319,23 @@ export function standardTopologyVariantSet(
319
319
  topology: { readonly kind: 'no-local-lights' | 'clustered' } | undefined,
320
320
  storageBuffer: boolean,
321
321
  vertexColorAvailable: boolean,
322
+ probeBlendAvailable = false,
322
323
  ): string {
323
- return standardCapabilityVariantSet(
324
+ const capabilityVariantSet = standardCapabilityVariantSet(
324
325
  topology?.kind === 'clustered',
325
326
  storageBuffer,
326
327
  vertexColorAvailable,
327
328
  );
329
+ if (!probeBlendAvailable || !storageBuffer) return capabilityVariantSet;
330
+ // The canonical empty key cannot carry the clustered=true fact through
331
+ // resolveMaterialShaderVariantSet (an omitted cluster axis means false).
332
+ // Expand that base before adding the object-level Probe ABI axis so shader,
333
+ // group(3) bind group, and pipeline layout remain one exact variant.
334
+ const explicitCapabilityVariantSet =
335
+ capabilityVariantSet === ''
336
+ ? 'CLUSTER_FORWARD_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true'
337
+ : capabilityVariantSet;
338
+ return `${explicitCapabilityVariantSet}+PROBE_BLEND_AVAILABLE=true`;
328
339
  }
329
340
 
330
341
  /**
package/src/plugin.ts CHANGED
@@ -5,6 +5,7 @@ import { Camera } from './components/camera';
5
5
  import { DirectionalLight } from './components/directional-light';
6
6
  import { Instances } from './components/instances';
7
7
  import { Layer } from './components/layer';
8
+ import { LightProbe } from './components/light-probe';
8
9
  import { Lines } from './components/lines';
9
10
  import { MeshFilter } from './components/mesh-filter';
10
11
  import { MeshRenderer } from './components/mesh-renderer';
@@ -12,6 +13,7 @@ import { PointLight } from './components/point-light';
12
13
  import { PointLightShadow } from './components/point-light-shadow';
13
14
  import { Points } from './components/points';
14
15
  import { PostProcessParams } from './components/post-process-params';
16
+ import { RectAreaLight } from './components/rect-area-light';
15
17
  import { SceneInstance } from './components/scene-instance';
16
18
  import { SkyboxBackground } from './components/skybox-background';
17
19
  import { Skylight } from './components/skylight';
@@ -30,6 +32,7 @@ const RENDER_COMPONENTS: readonly Component[] = [
30
32
  DirectionalLight,
31
33
  Instances,
32
34
  Layer,
35
+ LightProbe,
33
36
  MeshFilter,
34
37
  MeshRenderer,
35
38
  PointLight,
@@ -37,6 +40,7 @@ const RENDER_COMPONENTS: readonly Component[] = [
37
40
  Points,
38
41
  Lines,
39
42
  PostProcessParams,
43
+ RectAreaLight,
40
44
  SceneInstance,
41
45
  SkyboxBackground,
42
46
  Skylight,
@@ -154,4 +154,26 @@ describe('Points/Lines expansion cache and LKG recovery', () => {
154
154
  expect(preparation.prepare(snapshot(), mesh()).ok).toBe(true);
155
155
  expect(preparation.inspect()).toMatchObject({ status: 'resident', lastKnownGood: true });
156
156
  });
157
+
158
+ it('abandons lost-device handles without invoking the dead-device destroy path', () => {
159
+ let destroys = 0;
160
+ const preparation = new PointsLinesPreparation({
161
+ cache: new PointsLinesExpansionCache(),
162
+ adapter: {
163
+ create: () => ok('lost-device-resource'),
164
+ upload: () => ok(64),
165
+ validate: () => ok(undefined),
166
+ destroy: () => {
167
+ destroys += 1;
168
+ },
169
+ },
170
+ });
171
+
172
+ expect(preparation.prepare(snapshot(), mesh()).ok).toBe(true);
173
+ preparation.abandonForDeviceLoss();
174
+ preparation.abandonForDeviceLoss();
175
+
176
+ expect(destroys).toBe(0);
177
+ expect(preparation.inspect()).toMatchObject({ status: 'rebuild-pending', liveBytes: 0 });
178
+ });
157
179
  });
@@ -37,6 +37,8 @@ export interface PointsLinesLanePreparationAdapter<Resource> {
37
37
  mesh: MeshAsset,
38
38
  ): Result<PointsLinesPreparedResource<Resource>, PointsLinesPrepareFailedError>;
39
39
  resetForDeviceLoss(): void;
40
+ /** Drop lost-device handles without calling destroy on the dead device. */
41
+ abandonForDeviceLoss(): void;
40
42
  lastKnownGood(): PointsLinesPreparedResource<Resource> | undefined;
41
43
  inspect(): PointsLinesPreparationInspection<Resource>;
42
44
  }
@@ -121,6 +123,12 @@ export class PointsLinesPreparation<Resource> {
121
123
  this.status = 'rebuild-pending';
122
124
  }
123
125
 
126
+ abandonForDeviceLoss(): void {
127
+ this.live = undefined;
128
+ this.pendingCandidateBytes = 0;
129
+ this.status = 'rebuild-pending';
130
+ }
131
+
124
132
  lastKnownGood(): PointsLinesPreparedResource<Resource> | undefined {
125
133
  return this.live;
126
134
  }
@@ -171,6 +179,7 @@ export function createPointsLinesLanePreparationAdapter<Resource>(
171
179
  contract: createPointsLinesLaneContract(lane, backend),
172
180
  prepare: (snapshot, mesh) => preparation.prepare(snapshot, mesh),
173
181
  resetForDeviceLoss: () => preparation.resetForDeviceLoss(),
182
+ abandonForDeviceLoss: () => preparation.abandonForDeviceLoss(),
174
183
  lastKnownGood: () => preparation.lastKnownGood(),
175
184
  inspect: () => preparation.inspect(),
176
185
  };
@@ -0,0 +1,403 @@
1
+ import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
2
+ import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
3
+ import { err, ok } from '@forgeax/engine-rhi';
4
+ import type { MaterialAsset, MeshAsset } from '@forgeax/engine-types';
5
+ import { toShared } from '@forgeax/engine-types';
6
+ import { PointsLinesMaterialUnsupportedError } from '../errors/render';
7
+ import {
8
+ GPU_BUFFER_USAGE_COPY_DST,
9
+ GPU_BUFFER_USAGE_INDEX,
10
+ GPU_BUFFER_USAGE_VERTEX,
11
+ } from '../gpu-usage';
12
+ import type { ValidatedRenderable } from '../record/frame-snapshot';
13
+ import type {
14
+ PointsLinesRecordOwner,
15
+ PointsLinesRecordSubmission,
16
+ RenderSystemInternals,
17
+ } from '../record/render-context';
18
+ import type { RecoveryPointsLinesCandidate } from '../render-system';
19
+ import { admitPointsLines } from './admission';
20
+ import { PointsLinesExpansionCache } from './expansion-cache';
21
+ import type { PointsLinesInspection, PointsLinesSourceError } from './inspection';
22
+ import { inspectPointsLines } from './inspection';
23
+ import {
24
+ createPointsLinesLanePreparationAdapter,
25
+ type PointsLinesLanePreparationAdapter,
26
+ } from './prepare';
27
+ import {
28
+ createPointsLinesLaneAdapter,
29
+ type PointsLinesBackend,
30
+ type PointsLinesLane,
31
+ } from './record';
32
+ import type { PointsLinesRetainedSnapshot } from './snapshot';
33
+
34
+ type PointsLinesGpuResources = {
35
+ readonly vertexBuffer: import('@forgeax/engine-rhi').Buffer;
36
+ readonly indexBuffer: import('@forgeax/engine-rhi').Buffer;
37
+ };
38
+ type PointsLinesPreparationAdapter = PointsLinesLanePreparationAdapter<PointsLinesGpuResources>;
39
+
40
+ /**
41
+ * The Standard renderer's single Points/Lines prepare owner.
42
+ *
43
+ * The retained snapshot is the identity boundary; this owner only resolves
44
+ * the source assets, runs admission, and publishes the existing preparation
45
+ * and record contracts to the main geometry loop. The expansion cache is
46
+ * shared across lanes and this owner keeps the one prepared vertex/index
47
+ * resource pair for each retained identity.
48
+ */
49
+ export class StandardPointsLinesOwner implements PointsLinesRecordOwner {
50
+ private readonly cache = new PointsLinesExpansionCache();
51
+ private readonly preparations = new Map<string, PointsLinesPreparationAdapter>();
52
+ private readonly active = new Map<string, PointsLinesInspection>();
53
+ private readonly layoutProjection = deriveVertexLayoutProjection({
54
+ position: new Float32Array(0),
55
+ normal: new Float32Array(0),
56
+ uv: new Float32Array(0),
57
+ tangent: new Float32Array(0),
58
+ });
59
+
60
+ constructor(private readonly internals: RenderSystemInternals) {}
61
+
62
+ beginFrame(): void {
63
+ this.active.clear();
64
+ }
65
+
66
+ prepare(entry: ValidatedRenderable, clustered: boolean): PointsLinesRecordSubmission | undefined {
67
+ return this.prepareWithMaps(entry, clustered, this.internals, this.preparations, this.active);
68
+ }
69
+
70
+ prepareRecoveryCandidate(
71
+ entries: readonly ValidatedRenderable[],
72
+ clustered: boolean,
73
+ runtime: RenderSystemInternals,
74
+ ): RecoveryPointsLinesCandidate | undefined {
75
+ const stagedPreparations = new Map<string, PointsLinesPreparationAdapter>();
76
+ const stagedInspections = new Map<string, PointsLinesInspection>();
77
+ let pointEntryCount = 0;
78
+ try {
79
+ for (const entry of entries) {
80
+ const snapshot = entry.source.pointsLines;
81
+ if (snapshot?.component === undefined) continue;
82
+ pointEntryCount += 1;
83
+ const prepared = this.prepareWithMaps(
84
+ entry,
85
+ clustered,
86
+ runtime,
87
+ stagedPreparations,
88
+ stagedInspections,
89
+ );
90
+ if (prepared === undefined) {
91
+ throw new Error(
92
+ `recovery Points/Lines preparation failed for ${snapshot.worldId}:${snapshot.entityKey}`,
93
+ );
94
+ }
95
+ }
96
+ } catch (cause) {
97
+ for (const preparation of stagedPreparations.values()) {
98
+ preparation.resetForDeviceLoss();
99
+ }
100
+ throw cause;
101
+ }
102
+ if (pointEntryCount === 0) return undefined;
103
+
104
+ let released = false;
105
+ let published = false;
106
+ const candidate: RecoveryPointsLinesCandidate = {
107
+ createRecoveryRoot: (scope) => ({
108
+ kind: 'buffer',
109
+ create: () => {
110
+ if (!scope.isAlive() || released) {
111
+ throw new Error('Points/Lines recovery candidate scope is not active.');
112
+ }
113
+ return candidate;
114
+ },
115
+ cleanup: () => candidate.release(),
116
+ }),
117
+ publish: () => {
118
+ if (released || published) return;
119
+ this.preparations.clear();
120
+ for (const [key, preparation] of stagedPreparations) {
121
+ this.preparations.set(key, preparation);
122
+ }
123
+ published = true;
124
+ },
125
+ release: () => {
126
+ if (released || published) return;
127
+ released = true;
128
+ for (const preparation of stagedPreparations.values()) {
129
+ preparation.resetForDeviceLoss();
130
+ }
131
+ stagedPreparations.clear();
132
+ stagedInspections.clear();
133
+ },
134
+ };
135
+ return candidate;
136
+ }
137
+
138
+ private prepareWithMaps(
139
+ entry: ValidatedRenderable,
140
+ clustered: boolean,
141
+ runtime: RenderSystemInternals,
142
+ preparations: Map<string, PointsLinesPreparationAdapter>,
143
+ inspections: Map<string, PointsLinesInspection>,
144
+ ): PointsLinesRecordSubmission | undefined {
145
+ const snapshot = entry.source.pointsLines;
146
+ if (snapshot === undefined || snapshot.component === undefined || entry.world === undefined) {
147
+ return undefined;
148
+ }
149
+ const key = `${snapshot.worldId}:${snapshot.entityKey}`;
150
+ const topology = snapshot.component === 'Points' ? 'point-list' : 'line-list';
151
+ const backend = this.backend(runtime);
152
+ const lane = backend === 'wgpu-webgl2' ? 'cpu-webgl2' : clustered ? 'clustered' : 'direct';
153
+ const meshResult = resolveAssetHandle<MeshAsset>(
154
+ entry.world,
155
+ toShared<'MeshAsset'>(entry.source.assetHandle),
156
+ );
157
+ const materialResult = resolveAssetHandle<MaterialAsset>(
158
+ entry.world,
159
+ toShared<'MaterialAsset'>(snapshot.materialHandle),
160
+ );
161
+ if (!meshResult.ok || !materialResult.ok) {
162
+ this.publishRefusal(
163
+ inspections,
164
+ snapshot,
165
+ new PointsLinesMaterialUnsupportedError({
166
+ entity: snapshot.entityKey,
167
+ material: 'unresolved',
168
+ pass: 'forward',
169
+ module: 'asset-resolution',
170
+ reason: 'source MeshAsset or MaterialAsset could not be resolved',
171
+ }),
172
+ );
173
+ return undefined;
174
+ }
175
+ const admission = admitPointsLines({
176
+ entity: snapshot.entityKey,
177
+ mesh: meshResult.value,
178
+ material: materialResult.value,
179
+ ...(snapshot.style?.kind === 'points'
180
+ ? {
181
+ points: {
182
+ sizePx: snapshot.style.sizePx,
183
+ shape: snapshot.style.shape === 'circle' ? 1 : 0,
184
+ },
185
+ }
186
+ : { lines: { widthPx: snapshot.style?.widthPx ?? 1 } }),
187
+ });
188
+ if (!admission.ok) {
189
+ this.publishRefusal(inspections, snapshot, admission.error);
190
+ return undefined;
191
+ }
192
+ const geometryKey = this.cache.getOrCreate(snapshot, meshResult.value).key;
193
+ const prepKey = `${geometryKey}:${lane}:${backend}`;
194
+ let preparation = preparations.get(prepKey);
195
+ if (preparation === undefined) {
196
+ // A new expansion is visible cold upload work. Candidate preparation
197
+ // uses an unarmed runtime and stages the result; the published runtime
198
+ // is armed, so a missing staged resource fails before any RHI create.
199
+ runtime.recoveryColdWorkGuard?.noteUploadColdWork();
200
+ preparation = this.createPreparation(runtime, geometryKey, lane, backend);
201
+ preparations.set(prepKey, preparation);
202
+ } else if (preparation.lastKnownGood()?.geometry.key !== geometryKey) {
203
+ runtime.recoveryColdWorkGuard?.noteUploadColdWork();
204
+ }
205
+ const prepared = preparation.prepare(snapshot, meshResult.value);
206
+ if (!prepared.ok) {
207
+ const lkg = preparation.lastKnownGood();
208
+ if (lkg !== undefined) {
209
+ const lkgPlan = createPointsLinesLaneAdapter(lane, backend).createRecordPlan(
210
+ lkg.snapshot,
211
+ lkg.geometry,
212
+ );
213
+ const state = preparation.inspect();
214
+ inspections.set(
215
+ key,
216
+ inspectPointsLines({
217
+ snapshot,
218
+ topology,
219
+ lane,
220
+ pointCount: lkg.geometry.pointCount,
221
+ segmentCount: lkg.geometry.segmentCount,
222
+ sourceBytes: lkg.geometry.sourceBytes,
223
+ derivedBytes: lkg.geometry.derivedBytes,
224
+ cache: { hit: true, rebuilds: state.rebuilds, evictions: 0 },
225
+ drawCount: lkgPlan.drawCount,
226
+ uploadBytes: 0,
227
+ lastKnownGood: true,
228
+ refusal: {
229
+ code: prepared.error.code,
230
+ expected: prepared.error.expected,
231
+ hint: prepared.error.hint,
232
+ detail: prepared.error.detail,
233
+ generation: prepared.error.detail.generation,
234
+ lastKnownGood: true,
235
+ },
236
+ }),
237
+ );
238
+ return {
239
+ plan: lkgPlan,
240
+ vertexBuffer: lkg.resource.vertexBuffer,
241
+ indexBuffer: lkg.resource.indexBuffer,
242
+ layoutProjection: this.layoutProjection,
243
+ };
244
+ }
245
+ this.publishRefusal(inspections, snapshot, prepared.error);
246
+ return undefined;
247
+ }
248
+ const plan = createPointsLinesLaneAdapter(lane, backend).createRecordPlan(
249
+ snapshot,
250
+ prepared.value.geometry,
251
+ );
252
+ const state = preparation.inspect();
253
+ inspections.set(
254
+ key,
255
+ inspectPointsLines({
256
+ snapshot,
257
+ topology,
258
+ lane,
259
+ pointCount: prepared.value.geometry.pointCount,
260
+ segmentCount: prepared.value.geometry.segmentCount,
261
+ sourceBytes: prepared.value.geometry.sourceBytes,
262
+ derivedBytes: prepared.value.geometry.derivedBytes,
263
+ cache: {
264
+ hit: prepared.value.uploadedBytes === 0,
265
+ rebuilds: state.rebuilds,
266
+ evictions: 0,
267
+ },
268
+ drawCount: plan.drawCount,
269
+ uploadBytes: prepared.value.uploadedBytes,
270
+ lastKnownGood: prepared.value.lastKnownGood,
271
+ }),
272
+ );
273
+ return {
274
+ plan,
275
+ vertexBuffer: prepared.value.resource.vertexBuffer,
276
+ indexBuffer: prepared.value.resource.indexBuffer,
277
+ layoutProjection: this.layoutProjection,
278
+ };
279
+ }
280
+
281
+ resetForDeviceLoss(): void {
282
+ for (const preparation of this.preparations.values()) preparation.resetForDeviceLoss();
283
+ this.active.clear();
284
+ }
285
+
286
+ abandonForDeviceLoss(): void {
287
+ for (const preparation of this.preparations.values()) {
288
+ preparation.abandonForDeviceLoss();
289
+ }
290
+ this.active.clear();
291
+ }
292
+
293
+ dispose(): void {
294
+ this.resetForDeviceLoss();
295
+ this.preparations.clear();
296
+ }
297
+
298
+ inspections(): readonly PointsLinesInspection[] {
299
+ return [...this.active.values()];
300
+ }
301
+
302
+ private backend(runtime: RenderSystemInternals): PointsLinesBackend {
303
+ switch (runtime.device.caps.backendKind) {
304
+ case 'wgpu-webgl2':
305
+ return 'wgpu-webgl2';
306
+ case 'null':
307
+ return 'null';
308
+ default:
309
+ return 'webgpu';
310
+ }
311
+ }
312
+
313
+ private publishRefusal(
314
+ inspections: Map<string, PointsLinesInspection>,
315
+ snapshot: PointsLinesRetainedSnapshot,
316
+ error: PointsLinesSourceError,
317
+ ): void {
318
+ inspections.set(
319
+ `${snapshot.worldId}:${snapshot.entityKey}`,
320
+ inspectPointsLines({
321
+ snapshot,
322
+ topology: snapshot.component === 'Points' ? 'point-list' : 'line-list',
323
+ lane: 'refused',
324
+ pointCount: 0,
325
+ segmentCount: 0,
326
+ sourceBytes: 0,
327
+ derivedBytes: 0,
328
+ cache: { hit: false, rebuilds: 0, evictions: 0 },
329
+ drawCount: 0,
330
+ uploadBytes: 0,
331
+ lastKnownGood: false,
332
+ refusal: {
333
+ code: error.code,
334
+ expected: error.expected,
335
+ hint: error.hint,
336
+ detail: error.detail,
337
+ generation: snapshot.meshGeneration,
338
+ lastKnownGood: false,
339
+ },
340
+ }),
341
+ );
342
+ }
343
+
344
+ private createPreparation(
345
+ runtime: RenderSystemInternals,
346
+ geometryKey: string,
347
+ lane: PointsLinesLane,
348
+ backend: PointsLinesBackend,
349
+ ): PointsLinesPreparationAdapter {
350
+ return createPointsLinesLanePreparationAdapter(lane, backend, {
351
+ cache: this.cache,
352
+ adapter: {
353
+ create: (geometry) => {
354
+ const vertex = runtime.device.createBuffer({
355
+ label: `points-lines-vertices:${geometryKey}`,
356
+ size: Math.max(4, geometry.vertices.byteLength),
357
+ usage: GPU_BUFFER_USAGE_VERTEX | GPU_BUFFER_USAGE_COPY_DST,
358
+ mappedAtCreation: false,
359
+ });
360
+ if (!vertex.ok) return err(vertex.error);
361
+ const index = runtime.device.createBuffer({
362
+ label: `points-lines-indices:${geometryKey}`,
363
+ size: Math.max(4, geometry.indices.byteLength),
364
+ usage: GPU_BUFFER_USAGE_INDEX | GPU_BUFFER_USAGE_COPY_DST,
365
+ mappedAtCreation: false,
366
+ });
367
+ if (!index.ok) {
368
+ runtime.device.destroyBuffer(vertex.value);
369
+ return err(index.error);
370
+ }
371
+ return ok({ vertexBuffer: vertex.value, indexBuffer: index.value });
372
+ },
373
+ upload: (resource, geometry) => {
374
+ if (geometry.vertices.byteLength > 0) {
375
+ const vertexWrite = runtime.device.queue.writeBuffer(
376
+ resource.vertexBuffer,
377
+ 0,
378
+ geometry.vertices,
379
+ );
380
+ if (!vertexWrite.ok) return err(vertexWrite.error);
381
+ }
382
+ if (geometry.indices.byteLength > 0) {
383
+ const indexWrite = runtime.device.queue.writeBuffer(
384
+ resource.indexBuffer,
385
+ 0,
386
+ geometry.indices,
387
+ );
388
+ if (!indexWrite.ok) return err(indexWrite.error);
389
+ }
390
+ return ok(geometry.derivedBytes);
391
+ },
392
+ validate: (_resource, geometry) =>
393
+ geometry.expandedVertexCount > 0 && geometry.expandedIndexCount > 0
394
+ ? ok(undefined)
395
+ : err(new Error('Points/Lines expansion contains no drawable triangles')),
396
+ destroy: (resource) => {
397
+ runtime.device.destroyBuffer(resource.vertexBuffer);
398
+ runtime.device.destroyBuffer(resource.indexBuffer);
399
+ },
400
+ },
401
+ });
402
+ }
403
+ }
@@ -0,0 +1,56 @@
1
+ import type { RhiCaps, RhiDevice } from '@forgeax/engine-rhi';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { deriveExtendedLightingCapability } from '../extended-lighting/resources';
4
+
5
+ const device = {
6
+ caps: {
7
+ backendKind: 'null',
8
+ compute: true,
9
+ storageBuffer: true,
10
+ storageTexture: true,
11
+ rgba16floatRenderable: true,
12
+ samplerAliasing: true,
13
+ } as RhiCaps,
14
+ limits: {
15
+ maxSampledTexturesPerShaderStage: 20,
16
+ maxTextureDimension2D: 4096,
17
+ maxTextureArrayLayers: 32,
18
+ maxUniformBuffersPerShaderStage: 12,
19
+ },
20
+ } as unknown as RhiDevice;
21
+
22
+ describe('extended lighting capability admission', () => {
23
+ it('derives admission from real format, filter, array, and uniform facts', () => {
24
+ expect(deriveExtendedLightingCapability(device)).toEqual({
25
+ admitted: true,
26
+ topology: 'extendedLighting',
27
+ reason: undefined,
28
+ });
29
+ });
30
+
31
+ it('rejects a device whose array or uniform limit cannot hold the contract', () => {
32
+ const limited = {
33
+ ...device,
34
+ limits: { ...device.limits, maxTextureArrayLayers: 16, maxUniformBuffersPerShaderStage: 0 },
35
+ } as RhiDevice;
36
+
37
+ expect(deriveExtendedLightingCapability(limited)).toMatchObject({
38
+ admitted: false,
39
+ topology: 'extendedLighting',
40
+ reason: expect.stringContaining('maxTextureArrayLayers'),
41
+ });
42
+ });
43
+
44
+ it('rejects the topology when the sampled-texture limit is below the shader contract', () => {
45
+ const limited = {
46
+ ...device,
47
+ limits: { ...device.limits, maxSampledTexturesPerShaderStage: 16 },
48
+ } as RhiDevice;
49
+
50
+ expect(deriveExtendedLightingCapability(limited)).toEqual({
51
+ admitted: false,
52
+ topology: 'extendedLighting',
53
+ reason: 'maxSampledTexturesPerShaderStage 16 < 20',
54
+ });
55
+ });
56
+ });