@forgeax/engine-render 0.1.21 → 0.1.23

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 (426) hide show
  1. package/README.md +150 -29
  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/device-feature-admission.d.ts.map +1 -1
  5. package/dist/assembly/factory.d.ts +14 -6
  6. package/dist/assembly/factory.d.ts.map +1 -1
  7. package/dist/assembly/host-contract.d.ts +10 -0
  8. package/dist/assembly/host-contract.d.ts.map +1 -1
  9. package/dist/authoring.mjs +1 -1
  10. package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
  11. package/dist/chunk-4L3P6DT5.mjs.map +1 -0
  12. package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
  13. package/dist/chunk-4NPUASZR.mjs.map +1 -0
  14. package/dist/chunk-DIYW3M5D.mjs +5085 -0
  15. package/dist/chunk-DIYW3M5D.mjs.map +1 -0
  16. package/dist/chunk-FBC4R44J.mjs +1003 -0
  17. package/dist/chunk-FBC4R44J.mjs.map +1 -0
  18. package/dist/{chunk-FS2KNUQH.mjs → chunk-FF7K3FSO.mjs} +253 -489
  19. package/dist/chunk-FF7K3FSO.mjs.map +1 -0
  20. package/dist/chunk-HZUPSYW7.mjs +1104 -0
  21. package/dist/chunk-HZUPSYW7.mjs.map +1 -0
  22. package/dist/{chunk-6OPXDQ2E.mjs → chunk-QODA5UKU.mjs} +33 -294
  23. package/dist/chunk-QODA5UKU.mjs.map +1 -0
  24. package/dist/chunk-YALPS44A.mjs +296 -0
  25. package/dist/chunk-YALPS44A.mjs.map +1 -0
  26. package/dist/{chunk-5YADUCA7.mjs → chunk-ZUWKAZ2I.mjs} +585 -991
  27. package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
  28. package/dist/cluster-binner.d.ts +5 -0
  29. package/dist/cluster-binner.d.ts.map +1 -1
  30. package/dist/components/index.d.ts +3 -0
  31. package/dist/components/index.d.ts.map +1 -1
  32. package/dist/components/light-helpers.d.ts +4 -0
  33. package/dist/components/light-helpers.d.ts.map +1 -1
  34. package/dist/components/light-probe.d.ts +9 -0
  35. package/dist/components/light-probe.d.ts.map +1 -0
  36. package/dist/components/rect-area-light.d.ts +12 -0
  37. package/dist/components/rect-area-light.d.ts.map +1 -0
  38. package/dist/components/scene-instance.d.ts +4 -0
  39. package/dist/components/scene-instance.d.ts.map +1 -1
  40. package/dist/components/spot-light.d.ts +3 -0
  41. package/dist/components/spot-light.d.ts.map +1 -1
  42. package/dist/construct-renderer.mjs +10437 -10044
  43. package/dist/construct-renderer.mjs.map +1 -1
  44. package/dist/device/gpu-residency.d.ts +8 -1
  45. package/dist/device/gpu-residency.d.ts.map +1 -1
  46. package/dist/device/lifecycle-transaction.d.ts +2 -0
  47. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  48. package/dist/environment/lifecycle.d.ts.map +1 -1
  49. package/dist/errors/gpu-driven.d.ts +26 -0
  50. package/dist/errors/gpu-driven.d.ts.map +1 -0
  51. package/dist/errors/index.d.ts +1 -0
  52. package/dist/errors/index.d.ts.map +1 -1
  53. package/dist/errors/recover.d.ts +9 -1
  54. package/dist/errors/recover.d.ts.map +1 -1
  55. package/dist/errors/render.d.ts +26 -1
  56. package/dist/errors/render.d.ts.map +1 -1
  57. package/dist/extract/gpu-driven.d.ts +50 -0
  58. package/dist/extract/gpu-driven.d.ts.map +1 -0
  59. package/dist/extract/visibility.d.ts.map +1 -1
  60. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  61. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  62. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  63. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  64. package/dist/gpu-driven/production-raster.d.ts +98 -2
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  67. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  68. package/dist/gpu-scene-schema.d.ts +14 -0
  69. package/dist/gpu-scene-schema.d.ts.map +1 -1
  70. package/dist/gpu-scene.d.ts +8 -1
  71. package/dist/gpu-scene.d.ts.map +1 -1
  72. package/dist/gpu-usage.d.ts +0 -1
  73. package/dist/gpu-usage.d.ts.map +1 -1
  74. package/dist/hdrp-buffers.d.ts +3 -3
  75. package/dist/hdrp-buffers.d.ts.map +1 -1
  76. package/dist/index.d.ts +12 -1
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.mjs +90 -5
  79. package/dist/index.mjs.map +1 -1
  80. package/dist/inspection-types.d.ts +163 -1
  81. package/dist/inspection-types.d.ts.map +1 -1
  82. package/dist/internal.d.ts +9 -0
  83. package/dist/internal.d.ts.map +1 -1
  84. package/dist/internal.mjs +23 -2
  85. package/dist/internal.mjs.map +1 -1
  86. package/dist/light-buffer-layout.d.ts +58 -149
  87. package/dist/light-buffer-layout.d.ts.map +1 -1
  88. package/dist/materials.d.ts.map +1 -1
  89. package/dist/pbr-pipeline.d.ts +26 -12
  90. package/dist/pbr-pipeline.d.ts.map +1 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
  93. package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
  94. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
  95. package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
  96. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
  97. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
  98. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  99. package/dist/pipeline-builder.d.ts +2 -0
  100. package/dist/pipeline-builder.d.ts.map +1 -1
  101. package/dist/pipeline-spec.d.ts +1 -1
  102. package/dist/pipeline-spec.d.ts.map +1 -1
  103. package/dist/plugin.d.ts.map +1 -1
  104. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  105. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  106. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  107. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  108. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  109. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  110. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  111. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  112. package/dist/record/frame-lighting.d.ts +8 -6
  113. package/dist/record/frame-lighting.d.ts.map +1 -1
  114. package/dist/record/frame-snapshot.d.ts +50 -10
  115. package/dist/record/frame-snapshot.d.ts.map +1 -1
  116. package/dist/record/frame.d.ts +7 -3
  117. package/dist/record/frame.d.ts.map +1 -1
  118. package/dist/record/gpu-timing.d.ts +19 -7
  119. package/dist/record/gpu-timing.d.ts.map +1 -1
  120. package/dist/record/helpers.d.ts +0 -20
  121. package/dist/record/helpers.d.ts.map +1 -1
  122. package/dist/record/main-pass-geometry.d.ts +6 -1
  123. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  124. package/dist/record/main-pass-material.d.ts +3 -1
  125. package/dist/record/main-pass-material.d.ts.map +1 -1
  126. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  127. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  128. package/dist/record/render-context.d.ts +57 -6
  129. package/dist/record/render-context.d.ts.map +1 -1
  130. package/dist/record/shadow-pass.d.ts.map +1 -1
  131. package/dist/record/typed-frame-graph.d.ts +49 -2
  132. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  133. package/dist/record/view-ubo.d.ts +1 -2
  134. package/dist/record/view-ubo.d.ts.map +1 -1
  135. package/dist/reflection/inspection.d.ts +10 -0
  136. package/dist/reflection/inspection.d.ts.map +1 -0
  137. package/dist/reflection/projection.d.ts +49 -0
  138. package/dist/reflection/projection.d.ts.map +1 -1
  139. package/dist/reflection/record-owner.d.ts +60 -0
  140. package/dist/reflection/record-owner.d.ts.map +1 -0
  141. package/dist/render-contract.d.ts +14 -8
  142. package/dist/render-contract.d.ts.map +1 -1
  143. package/dist/render-pipeline.d.ts +7 -0
  144. package/dist/render-pipeline.d.ts.map +1 -1
  145. package/dist/render-system-extract.d.ts +104 -16
  146. package/dist/render-system-extract.d.ts.map +1 -1
  147. package/dist/render-system.d.ts +12 -1
  148. package/dist/render-system.d.ts.map +1 -1
  149. package/dist/scene/probe-blend-record.d.ts +22 -0
  150. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  151. package/dist/scene/probe-blend.d.ts +142 -0
  152. package/dist/scene/probe-blend.d.ts.map +1 -0
  153. package/dist/scene/render-scene-types.d.ts +0 -6
  154. package/dist/scene/render-scene-types.d.ts.map +1 -1
  155. package/dist/scene/render-scene.d.ts +103 -9
  156. package/dist/scene/render-scene.d.ts.map +1 -1
  157. package/dist/scene/visibility/bounds.d.ts +20 -0
  158. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  159. package/dist/scene/visibility/budget.d.ts +16 -0
  160. package/dist/scene/visibility/budget.d.ts.map +1 -0
  161. package/dist/scene/visibility/facet.d.ts +73 -0
  162. package/dist/scene/visibility/facet.d.ts.map +1 -0
  163. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  164. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  165. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  166. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  167. package/dist/scene/visibility/inspection.d.ts +132 -0
  168. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  169. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  170. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  171. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  172. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  173. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  174. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  175. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  176. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  177. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  178. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  179. package/dist/scene/visibility/types.d.ts +34 -0
  180. package/dist/scene/visibility/types.d.ts.map +1 -0
  181. package/dist/ssr/admission.d.ts +122 -0
  182. package/dist/ssr/admission.d.ts.map +1 -0
  183. package/dist/ssr/composition.d.ts +32 -0
  184. package/dist/ssr/composition.d.ts.map +1 -0
  185. package/dist/ssr/errors.d.ts +39 -0
  186. package/dist/ssr/errors.d.ts.map +1 -0
  187. package/dist/ssr/identity.d.ts +13 -0
  188. package/dist/ssr/identity.d.ts.map +1 -0
  189. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  190. package/dist/temporal/frame-coordinator.d.ts +13 -0
  191. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  192. package/dist/temporal/frame.d.ts +2 -0
  193. package/dist/temporal/frame.d.ts.map +1 -1
  194. package/dist/temporal/index.mjs +6 -5
  195. package/dist/temporal/view.d.ts +7 -0
  196. package/dist/temporal/view.d.ts.map +1 -1
  197. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  198. package/dist/typed-render-graph-primitives.d.ts +4 -0
  199. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  200. package/dist/volume/passes.d.ts +8 -4
  201. package/dist/volume/passes.d.ts.map +1 -1
  202. package/package.json +20 -20
  203. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
  204. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  205. package/src/__tests__/device-feature-admission.unit.test.ts +13 -1
  206. package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
  207. package/src/__tests__/environment-generation.integration.test.ts +16 -0
  208. package/src/__tests__/evidence-identity.ts +13 -0
  209. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  210. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  211. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  212. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  213. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  214. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  215. package/src/__tests__/factory-contract.integration.test.ts +33 -0
  216. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  217. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  218. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
  219. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
  220. package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
  221. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  222. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  223. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
  224. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  225. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  226. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  227. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  228. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  229. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  230. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  231. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  232. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  233. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  234. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  235. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  236. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  237. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  238. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  239. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  240. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  241. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  242. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  243. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  244. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  245. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  246. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  247. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  248. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  249. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  250. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  251. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  252. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  253. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  254. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  255. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  256. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  257. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  258. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  259. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  260. package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
  261. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  262. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  263. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  264. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  265. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  266. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  267. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  268. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  269. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  270. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  271. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  272. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  273. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  274. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  275. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  276. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  277. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  278. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  279. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  280. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  281. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  282. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  283. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  284. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  285. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  286. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  287. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  288. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  289. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  290. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  291. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  292. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  293. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  294. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  295. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  296. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  297. package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
  298. package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
  299. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  300. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  301. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  302. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  303. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  304. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
  305. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
  306. package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
  307. package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
  308. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  309. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  310. package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
  311. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  312. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  313. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  315. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  316. package/src/assembly/backend-contract.ts +13 -0
  317. package/src/assembly/device-feature-admission.ts +16 -9
  318. package/src/assembly/factory.ts +547 -93
  319. package/src/assembly/host-contract.ts +10 -0
  320. package/src/cluster-binner.ts +31 -0
  321. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  322. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  323. package/src/components/index.ts +3 -0
  324. package/src/components/light-helpers.ts +52 -1
  325. package/src/components/light-probe.ts +13 -0
  326. package/src/components/rect-area-light.ts +15 -0
  327. package/src/components/scene-instance.ts +6 -0
  328. package/src/components/spot-light.ts +3 -0
  329. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  330. package/src/device/gpu-residency.ts +140 -9
  331. package/src/device/lifecycle-transaction.ts +12 -0
  332. package/src/environment/lifecycle.ts +8 -1
  333. package/src/errors/gpu-driven.ts +92 -0
  334. package/src/errors/index.ts +1 -0
  335. package/src/errors/recover.ts +32 -0
  336. package/src/errors/render.ts +55 -1
  337. package/src/extract/camera.ts +3 -3
  338. package/src/extract/gpu-driven.ts +108 -0
  339. package/src/extract/visibility.ts +0 -23
  340. package/src/gpu-driven/batch-topology.ts +206 -28
  341. package/src/gpu-driven/prepared-draw.ts +208 -0
  342. package/src/gpu-driven/production-raster.ts +953 -41
  343. package/src/gpu-driven/view-gpu.ts +411 -29
  344. package/src/gpu-scene-schema.ts +13 -0
  345. package/src/gpu-scene.ts +134 -65
  346. package/src/gpu-usage.ts +0 -1
  347. package/src/hdrp-buffers.ts +6 -6
  348. package/src/index.ts +74 -0
  349. package/src/inspection-types.ts +220 -1
  350. package/src/internal.ts +38 -0
  351. package/src/light-buffer-layout.ts +154 -324
  352. package/src/materials.ts +16 -2
  353. package/src/pbr-pipeline.ts +151 -45
  354. package/src/pipeline/standard-forward-lane.ts +47 -0
  355. package/src/pipeline/standard-lighting/graph.ts +2 -1
  356. package/src/pipeline/standard-lighting/light-frame.ts +3 -2
  357. package/src/pipeline/standard-lighting/topology.ts +1 -1
  358. package/src/pipeline/standard-lighting/transport.ts +2 -1
  359. package/src/pipeline/standard-pipeline.ts +2 -0
  360. package/src/pipeline-builder.ts +5 -2
  361. package/src/pipeline-spec.ts +12 -1
  362. package/src/plugin.ts +4 -0
  363. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  364. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  365. package/src/prepare/extended-lighting/resources.ts +389 -0
  366. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  367. package/src/prepare/extended-lighting/state.ts +92 -0
  368. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  369. package/src/record/__tests__/temporal-payload.unit.test.ts +23 -1
  370. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
  371. package/src/record/frame-lighting.ts +252 -53
  372. package/src/record/frame-snapshot.ts +57 -12
  373. package/src/record/frame.ts +410 -93
  374. package/src/record/gpu-timing.ts +108 -44
  375. package/src/record/helpers.ts +0 -58
  376. package/src/record/main-pass-geometry.ts +204 -39
  377. package/src/record/main-pass-material.ts +8 -1
  378. package/src/record/main-pass-sprite-draws.ts +52 -85
  379. package/src/record/mesh-ssbo.ts +47 -36
  380. package/src/record/render-context.ts +65 -4
  381. package/src/record/shadow-pass.ts +66 -40
  382. package/src/record/typed-frame-graph.ts +225 -83
  383. package/src/record/view-ubo.ts +14 -24
  384. package/src/reflection/inspection.ts +67 -0
  385. package/src/reflection/projection.ts +196 -1
  386. package/src/reflection/record-owner.ts +1283 -0
  387. package/src/render-contract.ts +17 -5
  388. package/src/render-pipeline.ts +5 -0
  389. package/src/render-system-extract.ts +493 -134
  390. package/src/render-system.ts +811 -615
  391. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  392. package/src/scene/probe-blend-record.ts +54 -0
  393. package/src/scene/probe-blend.ts +813 -0
  394. package/src/scene/render-scene-types.ts +0 -7
  395. package/src/scene/render-scene.ts +848 -183
  396. package/src/scene/visibility/bounds.ts +57 -0
  397. package/src/scene/visibility/budget.ts +40 -0
  398. package/src/scene/visibility/facet.ts +400 -0
  399. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  400. package/src/scene/visibility/gpu-lod.ts +119 -0
  401. package/src/scene/visibility/inspection.ts +313 -0
  402. package/src/scene/visibility/lod-selector.ts +84 -0
  403. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  404. package/src/scene/visibility/occlusion-pass.ts +165 -0
  405. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  406. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  407. package/src/scene/visibility/types.ts +50 -0
  408. package/src/ssr/admission.ts +451 -0
  409. package/src/ssr/composition.ts +73 -0
  410. package/src/ssr/errors.ts +76 -0
  411. package/src/ssr/identity.ts +12 -0
  412. package/src/systems/skin-palette-allocator.ts +1 -1
  413. package/src/temporal/frame-coordinator.ts +26 -0
  414. package/src/temporal/frame.ts +14 -1
  415. package/src/temporal/view.ts +11 -0
  416. package/src/tilemap-chunk-extract-system.ts +4 -4
  417. package/src/typed-render-graph-primitives.ts +48 -0
  418. package/src/volume/passes.ts +46 -49
  419. package/dist/.tsbuildinfo +0 -1
  420. package/dist/chunk-5YADUCA7.mjs.map +0 -1
  421. package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
  422. package/dist/chunk-BXBQQKFQ.mjs +0 -67
  423. package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
  424. package/dist/chunk-FS2KNUQH.mjs.map +0 -1
  425. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  426. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
package/src/gpu-scene.ts CHANGED
@@ -37,6 +37,8 @@ interface PrimitiveAllocation {
37
37
  readonly instanceStart: number;
38
38
  readonly instanceCount: number;
39
39
  readonly transformStart: number;
40
+ readonly instanceTransformStart: number;
41
+ readonly instanceTransformCount: number;
40
42
  readonly drawStart: number;
41
43
  readonly drawCount: number;
42
44
  readonly materialStart: number;
@@ -85,8 +87,8 @@ class StableRangeAllocator {
85
87
  return this.next;
86
88
  }
87
89
 
88
- reset(): void {
89
- this.next = 0;
90
+ reset(start = 0): void {
91
+ this.next = start;
90
92
  this.free.length = 0;
91
93
  }
92
94
  }
@@ -177,7 +179,14 @@ function stableU32(value: string): number {
177
179
  function coalesceSlots(
178
180
  slots: readonly number[],
179
181
  ): readonly { readonly start: number; readonly end: number }[] {
180
- const ordered = [...new Set(slots)].sort((a, b) => a - b);
182
+ let alreadyOrdered = true;
183
+ for (let index = 1; index < slots.length; index += 1) {
184
+ if ((slots[index] ?? 0) <= (slots[index - 1] ?? 0)) {
185
+ alreadyOrdered = false;
186
+ break;
187
+ }
188
+ }
189
+ const ordered = alreadyOrdered ? slots : [...new Set(slots)].sort((a, b) => a - b);
181
190
  const ranges: Array<{ start: number; end: number }> = [];
182
191
  for (const slot of ordered) {
183
192
  const previous = ranges.at(-1);
@@ -193,6 +202,8 @@ function coalesceSlots(
193
202
  /** Persistent GPU tables derived only from renderer projection slots. */
194
203
  export class GpuScene {
195
204
  private tableBytes: Record<GpuSceneTableName, ArrayBuffer>;
205
+ private transformBytes: Uint8Array;
206
+ private transformView: DataView;
196
207
  private buffers: GpuSceneBuffers;
197
208
  private uploadRanges = 0;
198
209
  private uploadBytes = 0;
@@ -200,11 +211,19 @@ export class GpuScene {
200
211
  private fullRebuilds = 0;
201
212
  private clearedSlots = 0;
202
213
  private noChangeFrames = 0;
203
- private readonly allocations = new Map<number, PrimitiveAllocation>();
214
+ private identityUploaded = false;
215
+ private readonly allocations: Array<PrimitiveAllocation | undefined> = [];
204
216
  private readonly instances = new StableRangeAllocator();
205
217
  private readonly transforms = new StableRangeAllocator();
206
218
  private readonly draws = new StableRangeAllocator();
207
219
  private readonly materials = new StableRangeAllocator();
220
+ private readonly writesByTable: Record<GpuSceneTableName, number[]> = {
221
+ primitive: [],
222
+ instance: [],
223
+ transform: [],
224
+ drawTemplate: [],
225
+ material: [],
226
+ };
208
227
 
209
228
  private constructor(
210
229
  private readonly device: RhiDevice,
@@ -213,6 +232,10 @@ export class GpuScene {
213
232
  ) {
214
233
  this.buffers = buffers;
215
234
  this.tableBytes = this.allocateCpuTables(capacity);
235
+ this.transformBytes = new Uint8Array(this.tableBytes.transform);
236
+ this.transformView = new DataView(this.tableBytes.transform);
237
+ this.transforms.reset(1);
238
+ this.writeIdentityTransform();
216
239
  }
217
240
 
218
241
  static create(device: RhiDevice, initialCapacity = 256): Result<GpuSceneAvailability, RhiError> {
@@ -249,25 +272,33 @@ export class GpuScene {
249
272
  }
250
273
 
251
274
  sync(delta: RenderSceneApplyResult): Result<GpuSceneSyncResult, RhiError> {
252
- const writes = [...delta.createdSlots, ...delta.updatedSlots, ...delta.recreatedSlots];
253
- const changedSlots = [
254
- ...writes.map((record) => record.slot),
255
- ...delta.removedSlots.map((r) => r.slot),
256
- ];
257
- if (changedSlots.length === 0) {
275
+ if (
276
+ delta.createdSlots.length === 0 &&
277
+ delta.updatedSlots.length === 0 &&
278
+ delta.recreatedSlots.length === 0 &&
279
+ delta.removedSlots.length === 0
280
+ ) {
258
281
  this.noChangeFrames += 1;
259
282
  return ok({ ranges: 0, bytes: 0, grew: false, cleared: 0 });
260
283
  }
261
- const writesByTable: Record<GpuSceneTableName, number[]> = {
262
- primitive: [],
263
- instance: [],
264
- transform: [],
265
- drawTemplate: [],
266
- material: [],
267
- };
268
- for (const record of writes) this.ensureAllocation(record, writesByTable);
284
+ const writesByTable = this.writesByTable;
285
+ for (const name of TABLE_NAMES) writesByTable[name].length = 0;
286
+ if (!this.identityUploaded) writesByTable.transform.push(0);
287
+ let highestChangedSlot = -1;
288
+ for (const records of [delta.createdSlots, delta.recreatedSlots]) {
289
+ for (const record of records) {
290
+ this.ensureAllocation(record, writesByTable);
291
+ if (record.slot > highestChangedSlot) highestChangedSlot = record.slot;
292
+ }
293
+ }
294
+ for (const record of delta.updatedSlots) {
295
+ if (record.slot > highestChangedSlot) highestChangedSlot = record.slot;
296
+ }
297
+ for (const record of delta.removedSlots) {
298
+ if (record.slot > highestChangedSlot) highestChangedSlot = record.slot;
299
+ }
269
300
  const requiredCapacity = Math.max(
270
- Math.max(...changedSlots) + 1,
301
+ highestChangedSlot + 1,
271
302
  this.instances.requiredCapacity(),
272
303
  this.transforms.requiredCapacity(),
273
304
  this.draws.requiredCapacity(),
@@ -280,11 +311,12 @@ export class GpuScene {
280
311
  }
281
312
 
282
313
  for (const record of delta.createdSlots) this.writeSlot(record, true, writesByTable);
283
- for (const record of delta.updatedSlots) this.writeSlot(record, false, writesByTable);
314
+ for (const record of delta.updatedSlots) this.writeRootTransform(record, false, writesByTable);
284
315
  for (const record of delta.recreatedSlots) this.writeSlot(record, true, writesByTable);
285
316
  for (const record of delta.removedSlots) this.clearSlot(record.slot, writesByTable);
286
317
  const uploaded = this.uploadRows(writesByTable);
287
318
  if (!uploaded.ok) return uploaded;
319
+ this.identityUploaded = true;
288
320
  this.clearedSlots += delta.removedSlots.length;
289
321
  return ok({
290
322
  ranges: uploaded.value.ranges,
@@ -295,10 +327,11 @@ export class GpuScene {
295
327
  }
296
328
 
297
329
  /** Publish current transforms as previous only after a successful submit. */
298
- commitTemporalFrame(): Result<void, RhiError> {
330
+ commitTemporalFrame(enabled = true): Result<void, RhiError> {
331
+ if (!enabled) return ok(undefined);
299
332
  const nextTransform = this.tableBytes.transform.slice(0);
300
333
  const next = new Uint8Array(nextTransform);
301
- const current = new Uint8Array(this.tableBytes.transform);
334
+ const current = this.transformBytes;
302
335
  const currentOffset = offset(TRANSFORM, 'currentWorld');
303
336
  const previousOffset = offset(TRANSFORM, 'previousWorld');
304
337
  for (let index = 0; index < this.capacity; index += 1) {
@@ -313,15 +346,16 @@ export class GpuScene {
313
346
  const uploaded = this.device.queue.writeBuffer(this.buffers.transform, 0, next);
314
347
  if (!uploaded.ok) return uploaded;
315
348
  this.tableBytes.transform = nextTransform;
349
+ this.refreshTransformViews();
316
350
  this.uploadRanges += 1;
317
351
  this.uploadBytes += next.byteLength;
318
352
  return ok(undefined);
319
353
  }
320
354
 
321
355
  rebuild(slots: readonly RenderSceneSlot[]): Result<GpuSceneSyncResult, RhiError> {
322
- this.allocations.clear();
356
+ this.allocations.length = 0;
323
357
  this.instances.reset();
324
- this.transforms.reset();
358
+ this.transforms.reset(1);
325
359
  this.draws.reset();
326
360
  this.materials.reset();
327
361
  const writesByTable: Record<GpuSceneTableName, number[]> = {
@@ -347,6 +381,7 @@ export class GpuScene {
347
381
  grew = true;
348
382
  }
349
383
  for (const bytes of Object.values(this.tableBytes)) new Uint8Array(bytes).fill(0);
384
+ this.writeIdentityTransform();
350
385
  for (const slot of slots) this.writeSlot(slot, true, writesByTable);
351
386
  let bytes = 0;
352
387
  for (const name of TABLE_NAMES) {
@@ -358,6 +393,7 @@ export class GpuScene {
358
393
  this.uploadRanges += TABLE_NAMES.length;
359
394
  this.uploadBytes += bytes;
360
395
  this.fullRebuilds += 1;
396
+ this.identityUploaded = true;
361
397
  return ok({ ranges: TABLE_NAMES.length, bytes, grew, cleared: 0 });
362
398
  }
363
399
 
@@ -404,7 +440,7 @@ export class GpuScene {
404
440
  resetPrevious: boolean,
405
441
  writes: Record<GpuSceneTableName, number[]>,
406
442
  ): void {
407
- const allocation = this.allocations.get(record.slot);
443
+ const allocation = this.allocations[record.slot];
408
444
  if (allocation === undefined) throw new RangeError('GPU Scene allocation unavailable');
409
445
  const primitiveOffset = record.slot * PRIMITIVE.stride;
410
446
  const primitive = new DataView(this.tableBytes.primitive);
@@ -461,45 +497,34 @@ export class GpuScene {
461
497
  ]);
462
498
 
463
499
  const instance = new DataView(this.tableBytes.instance);
464
- const transform = new DataView(this.tableBytes.transform);
500
+ const transform = this.transformView;
465
501
  for (let ordinal = 0; ordinal < allocation.instanceCount; ordinal += 1) {
466
502
  const instanceIndex = allocation.instanceStart + ordinal;
467
503
  const instanceOffset = instanceIndex * INSTANCE.stride;
468
- const transformIndex = allocation.transformStart + 1 + ordinal;
504
+ const transformIndex =
505
+ allocation.instanceTransformCount === 0 ? 0 : allocation.instanceTransformStart + ordinal;
469
506
  instance.setUint32(instanceOffset + offset(INSTANCE, 'primitiveIndex'), record.slot, true);
470
507
  instance.setUint32(instanceOffset + offset(INSTANCE, 'transformIndex'), transformIndex, true);
471
508
  instance.setUint32(instanceOffset + offset(INSTANCE, 'customDataStart'), 0, true);
472
509
  instance.setUint32(instanceOffset + offset(INSTANCE, 'flags'), PRIMITIVE_ACTIVE, true);
473
- const local = record.snapshot.instances?.transforms.subarray(ordinal * 16, ordinal * 16 + 16);
474
- const localWorld = local?.length === 16 ? local : IDENTITY_MATRIX;
475
- const localOffset = transformIndex * TRANSFORM.stride;
476
- const localCurrentOffset = localOffset + offset(TRANSFORM, 'currentWorld');
477
- const localPreviousOffset = localOffset + offset(TRANSFORM, 'previousWorld');
478
- const priorLocal = new Uint8Array(
479
- this.tableBytes.transform.slice(localCurrentOffset, localCurrentOffset + 64),
480
- );
481
- writeMat4(transform, localCurrentOffset, localWorld);
482
- if (!resetPrevious && priorLocal.some((value) => value !== 0)) {
483
- new Uint8Array(this.tableBytes.transform, localPreviousOffset, 64).set(priorLocal);
484
- } else {
510
+ if (allocation.instanceTransformCount > 0) {
511
+ const local = record.snapshot.instances?.transforms.subarray(
512
+ ordinal * 16,
513
+ ordinal * 16 + 16,
514
+ );
515
+ const localWorld = local?.length === 16 ? local : IDENTITY_MATRIX;
516
+ const localOffset = transformIndex * TRANSFORM.stride;
517
+ const localCurrentOffset = localOffset + offset(TRANSFORM, 'currentWorld');
518
+ const localPreviousOffset = localOffset + offset(TRANSFORM, 'previousWorld');
519
+ writeMat4(transform, localCurrentOffset, localWorld);
485
520
  writeMat4(transform, localPreviousOffset, localWorld);
521
+ writes.transform.push(transformIndex);
486
522
  }
487
523
  writes.instance.push(instanceIndex);
488
- writes.transform.push(transformIndex);
489
524
  }
490
525
 
491
- const transformOffset = allocation.transformStart * TRANSFORM.stride;
492
- const currentOffset = transformOffset + offset(TRANSFORM, 'currentWorld');
493
- const previousOffset = transformOffset + offset(TRANSFORM, 'previousWorld');
494
- const priorCurrent = new Uint8Array(
495
- this.tableBytes.transform.slice(currentOffset, currentOffset + 64),
496
- );
497
- const hasPrior = !resetPrevious && priorCurrent.some((value) => value !== 0);
498
- writeMat4(transform, currentOffset, record.snapshot.transform.world);
499
- if (hasPrior) new Uint8Array(this.tableBytes.transform, previousOffset, 64).set(priorCurrent);
500
- else writeMat4(transform, previousOffset, record.snapshot.transform.world);
526
+ this.writeRootTransform(record, resetPrevious, writes);
501
527
  writes.primitive.push(record.slot);
502
- writes.transform.push(allocation.transformStart);
503
528
 
504
529
  const draw = new DataView(this.tableBytes.drawTemplate);
505
530
  const drawSnapshots = record.snapshot.gpuDrivenDraws ?? [];
@@ -509,7 +534,13 @@ export class GpuScene {
509
534
  const drawSnapshot = drawSnapshots[ordinal];
510
535
  draw.setUint32(
511
536
  drawOffset + offset(DRAW_TEMPLATE, 'pipelineClass'),
512
- drawSnapshot === undefined ? 0 : stableU32(drawSnapshot.pipelineClass),
537
+ drawSnapshot === undefined
538
+ ? 0
539
+ : stableU32(
540
+ drawSnapshot.prepared === undefined
541
+ ? drawSnapshot.pipelineClass
542
+ : `${drawSnapshot.prepared.identity.material}|${drawSnapshot.prepared.identity.geometry}|${drawSnapshot.prepared.identity.deformation}`,
543
+ ),
513
544
  true,
514
545
  );
515
546
  draw.setUint32(
@@ -519,17 +550,17 @@ export class GpuScene {
519
550
  );
520
551
  draw.setUint32(
521
552
  drawOffset + offset(DRAW_TEMPLATE, 'firstIndex'),
522
- drawSnapshot?.first ?? 0,
553
+ drawSnapshot?.prepared?.first ?? drawSnapshot?.first ?? 0,
523
554
  true,
524
555
  );
525
556
  draw.setUint32(
526
557
  drawOffset + offset(DRAW_TEMPLATE, 'indexCount'),
527
- drawSnapshot?.count ?? 0,
558
+ drawSnapshot?.prepared?.count ?? drawSnapshot?.count ?? 0,
528
559
  true,
529
560
  );
530
561
  draw.setInt32(
531
562
  drawOffset + offset(DRAW_TEMPLATE, 'baseVertex'),
532
- drawSnapshot?.baseVertex ?? 0,
563
+ drawSnapshot?.prepared?.baseVertex ?? drawSnapshot?.baseVertex ?? 0,
533
564
  true,
534
565
  );
535
566
  draw.setUint32(drawOffset + offset(DRAW_TEMPLATE, 'firstInstance'), 0, true);
@@ -591,16 +622,35 @@ export class GpuScene {
591
622
  }
592
623
  }
593
624
 
625
+ private writeRootTransform(
626
+ record: RenderSceneSlot,
627
+ resetPrevious: boolean,
628
+ writes: Record<GpuSceneTableName, number[]>,
629
+ ): void {
630
+ const allocation = this.allocations[record.slot];
631
+ if (allocation === undefined) throw new RangeError('GPU Scene allocation unavailable');
632
+ const transformOffset = allocation.transformStart * TRANSFORM.stride;
633
+ const currentOffset = transformOffset + offset(TRANSFORM, 'currentWorld');
634
+ const previousOffset = transformOffset + offset(TRANSFORM, 'previousWorld');
635
+ if (resetPrevious) {
636
+ writeMat4(this.transformView, previousOffset, record.snapshot.transform.world);
637
+ } else {
638
+ this.transformBytes.copyWithin(previousOffset, currentOffset, currentOffset + 64);
639
+ }
640
+ writeMat4(this.transformView, currentOffset, record.snapshot.transform.world);
641
+ writes.transform.push(allocation.transformStart);
642
+ }
643
+
594
644
  private clearSlot(slot: number, writes: Record<GpuSceneTableName, number[]>): void {
595
645
  for (const name of ['primitive'] as const) {
596
646
  const layout = TABLE_LAYOUTS[name];
597
647
  new Uint8Array(this.tableBytes[name], slot * layout.stride, layout.stride).fill(0);
598
648
  writes[name].push(slot);
599
649
  }
600
- const allocation = this.allocations.get(slot);
650
+ const allocation = this.allocations[slot];
601
651
  if (allocation === undefined) return;
602
652
  this.clearAllocation(allocation, writes);
603
- this.allocations.delete(slot);
653
+ this.allocations[slot] = undefined;
604
654
  }
605
655
 
606
656
  private uploadRows(
@@ -637,15 +687,18 @@ export class GpuScene {
637
687
  // empty: preserve zero so neither the GPU Scene nor the indirect topology
638
688
  // turns it into a synthetic identity instance. Entities without the
639
689
  // component retain the ordinary one-instance identity path.
690
+ const explicitInstances = record.snapshot.instances;
640
691
  const instanceCount =
641
- record.snapshot.instances === undefined
692
+ explicitInstances === undefined
642
693
  ? 1
643
- : Math.max(0, Math.floor(record.snapshot.instances.instanceCount));
694
+ : Math.max(0, Math.floor(explicitInstances.instanceCount));
695
+ const instanceTransformCount = explicitInstances === undefined ? 0 : instanceCount;
644
696
  const drawCount = Math.max(1, record.snapshot.gpuDrivenDraws?.length ?? 0);
645
697
  const materialCount = Math.max(1, record.snapshot.materials.length);
646
- const existing = this.allocations.get(record.slot);
698
+ const existing = this.allocations[record.slot];
647
699
  if (
648
700
  existing?.instanceCount === instanceCount &&
701
+ existing.instanceTransformCount === instanceTransformCount &&
649
702
  existing.drawCount === drawCount &&
650
703
  existing.materialCount === materialCount
651
704
  ) {
@@ -655,13 +708,16 @@ export class GpuScene {
655
708
  const allocation = {
656
709
  instanceStart: this.instances.allocate(instanceCount),
657
710
  instanceCount,
658
- transformStart: this.transforms.allocate(instanceCount + 1),
711
+ transformStart: this.transforms.allocate(1),
712
+ instanceTransformStart:
713
+ instanceTransformCount === 0 ? 0 : this.transforms.allocate(instanceTransformCount),
714
+ instanceTransformCount,
659
715
  drawStart: this.draws.allocate(drawCount),
660
716
  drawCount,
661
717
  materialStart: this.materials.allocate(materialCount),
662
718
  materialCount,
663
719
  };
664
- this.allocations.set(record.slot, allocation);
720
+ this.allocations[record.slot] = allocation;
665
721
  }
666
722
 
667
723
  private clearAllocation(
@@ -677,8 +733,9 @@ export class GpuScene {
677
733
  ).fill(0);
678
734
  writes.instance.push(instanceIndex);
679
735
  }
680
- for (let ordinal = 0; ordinal <= allocation.instanceCount; ordinal += 1) {
681
- const transformIndex = allocation.transformStart + ordinal;
736
+ for (let ordinal = -1; ordinal < allocation.instanceTransformCount; ordinal += 1) {
737
+ const transformIndex =
738
+ ordinal < 0 ? allocation.transformStart : allocation.instanceTransformStart + ordinal;
682
739
  new Uint8Array(
683
740
  this.tableBytes.transform,
684
741
  transformIndex * TRANSFORM.stride,
@@ -705,7 +762,8 @@ export class GpuScene {
705
762
  writes.material.push(materialIndex);
706
763
  }
707
764
  this.instances.release(allocation.instanceStart, allocation.instanceCount);
708
- this.transforms.release(allocation.transformStart, allocation.instanceCount + 1);
765
+ this.transforms.release(allocation.transformStart, 1);
766
+ this.transforms.release(allocation.instanceTransformStart, allocation.instanceTransformCount);
709
767
  this.draws.release(allocation.drawStart, allocation.drawCount);
710
768
  this.materials.release(allocation.materialStart, allocation.materialCount);
711
769
  }
@@ -731,6 +789,7 @@ export class GpuScene {
731
789
  for (const buffer of Object.values(this.buffers)) this.device.destroyBuffer(buffer);
732
790
  this.buffers = nextBuffers.value;
733
791
  this.tableBytes = nextTables;
792
+ this.refreshTransformViews();
734
793
  this.capacity = nextCapacity;
735
794
  this.capacityGrows += 1;
736
795
  this.uploadRanges += TABLE_NAMES.length;
@@ -750,4 +809,14 @@ export class GpuScene {
750
809
  material: new ArrayBuffer(capacity * MATERIAL.stride),
751
810
  };
752
811
  }
812
+
813
+ private refreshTransformViews(): void {
814
+ this.transformBytes = new Uint8Array(this.tableBytes.transform);
815
+ this.transformView = new DataView(this.tableBytes.transform);
816
+ }
817
+
818
+ private writeIdentityTransform(): void {
819
+ writeMat4(this.transformView, offset(TRANSFORM, 'currentWorld'), IDENTITY_MATRIX);
820
+ writeMat4(this.transformView, offset(TRANSFORM, 'previousWorld'), IDENTITY_MATRIX);
821
+ }
753
822
  }
package/src/gpu-usage.ts CHANGED
@@ -12,5 +12,4 @@ export const GPU_BUFFER_USAGE_UNIFORM = 0x40;
12
12
  export const GPU_BUFFER_USAGE_STORAGE = 0x80;
13
13
  export const GPU_BUFFER_USAGE_INDIRECT = 0x100;
14
14
  export const GPU_BUFFER_USAGE_MAP_READ = 0x01;
15
- /** GPUBufferUsage.QUERY_RESOLVE, used by optional timestamp captures. */
16
15
  export const GPU_BUFFER_USAGE_QUERY_RESOLVE = 0x200;
@@ -19,7 +19,7 @@
19
19
  // usage owner; this module stays decoupled from renderer bootstrap.
20
20
  //
21
21
  // Sizes:
22
- // - light_data : 256 x 64 B = 16 384 B
22
+ // - light_data : 256 x 80 B = 20 480 B
23
23
  // - cluster_grid : maxGridCells x 8 B = 64 x 64 x 64 x 8 B = 2 097 152 B max
24
24
  // (plan D-grid: x,y,z each in [1..64]; maxCells=262144;
25
25
  // stride 2 u32 = 8B; we allocate at the install-time
@@ -47,7 +47,7 @@ import {
47
47
  GPU_BUFFER_USAGE_STORAGE,
48
48
  GPU_BUFFER_USAGE_UNIFORM,
49
49
  } from './gpu-usage';
50
- import { BYTES_PER_LIGHT_SLOT } from './light-buffer-layout';
50
+ import { BYTES_PER_DIRECT_LIGHT_SLOT } from './light-buffer-layout';
51
51
  import { createPbrSkinMeshBindGroupEntries } from './pbr-pipeline';
52
52
  import {
53
53
  CLUSTER_GRID_STRIDE_U32,
@@ -95,8 +95,8 @@ export function createHdrpClusterMembershipBindGroupLayoutDescriptor(): BindGrou
95
95
  * The persistent HDRP GPU buffers (plan D-1, BGL slot 3..6) plus the unified
96
96
  * BGL layout for group(2) (plan D-6, feat-20260609-hdrp-cluster-fragment-ggx M3).
97
97
  *
98
- * AC-11: light_data stride = `BYTES_PER_LIGHT_SLOT` = 64 (double-sided lock with
99
- * WGSL hdrp-cluster-forward.wgsl LightSlot).
98
+ * AC-11: light_data stride = `BYTES_PER_DIRECT_LIGHT_SLOT` = 80 (double-sided
99
+ * lock with WGSL hdrp-cluster-forward.wgsl DirectLightSlot).
100
100
  * AC-13: 4 distinct RHI Buffer handles, ready for slot-3..6 BGL binding.
101
101
  * AC-14: clusterUniform is a uniform buffer (not storage); runtime grid change
102
102
  * is a writeBuffer field update, not a PSO rebuild.
@@ -106,7 +106,7 @@ export function createHdrpClusterMembershipBindGroupLayoutDescriptor(): BindGrou
106
106
  export interface HdrpBuffers {
107
107
  /** Device identity that owns every handle in this bundle. */
108
108
  readonly device: RenderSystemRuntime['device'];
109
- /** light_data -- the full 256 x 64 B Standard light budget. */
109
+ /** light_data -- the full 256 x 80 B DirectLightSlot budget. */
110
110
  readonly lightDataBuffer: Buffer;
111
111
  readonly lightDataBytes: number;
112
112
  /** cluster_grid SSBO -- gridX*gridY*gridZ * 2 u32, BGL slot 4. */
@@ -175,7 +175,7 @@ export function getOrCreateHdrpBuffers(
175
175
  }
176
176
  const device = runtime.device;
177
177
  const clusterUniformBytes = 32;
178
- const lightDataBytes = MAX_LIGHTS * BYTES_PER_LIGHT_SLOT;
178
+ const lightDataBytes = MAX_LIGHTS * BYTES_PER_DIRECT_LIGHT_SLOT;
179
179
  const clusterCells = grid.x * grid.y * grid.z;
180
180
  const clusterGridBytes = clusterCells * CLUSTER_GRID_STRIDE_U32 * 4;
181
181
  const lightIndexListBytes = LIGHT_INDEX_LIST_CAPACITY * 4;
package/src/index.ts CHANGED
@@ -65,6 +65,8 @@ export * from './components/directional-light';
65
65
  export { Fog } from './components/fog';
66
66
  export { Instances, type InstancesData } from './components/instances';
67
67
  export { Layer } from './components/layer';
68
+ export * from './components/light-helpers';
69
+ export { LightProbe } from './components/light-probe';
68
70
  export { Lines } from './components/lines';
69
71
  export * from './components/mesh-filter';
70
72
  export * from './components/mesh-renderer';
@@ -78,6 +80,7 @@ export {
78
80
  pointShapeFromU32,
79
81
  } from './components/points';
80
82
  export { PostProcessParams } from './components/post-process-params';
83
+ export { RectAreaLight } from './components/rect-area-light';
81
84
  export {
82
85
  REFLECTION_PROBE_UPDATE_CONTINUOUS,
83
86
  REFLECTION_PROBE_UPDATE_ON_CHANGE,
@@ -180,8 +183,15 @@ export {
180
183
  } from './ibl/kernel-cache';
181
184
  export type {
182
185
  BloomInspection,
186
+ LightInspection,
187
+ LodOcclusionInspection,
183
188
  MotionBlurInspection,
184
189
  MotionBlurInspectionStatus,
190
+ ReflectionFallbackFailureStage,
191
+ ReflectionFallbackInspection,
192
+ ReflectionFallbackReadbackReceipt,
193
+ ReflectionFallbackReceipt,
194
+ ReflectionFallbackRecoveryAction,
185
195
  ReflectionProbeInspection,
186
196
  ReflectionProbeSelectionInspection,
187
197
  TransmissionInspection,
@@ -268,6 +278,10 @@ export {
268
278
  type ReflectionProbeTableRow,
269
279
  reflectionProbeTableBytes,
270
280
  } from './reflection/gpu-table';
281
+ export {
282
+ inspectReflectionFallback,
283
+ type ReflectionFallbackFailureInput,
284
+ } from './reflection/inspection';
271
285
  export {
272
286
  admitReflectionProbe,
273
287
  DEFAULT_REFLECTION_PROBE_LIMITS,
@@ -306,11 +320,71 @@ export type {
306
320
  TemporalInspectionInput,
307
321
  TemporalInspectionStatus,
308
322
  } from './renderer-inspect';
323
+ export type {
324
+ GpuFrameTiming,
325
+ GpuFrameTimingProtocol,
326
+ GpuFrameTimingRecord,
327
+ GpuFrameTimingSample,
328
+ GpuFrameTimingSummary,
329
+ } from './scene/visibility/gpu-frame-timing';
330
+ export {
331
+ createGpuFrameTiming,
332
+ recordGpuFrameTiming,
333
+ summarizeGpuFrameTiming,
334
+ } from './scene/visibility/gpu-frame-timing';
335
+ export type {
336
+ LodOcclusionDegradation,
337
+ LodOcclusionFallback,
338
+ LodOcclusionInspectionAction,
339
+ LodOcclusionInspectionBudget,
340
+ LodOcclusionInspectionError,
341
+ LodOcclusionInspectionInput,
342
+ LodOcclusionInspectionRow,
343
+ LodOcclusionInspectionSample,
344
+ LodOcclusionInspectionSubmit,
345
+ LodOcclusionWorldAttribution,
346
+ LodOcclusionWorldInspection,
347
+ LodOcclusionWorldInspectionInput,
348
+ } from './scene/visibility/inspection';
349
+ export {
350
+ consumeLodOcclusionInspection,
351
+ inspectLodOcclusion,
352
+ LOD_OCCLUSION_INSPECTION_MAX_BYTES,
353
+ LOD_OCCLUSION_INSPECTION_SCHEMA,
354
+ serializeLodOcclusionInspection,
355
+ } from './scene/visibility/inspection';
309
356
  export {
310
357
  SHADOW_ATLAS_DEFAULT_FACE_SIZE,
311
358
  SHADOW_ATLAS_DEFAULT_LAYERS,
312
359
  ShadowAtlas,
313
360
  } from './shadow-atlas';
361
+ export type {
362
+ SsrAdmissionBudget,
363
+ SsrAdmissionFailure,
364
+ SsrAdmissionIdentity,
365
+ SsrAdmissionInput,
366
+ SsrAdmissionResult,
367
+ SsrAdmissionWork,
368
+ SsrDependenciesInspection,
369
+ SsrFormatReceipt,
370
+ SsrReflectionFallbackReceipt,
371
+ SsrTemporalReceipt,
372
+ } from './ssr/admission';
373
+ export {
374
+ admitSsrM0,
375
+ projectSsrDependencies,
376
+ resolveSsrAdmissionGeneration,
377
+ SSR_FORMAT_PROFILE,
378
+ SSR_FORMAT_STAGES,
379
+ zeroSsrAdmissionWork,
380
+ } from './ssr/admission';
381
+ export {
382
+ composeSsrReflection,
383
+ type SsrCompositionInput,
384
+ type SsrCompositionInputError,
385
+ type SsrCompositionResult,
386
+ type SsrReflectionColor,
387
+ } from './ssr/composition';
314
388
  export type {
315
389
  RenderTarget,
316
390
  RenderTargetAdmissionLimits,