@forgeax/engine-render 0.1.4 → 0.1.7

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 (979) hide show
  1. package/README.md +268 -640
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts +2 -0
  4. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts +2 -0
  6. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts +2 -0
  8. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -1
  10. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +6 -0
  11. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -1
  12. package/dist/{gpu-driven/view-reference.d.ts → __tests__/gpu-driven-view-reference.d.ts} +4 -4
  13. package/dist/__tests__/gpu-driven-view-reference.d.ts.map +1 -0
  14. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -1
  15. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts +2 -0
  16. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts.map +1 -0
  17. package/dist/__tests__/morph-feature-plan.unit.test.d.ts +2 -0
  18. package/dist/__tests__/morph-feature-plan.unit.test.d.ts.map +1 -0
  19. package/dist/__tests__/render-feature-plan.test-d.d.ts +2 -0
  20. package/dist/__tests__/render-feature-plan.test-d.d.ts.map +1 -0
  21. package/dist/__tests__/render-feature-plan.unit.test.d.ts +2 -0
  22. package/dist/__tests__/render-feature-plan.unit.test.d.ts.map +1 -0
  23. package/dist/__tests__/ssao-config.unit.test.d.ts +2 -0
  24. package/dist/__tests__/ssao-config.unit.test.d.ts.map +1 -0
  25. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts +2 -0
  26. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts.map +1 -0
  27. package/dist/__tests__/standard-descriptors.test-d.d.ts +2 -0
  28. package/dist/__tests__/standard-descriptors.test-d.d.ts.map +1 -0
  29. package/dist/__tests__/standard-pipeline.dawn.test.d.ts +2 -0
  30. package/dist/__tests__/standard-pipeline.dawn.test.d.ts.map +1 -0
  31. package/dist/__tests__/standard-pipeline.integration.test.d.ts +2 -0
  32. package/dist/__tests__/standard-pipeline.integration.test.d.ts.map +1 -0
  33. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts +2 -0
  34. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts +2 -0
  36. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts.map +1 -0
  37. package/dist/{renderer/backend-selection.d.ts → assembly/backend-contract.d.ts} +15 -4
  38. package/dist/assembly/backend-contract.d.ts.map +1 -0
  39. package/dist/assembly/factory.d.ts +214 -0
  40. package/dist/assembly/factory.d.ts.map +1 -0
  41. package/dist/assembly/host-contract.d.ts +84 -0
  42. package/dist/assembly/host-contract.d.ts.map +1 -0
  43. package/dist/{renderer → assembly}/material/assembly.d.ts +0 -1
  44. package/dist/{renderer → assembly}/material/assembly.d.ts.map +1 -1
  45. package/dist/assembly/material/pipeline-projection.d.ts +30 -0
  46. package/dist/assembly/material/pipeline-projection.d.ts.map +1 -0
  47. package/dist/authoring.d.ts +11 -11
  48. package/dist/authoring.d.ts.map +1 -1
  49. package/dist/authoring.mjs +25 -3
  50. package/dist/authoring.mjs.map +1 -1
  51. package/dist/chunk-CQXZC5XI.mjs +182 -0
  52. package/dist/chunk-CQXZC5XI.mjs.map +1 -0
  53. package/dist/chunk-HCOGPHKS.mjs +93 -0
  54. package/dist/chunk-HCOGPHKS.mjs.map +1 -0
  55. package/dist/chunk-YEJIUW7D.mjs +1152 -0
  56. package/dist/chunk-YEJIUW7D.mjs.map +1 -0
  57. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts +2 -0
  58. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts.map +1 -0
  59. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts +2 -0
  60. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts.map +1 -0
  61. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  62. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  63. package/dist/components/glyph-text.d.ts +1 -1
  64. package/dist/components/glyph-text.d.ts.map +1 -1
  65. package/dist/components/index.d.ts +4 -2
  66. package/dist/components/index.d.ts.map +1 -1
  67. package/dist/components/instances.d.ts +1 -1
  68. package/dist/components/instances.d.ts.map +1 -1
  69. package/dist/components/light-helpers.d.ts +1 -1
  70. package/dist/components/light-helpers.d.ts.map +1 -1
  71. package/dist/components/lines.d.ts +5 -0
  72. package/dist/components/lines.d.ts.map +1 -0
  73. package/dist/components/mesh-filter.d.ts +7 -7
  74. package/dist/components/mesh-filter.d.ts.map +1 -1
  75. package/dist/components/points.d.ts +15 -0
  76. package/dist/components/points.d.ts.map +1 -0
  77. package/dist/components/scene-instance.d.ts +11 -11
  78. package/dist/components/skybox-background.d.ts +56 -0
  79. package/dist/components/skybox-background.d.ts.map +1 -0
  80. package/dist/components/skylight.d.ts +55 -0
  81. package/dist/components/skylight.d.ts.map +1 -0
  82. package/dist/components/sprite-animation.d.ts +2 -3
  83. package/dist/components/sprite-animation.d.ts.map +1 -1
  84. package/dist/components/sprite-instances.d.ts +1 -1
  85. package/dist/components/sprite-playback-mode.d.ts +6 -1
  86. package/dist/components/sprite-playback-mode.d.ts.map +1 -1
  87. package/dist/components/sprite-region-override.d.ts +2 -3
  88. package/dist/components/sprite-region-override.d.ts.map +1 -1
  89. package/dist/components/tile-layer.d.ts +5 -0
  90. package/dist/components/tile-layer.d.ts.map +1 -1
  91. package/dist/construct-renderer.d.ts +18 -1
  92. package/dist/construct-renderer.d.ts.map +1 -1
  93. package/dist/construct-renderer.mjs +27463 -4
  94. package/dist/construct-renderer.mjs.map +1 -1
  95. package/dist/debug-draw-glue.d.ts +2 -53
  96. package/dist/debug-draw-glue.d.ts.map +1 -1
  97. package/dist/device/device-scope.d.ts +83 -0
  98. package/dist/device/device-scope.d.ts.map +1 -0
  99. package/dist/{gpu-resource-store.d.ts → device/gpu-residency.d.ts} +91 -48
  100. package/dist/device/gpu-residency.d.ts.map +1 -0
  101. package/dist/device/resource-types.d.ts +8 -0
  102. package/dist/device/resource-types.d.ts.map +1 -0
  103. package/dist/engine-metrics.d.ts +2 -2
  104. package/dist/engine-metrics.d.ts.map +1 -1
  105. package/dist/errors/recover.d.ts +28 -1
  106. package/dist/errors/recover.d.ts.map +1 -1
  107. package/dist/errors/render.d.ts +320 -248
  108. package/dist/errors/render.d.ts.map +1 -1
  109. package/dist/features/fullscreen.d.ts +19 -0
  110. package/dist/features/fullscreen.d.ts.map +1 -0
  111. package/dist/features/host.d.ts +32 -26
  112. package/dist/features/host.d.ts.map +1 -1
  113. package/dist/features/morph/morph-feature.d.ts +39 -5
  114. package/dist/features/morph/morph-feature.d.ts.map +1 -1
  115. package/dist/features/plan.d.ts +182 -0
  116. package/dist/features/plan.d.ts.map +1 -0
  117. package/dist/features/prepared-gpu-work.d.ts +21 -17
  118. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  119. package/dist/features/prepared-graphics-store.d.ts +2 -1
  120. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  121. package/dist/features/prepared-graphics.d.ts +11 -21
  122. package/dist/features/prepared-graphics.d.ts.map +1 -1
  123. package/dist/features/render-graph-compute.d.ts +2 -2
  124. package/dist/features/render-graph-compute.d.ts.map +1 -1
  125. package/dist/features/render-graph-contribution.d.ts +4 -7
  126. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  127. package/dist/features/render-graph-raster.d.ts +7 -3
  128. package/dist/features/render-graph-raster.d.ts.map +1 -1
  129. package/dist/features/render-graph-resources.d.ts +6 -6
  130. package/dist/features/render-graph-resources.d.ts.map +1 -1
  131. package/dist/features/targets.d.ts +5 -5
  132. package/dist/features/targets.d.ts.map +1 -1
  133. package/dist/features/types.d.ts +11 -190
  134. package/dist/features/types.d.ts.map +1 -1
  135. package/dist/features/vocabulary.d.ts +14 -0
  136. package/dist/features/vocabulary.d.ts.map +1 -0
  137. package/dist/fullscreen-post-process-pass.d.ts +4 -25
  138. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  139. package/dist/glyph-text-layout-system.d.ts +3 -2
  140. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  141. package/dist/gpu-driven/batch-topology.d.ts +6 -75
  142. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  143. package/dist/gpu-driven/production-raster.d.ts +13 -112
  144. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  145. package/dist/gpu-driven/view-gpu.d.ts +10 -66
  146. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  147. package/dist/gpu-resource.d.ts +3 -3
  148. package/dist/gpu-scene-schema.d.ts +1 -94
  149. package/dist/gpu-scene-schema.d.ts.map +1 -1
  150. package/dist/gpu-scene.d.ts +7 -33
  151. package/dist/gpu-scene.d.ts.map +1 -1
  152. package/dist/hdrp-buffers.d.ts +3 -53
  153. package/dist/hdrp-buffers.d.ts.map +1 -1
  154. package/dist/ibl/IblPipelineCache.d.ts +74 -180
  155. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  156. package/dist/ibl/skylight-bind-group.d.ts +1 -1
  157. package/dist/index.d.ts +17 -43
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.mjs +167 -3
  160. package/dist/index.mjs.map +1 -1
  161. package/dist/inspection-types.d.ts +72 -0
  162. package/dist/inspection-types.d.ts.map +1 -0
  163. package/dist/instance-buffer-cache.d.ts +1 -4
  164. package/dist/instance-buffer-cache.d.ts.map +1 -1
  165. package/dist/internal.d.ts +1 -73
  166. package/dist/internal.d.ts.map +1 -1
  167. package/dist/internal.mjs +1 -43
  168. package/dist/internal.mjs.map +1 -1
  169. package/dist/lifecycle.d.ts +36 -2
  170. package/dist/lifecycle.d.ts.map +1 -1
  171. package/dist/materials.d.ts +0 -3
  172. package/dist/materials.d.ts.map +1 -1
  173. package/dist/mesh-material-bindings.d.ts +0 -1
  174. package/dist/mesh-material-bindings.d.ts.map +1 -1
  175. package/dist/pbr-pipeline.d.ts +77 -29
  176. package/dist/pbr-pipeline.d.ts.map +1 -1
  177. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  178. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  179. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  180. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  181. package/dist/pipeline/standard-profile.d.ts +40 -0
  182. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  183. package/dist/pipeline-builder.d.ts +3 -3
  184. package/dist/pipeline-builder.d.ts.map +1 -1
  185. package/dist/pipeline-spec-types.d.ts +24 -0
  186. package/dist/pipeline-spec-types.d.ts.map +1 -0
  187. package/dist/pipeline-spec.d.ts +16 -155
  188. package/dist/pipeline-spec.d.ts.map +1 -1
  189. package/dist/plugin.d.ts +1 -14
  190. package/dist/plugin.d.ts.map +1 -1
  191. package/dist/points-lines/__tests__/bounds.unit.test.d.ts +2 -0
  192. package/dist/points-lines/__tests__/bounds.unit.test.d.ts.map +1 -0
  193. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts +2 -0
  194. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts.map +1 -0
  195. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts +2 -0
  196. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts.map +1 -0
  197. package/dist/points-lines/__tests__/inspection.unit.test.d.ts +2 -0
  198. package/dist/points-lines/__tests__/inspection.unit.test.d.ts.map +1 -0
  199. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts +2 -0
  200. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts.map +1 -0
  201. package/dist/points-lines/__tests__/points-lines.bench.d.ts +2 -0
  202. package/dist/points-lines/__tests__/points-lines.bench.d.ts.map +1 -0
  203. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts +2 -0
  204. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts.map +1 -0
  205. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts +2 -0
  206. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts.map +1 -0
  207. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts +2 -0
  208. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts.map +1 -0
  209. package/dist/points-lines/admission.d.ts +36 -0
  210. package/dist/points-lines/admission.d.ts.map +1 -0
  211. package/dist/points-lines/bounds.d.ts +8 -0
  212. package/dist/points-lines/bounds.d.ts.map +1 -0
  213. package/dist/points-lines/expansion-cache.d.ts +28 -0
  214. package/dist/points-lines/expansion-cache.d.ts.map +1 -0
  215. package/dist/points-lines/inspection.d.ts +53 -0
  216. package/dist/points-lines/inspection.d.ts.map +1 -0
  217. package/dist/points-lines/prepare.d.ts +67 -0
  218. package/dist/points-lines/prepare.d.ts.map +1 -0
  219. package/dist/points-lines/record.d.ts +60 -0
  220. package/dist/points-lines/record.d.ts.map +1 -0
  221. package/dist/points-lines/snapshot.d.ts +49 -0
  222. package/dist/points-lines/snapshot.d.ts.map +1 -0
  223. package/dist/post-process-errors.d.ts +18 -18
  224. package/dist/post-process-errors.d.ts.map +1 -1
  225. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -5
  226. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  227. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  228. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  229. package/dist/record/frame-lighting.d.ts +7 -73
  230. package/dist/record/frame-lighting.d.ts.map +1 -1
  231. package/dist/record/frame-snapshot.d.ts +44 -44
  232. package/dist/record/frame-snapshot.d.ts.map +1 -1
  233. package/dist/record/frame-targets.d.ts +5 -38
  234. package/dist/record/frame-targets.d.ts.map +1 -1
  235. package/dist/record/frame.d.ts +64 -52
  236. package/dist/record/frame.d.ts.map +1 -1
  237. package/dist/record/helpers.d.ts +3 -2
  238. package/dist/record/helpers.d.ts.map +1 -1
  239. package/dist/record/main-pass-geometry.d.ts +12 -4
  240. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  241. package/dist/record/main-pass-material.d.ts +90 -59
  242. package/dist/record/main-pass-material.d.ts.map +1 -1
  243. package/dist/record/main-pass-sprite-draws.d.ts +28 -3
  244. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  245. package/dist/record/main-pass.d.ts +1 -1
  246. package/dist/record/main-pass.d.ts.map +1 -1
  247. package/dist/record/mesh-ssbo.d.ts +276 -3
  248. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  249. package/dist/record/render-context.d.ts +252 -0
  250. package/dist/record/render-context.d.ts.map +1 -0
  251. package/dist/record/shadow-pass.d.ts +15 -88
  252. package/dist/record/shadow-pass.d.ts.map +1 -1
  253. package/dist/record/skybox-post-pass.d.ts +1 -1
  254. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  255. package/dist/record/typed-frame-graph.d.ts +29 -7
  256. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  257. package/dist/record/view-ubo.d.ts +9 -3
  258. package/dist/record/view-ubo.d.ts.map +1 -1
  259. package/dist/render-contract.d.ts +424 -0
  260. package/dist/render-contract.d.ts.map +1 -0
  261. package/dist/render-data.d.ts.map +1 -1
  262. package/dist/render-graph-primitives.d.ts +14 -362
  263. package/dist/render-graph-primitives.d.ts.map +1 -1
  264. package/dist/render-pipeline.d.ts +25 -64
  265. package/dist/render-pipeline.d.ts.map +1 -1
  266. package/dist/render-system-extract.d.ts +110 -338
  267. package/dist/render-system-extract.d.ts.map +1 -1
  268. package/dist/render-system.d.ts +24 -713
  269. package/dist/render-system.d.ts.map +1 -1
  270. package/dist/scene/render-scene-types.d.ts +61 -0
  271. package/dist/scene/render-scene-types.d.ts.map +1 -0
  272. package/dist/scene/render-scene.d.ts +112 -0
  273. package/dist/scene/render-scene.d.ts.map +1 -0
  274. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +2 -5
  275. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -1
  276. package/dist/ssao-buffers.d.ts +22 -3
  277. package/dist/ssao-buffers.d.ts.map +1 -1
  278. package/dist/systems/skin-palette-allocator.d.ts +2 -4
  279. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  280. package/dist/systems/skin-palette-types.d.ts +14 -0
  281. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  282. package/dist/systems/transparent-sort-config.d.ts +23 -2
  283. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  284. package/dist/tilemap-chunk-extract-system.d.ts +4 -3
  285. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -1
  286. package/dist/typed-render-graph-primitives.d.ts +2 -4
  287. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  288. package/dist/typed-shadow-passes.d.ts +3 -3
  289. package/dist/typed-shadow-passes.d.ts.map +1 -1
  290. package/package.json +23 -23
  291. package/src/__tests__/authoring-path.unit.test.ts +9 -0
  292. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +1 -1
  293. package/src/__tests__/callback-inference.test-d.ts +6 -3
  294. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -4
  295. package/src/__tests__/construct-renderer-identity.unit.test.ts +15 -2
  296. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  297. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  298. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +8 -19
  299. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -13
  300. package/src/__tests__/factory-contract.integration.test.ts +158 -209
  301. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +1 -4
  302. package/src/__tests__/frame-observation.contract.test.ts +17 -8
  303. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  304. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +6 -11
  305. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +21 -18
  306. package/src/__tests__/gpu-driven-production.integration.test.ts +32 -205
  307. package/src/__tests__/gpu-driven-scaling.unit.test.ts +4 -7
  308. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +87 -8
  309. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +170 -8
  310. package/src/{gpu-driven/view-reference.ts → __tests__/gpu-driven-view-reference.ts} +4 -3
  311. package/src/__tests__/gpu-driven-view.browser.test.ts +12 -1
  312. package/src/__tests__/gpu-driven-view.dawn.test.ts +12 -1
  313. package/src/__tests__/gpu-driven-view.unit.test.ts +11 -267
  314. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +3 -3
  315. package/src/__tests__/gpu-scene-render-graph-gpu.ts +2 -3
  316. package/src/__tests__/gpu-scene.dawn.test.ts +2 -6
  317. package/src/__tests__/gpu-scene.unit.test.ts +10 -24
  318. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  319. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +34 -66
  320. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -5
  321. package/src/__tests__/light-buffer-layout.unit.test.ts +4 -49
  322. package/src/__tests__/material-cooked-projection.unit.test.ts +31 -58
  323. package/src/__tests__/material-snapshot-mutation.integration.test.ts +10 -15
  324. package/src/__tests__/material-static-dynamic-route.unit.test.ts +31 -50
  325. package/src/__tests__/material-stride-surface.unit.test.ts +2 -2
  326. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +7 -8
  327. package/src/__tests__/morph-culling-reentry.dawn.test.ts +29 -38
  328. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +45 -43
  329. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  330. package/src/__tests__/morph-visual-evidence.integration.test.ts +47 -33
  331. package/src/__tests__/nineslice-handle-surface.unit.test.ts +11 -6
  332. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -13
  333. package/src/__tests__/prepared-graphics-capability.unit.test.ts +6 -81
  334. package/src/__tests__/prepared-graphics-generation.unit.test.ts +3 -17
  335. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +6 -74
  336. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +1 -3
  337. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +2 -2
  338. package/src/__tests__/profiler-default-off.test.ts +1 -1
  339. package/src/__tests__/profiler-phase-catalog.test.ts +2 -2
  340. package/src/__tests__/profiler-phase-integration.test.ts +5 -13
  341. package/src/__tests__/profiler-phase-token.test.ts +3 -8
  342. package/src/__tests__/public-surface.test-d.ts +65 -3
  343. package/src/__tests__/recover-error-policy-owner.unit.test.ts +1 -21
  344. package/src/__tests__/render-error-code-owner.test-d.ts +24 -23
  345. package/src/__tests__/render-error-detail-ssot.test-d.ts +0 -95
  346. package/src/__tests__/render-error-exhaustive.test-d.ts +27 -1
  347. package/src/__tests__/render-feature-assembly.test-d.ts +8 -16
  348. package/src/__tests__/render-feature-context.test-d.ts +16 -40
  349. package/src/__tests__/render-feature-contract.test-d.ts +9 -18
  350. package/src/__tests__/render-feature-diagnostics.unit.test.ts +6 -8
  351. package/src/__tests__/render-feature-docs.unit.test.ts +8 -7
  352. package/src/__tests__/render-feature-gpu-work.integration.test.ts +14 -75
  353. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  354. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  355. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +8 -19
  356. package/src/__tests__/render-feature-prepared-errors.test-d.ts +3 -6
  357. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +10 -71
  358. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +11 -61
  359. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +20 -43
  360. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +56 -78
  361. package/src/__tests__/render-feature-public-surface.test-d.ts +6 -24
  362. package/src/__tests__/render-feature-retry.unit.test.ts +7 -48
  363. package/src/__tests__/render-feature-scheduling.unit.test.ts +15 -27
  364. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +0 -9
  365. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +19 -109
  366. package/src/__tests__/render-feature-visibility-context.test-d.ts +1 -6
  367. package/src/__tests__/render-feature-visibility-context.unit.test.ts +1 -2
  368. package/src/__tests__/render-feature-zero-work.unit.test.ts +14 -20
  369. package/src/__tests__/render-scene-projection.unit.test.ts +73 -111
  370. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +82 -95
  371. package/src/__tests__/renderer-lifecycle.integration.test.ts +49 -1
  372. package/src/__tests__/shader-stage-surface.unit.test.ts +14 -9
  373. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  374. package/src/__tests__/ssao-kernel-surface.unit.test.ts +4 -5
  375. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  376. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  377. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  378. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  379. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  380. package/src/__tests__/surface-configuration.unit.test.ts +1 -2
  381. package/src/__tests__/texture-usage-surface.unit.test.ts +3 -6
  382. package/src/__tests__/typed-pipeline-topology.unit.test.ts +40 -206
  383. package/src/__tests__/urp-pipeline-targets.unit.test.ts +1 -11
  384. package/src/__tests__/urp-pipeline.unit.test.ts +2 -2
  385. package/src/__tests__/vertex-color-pipeline.unit.test.ts +10 -2
  386. package/src/__tests__/vertex-layout-consumer.unit.test.ts +1 -1
  387. package/src/__tests__/visibility-diagnostics.integration.test.ts +7 -11
  388. package/src/__tests__/visibility-extract.integration.test.ts +20 -11
  389. package/src/__tests__/visibility-extract.perf.test.ts +66 -32
  390. package/src/__tests__/visibility-feature-dedup.integration.test.ts +2 -4
  391. package/src/__tests__/visibility-hidden-report.unit.test.ts +1 -2
  392. package/src/__tests__/visibility-instances.integration.test.ts +7 -11
  393. package/src/__tests__/visibility-multi-world.integration.test.ts +38 -6
  394. package/src/__tests__/visibility-producer-matrix.integration.test.ts +18 -41
  395. package/src/__tests__/visibility-public-surface.test-d.ts +10 -9
  396. package/src/__tests__/visibility-resolver.unit.test.ts +2 -1
  397. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  398. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +2 -1
  399. package/src/__tests__/vocabulary.unit.test.ts +1 -1
  400. package/src/assembly/backend-contract.ts +57 -0
  401. package/src/{renderer/renderer-factory.ts → assembly/factory.ts} +1741 -2699
  402. package/src/assembly/host-contract.ts +101 -0
  403. package/src/{renderer → assembly}/material/assembly.ts +2 -7
  404. package/src/assembly/material/pipeline-projection.ts +63 -0
  405. package/src/authoring.ts +15 -22
  406. package/src/components/__tests__/points-lines-admission.unit.test.ts +219 -0
  407. package/src/components/__tests__/points-lines-schema.unit.test.ts +56 -0
  408. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  409. package/src/components/glyph-text.ts +3 -2
  410. package/src/components/index.ts +14 -9
  411. package/src/components/instances.ts +4 -5
  412. package/src/components/light-helpers.ts +1 -1
  413. package/src/components/lines.ts +18 -0
  414. package/src/components/mesh-filter.ts +11 -10
  415. package/src/components/points.ts +40 -0
  416. package/src/components/post-process-params.ts +3 -3
  417. package/src/components/scene-instance.ts +12 -12
  418. package/src/components/skybox-background.ts +103 -0
  419. package/src/components/{environment.ts → skylight.ts} +2 -110
  420. package/src/components/sprite-animation.ts +3 -4
  421. package/src/components/sprite-instances.ts +2 -2
  422. package/src/components/sprite-playback-mode.ts +7 -1
  423. package/src/components/sprite-region-override.ts +2 -3
  424. package/src/components/tile-layer.ts +8 -2
  425. package/src/construct-renderer.ts +67 -4
  426. package/src/debug-draw-glue.ts +8 -129
  427. package/src/device/device-scope.ts +306 -0
  428. package/src/{gpu-resource-store.ts → device/gpu-residency.ts} +540 -639
  429. package/src/device/resource-types.ts +20 -0
  430. package/src/engine-metrics.ts +12 -19
  431. package/src/errors/recover.ts +45 -3
  432. package/src/errors/render.ts +469 -429
  433. package/src/features/fullscreen.ts +46 -0
  434. package/src/features/host.ts +575 -309
  435. package/src/features/morph/morph-feature.ts +195 -105
  436. package/src/features/plan.ts +447 -0
  437. package/src/features/prepared-gpu-work.ts +72 -15
  438. package/src/features/prepared-graphics-store.ts +20 -6
  439. package/src/features/prepared-graphics.ts +12 -71
  440. package/src/features/render-graph-compute.ts +14 -5
  441. package/src/features/render-graph-contribution.ts +43 -63
  442. package/src/features/render-graph-raster.ts +32 -8
  443. package/src/features/render-graph-resources.ts +25 -23
  444. package/src/features/targets.ts +8 -21
  445. package/src/features/types.ts +39 -227
  446. package/src/features/vocabulary.ts +24 -0
  447. package/src/fullscreen-post-process-pass.ts +14 -57
  448. package/src/glyph-text-layout-system.ts +70 -96
  449. package/src/gpu-driven/batch-topology.ts +24 -202
  450. package/src/gpu-driven/production-raster.ts +99 -1109
  451. package/src/gpu-driven/view-gpu.ts +46 -192
  452. package/src/gpu-resource.ts +4 -4
  453. package/src/gpu-scene-schema.ts +11 -99
  454. package/src/gpu-scene.ts +231 -364
  455. package/src/hdrp-buffers.ts +12 -221
  456. package/src/ibl/IblPipelineCache.ts +471 -711
  457. package/src/ibl/skylight-bind-group.ts +4 -4
  458. package/src/index.ts +75 -217
  459. package/src/inspection-types.ts +80 -0
  460. package/src/instance-buffer-cache.ts +1 -29
  461. package/src/internal.ts +6 -85
  462. package/src/lifecycle.ts +64 -19
  463. package/src/materials.ts +7 -29
  464. package/src/mesh-material-bindings.ts +0 -1
  465. package/src/pbr-pipeline.ts +441 -53
  466. package/src/{urp-pipeline.ts → pipeline/standard-forward-lane.ts} +38 -149
  467. package/src/{hdrp-pipeline.ts → pipeline/standard-pipeline.ts} +221 -191
  468. package/src/pipeline/standard-profile.ts +65 -0
  469. package/src/pipeline-builder.ts +60 -64
  470. package/src/pipeline-spec-types.ts +28 -0
  471. package/src/pipeline-spec.ts +72 -609
  472. package/src/plugin.ts +7 -75
  473. package/src/points-lines/__tests__/bounds.unit.test.ts +21 -0
  474. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +157 -0
  475. package/src/points-lines/__tests__/inspection-lanes.integration.test.ts +146 -0
  476. package/src/points-lines/__tests__/inspection.unit.test.ts +173 -0
  477. package/src/points-lines/__tests__/lane-structural.integration.test.ts +122 -0
  478. package/src/points-lines/__tests__/points-lines.bench.ts +400 -0
  479. package/src/points-lines/__tests__/raster-lane.integration.test.ts +44 -0
  480. package/src/points-lines/__tests__/snapshot.unit.test.ts +101 -0
  481. package/src/points-lines/__tests__/view-ubo.unit.test.ts +73 -0
  482. package/src/points-lines/admission.ts +238 -0
  483. package/src/points-lines/bounds.ts +23 -0
  484. package/src/points-lines/expansion-cache.ts +215 -0
  485. package/src/points-lines/inspection.ts +97 -0
  486. package/src/points-lines/prepare.ts +177 -0
  487. package/src/points-lines/record.ts +125 -0
  488. package/src/points-lines/snapshot.ts +130 -0
  489. package/src/post-process-errors.ts +31 -33
  490. package/src/prepare/prepared-graphics-resolver.ts +5 -4
  491. package/src/record/__tests__/material-slot-plan.unit.test.ts +1 -33
  492. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  493. package/src/record/__tests__/video-texture-view.unit.test.ts +1 -1
  494. package/src/record/frame-lighting.ts +88 -197
  495. package/src/record/frame-snapshot.ts +45 -60
  496. package/src/record/frame-targets.ts +8 -243
  497. package/src/record/frame.ts +521 -797
  498. package/src/record/helpers.ts +6 -11
  499. package/src/record/main-pass-geometry.ts +198 -147
  500. package/src/record/main-pass-material.ts +517 -190
  501. package/src/record/main-pass-sprite-draws.ts +199 -118
  502. package/src/record/main-pass.ts +166 -144
  503. package/src/record/mesh-ssbo.ts +517 -38
  504. package/src/record/render-context.ts +384 -0
  505. package/src/record/shadow-pass.ts +154 -1843
  506. package/src/record/skybox-post-pass.ts +14 -15
  507. package/src/record/typed-frame-graph.ts +224 -262
  508. package/src/record/view-ubo.ts +53 -37
  509. package/src/render-contract.ts +582 -0
  510. package/src/render-data.ts +3 -3
  511. package/src/render-graph-primitives.ts +76 -851
  512. package/src/render-pipeline.ts +104 -188
  513. package/src/render-system-extract.ts +1114 -1732
  514. package/src/render-system.ts +614 -1939
  515. package/src/scene/render-scene-types.ts +67 -0
  516. package/src/scene/render-scene.ts +1087 -0
  517. package/src/scene-instances/post-spawn-resolve-joints.ts +4 -7
  518. package/src/ssao-buffers.ts +167 -8
  519. package/src/systems/skin-palette-allocator.ts +21 -64
  520. package/src/systems/skin-palette-types.ts +14 -0
  521. package/src/systems/transparent-sort-config.ts +25 -3
  522. package/src/tilemap-chunk-extract-system.ts +53 -70
  523. package/src/typed-render-graph-primitives.ts +35 -24
  524. package/src/typed-shadow-passes.ts +26 -56
  525. package/dist/__tests__/analytic-sky-contract.test.d.ts +0 -2
  526. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +0 -1
  527. package/dist/__tests__/analytic-sky-falsify.test.d.ts +0 -2
  528. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +0 -1
  529. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +0 -2
  530. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +0 -1
  531. package/dist/__tests__/backend-selection.integration.test.d.ts +0 -2
  532. package/dist/__tests__/backend-selection.integration.test.d.ts.map +0 -1
  533. package/dist/__tests__/camera-temporal.test-d.d.ts +0 -2
  534. package/dist/__tests__/camera-temporal.test-d.d.ts.map +0 -1
  535. package/dist/__tests__/camera-temporal.test.d.ts +0 -2
  536. package/dist/__tests__/camera-temporal.test.d.ts.map +0 -1
  537. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +0 -2
  538. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +0 -1
  539. package/dist/__tests__/environment-inspection.test.d.ts +0 -2
  540. package/dist/__tests__/environment-inspection.test.d.ts.map +0 -1
  541. package/dist/__tests__/fog-ai-user.fixture.d.ts +0 -2
  542. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +0 -1
  543. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +0 -16
  544. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +0 -1
  545. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +0 -2
  546. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +0 -1
  547. package/dist/__tests__/fog-inspection.integration.test.d.ts +0 -2
  548. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +0 -1
  549. package/dist/__tests__/fog-owner-state.integration.test.d.ts +0 -2
  550. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +0 -1
  551. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +0 -2
  552. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +0 -1
  553. package/dist/__tests__/fog-public-surface.integration.test.d.ts +0 -2
  554. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +0 -1
  555. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +0 -2
  556. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +0 -1
  557. package/dist/__tests__/fog-source-absence.integration.test.d.ts +0 -2
  558. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +0 -1
  559. package/dist/__tests__/fog-temporal.integration.test.d.ts +0 -2
  560. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +0 -1
  561. package/dist/__tests__/frame-chain.unit.test.d.ts +0 -2
  562. package/dist/__tests__/frame-chain.unit.test.d.ts.map +0 -1
  563. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +0 -2
  564. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +0 -1
  565. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +0 -2
  566. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +0 -1
  567. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +0 -2
  568. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +0 -1
  569. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +0 -2
  570. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +0 -1
  571. package/dist/__tests__/material-derived-payload.integration.test.d.ts +0 -2
  572. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +0 -1
  573. package/dist/__tests__/materials.unit.test.d.ts +0 -2
  574. package/dist/__tests__/materials.unit.test.d.ts.map +0 -1
  575. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +0 -2
  576. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +0 -1
  577. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +0 -2
  578. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +0 -1
  579. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +0 -2
  580. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +0 -1
  581. package/dist/__tests__/pipeline-pass-trace.test.d.ts +0 -2
  582. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +0 -1
  583. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +0 -2
  584. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +0 -1
  585. package/dist/__tests__/plugin.test.d.ts +0 -2
  586. package/dist/__tests__/plugin.test.d.ts.map +0 -1
  587. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +0 -2
  588. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +0 -1
  589. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +0 -2
  590. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +0 -1
  591. package/dist/__tests__/public-pipeline-id.test-d.d.ts +0 -2
  592. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +0 -1
  593. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +0 -2
  594. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +0 -1
  595. package/dist/__tests__/render-feature-construction.unit.test.d.ts +0 -2
  596. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +0 -1
  597. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +0 -2
  598. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +0 -1
  599. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +0 -2
  600. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +0 -1
  601. package/dist/__tests__/render-feature-graph.integration.test.d.ts +0 -2
  602. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +0 -1
  603. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +0 -2
  604. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +0 -1
  605. package/dist/__tests__/render-feature-order.unit.test.d.ts +0 -2
  606. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +0 -1
  607. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +0 -2
  608. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +0 -1
  609. package/dist/__tests__/render-feature-staging.unit.test.d.ts +0 -2
  610. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +0 -1
  611. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +0 -2
  612. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +0 -1
  613. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +0 -2
  614. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +0 -1
  615. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +0 -2
  616. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +0 -1
  617. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +0 -2
  618. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +0 -1
  619. package/dist/__tests__/taa-history-store.unit.test.d.ts +0 -2
  620. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +0 -1
  621. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +0 -2
  622. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +0 -1
  623. package/dist/__tests__/temporal-inspection.unit.test.d.ts +0 -2
  624. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +0 -1
  625. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +0 -2
  626. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +0 -1
  627. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +0 -2
  628. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +0 -1
  629. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +0 -2
  630. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +0 -1
  631. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +0 -2
  632. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +0 -1
  633. package/dist/chunk-DJIMFYX6.mjs +0 -1439
  634. package/dist/chunk-DJIMFYX6.mjs.map +0 -1
  635. package/dist/chunk-F2SIOCRM.mjs +0 -7423
  636. package/dist/chunk-F2SIOCRM.mjs.map +0 -1
  637. package/dist/chunk-JMSB7AR4.mjs +0 -3
  638. package/dist/chunk-JMSB7AR4.mjs.map +0 -1
  639. package/dist/chunk-KHI6K4C6.mjs +0 -659
  640. package/dist/chunk-KHI6K4C6.mjs.map +0 -1
  641. package/dist/chunk-PORZOL2V.mjs +0 -569
  642. package/dist/chunk-PORZOL2V.mjs.map +0 -1
  643. package/dist/chunk-UOJGMDGP.mjs +0 -29913
  644. package/dist/chunk-UOJGMDGP.mjs.map +0 -1
  645. package/dist/components/__tests__/atmosphere-red.test.d.ts +0 -2
  646. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +0 -1
  647. package/dist/components/__tests__/atmosphere.test.d.ts +0 -2
  648. package/dist/components/__tests__/atmosphere.test.d.ts.map +0 -1
  649. package/dist/components/__tests__/fog.test-d.d.ts +0 -2
  650. package/dist/components/__tests__/fog.test-d.d.ts.map +0 -1
  651. package/dist/components/__tests__/fog.test.d.ts +0 -2
  652. package/dist/components/__tests__/fog.test.d.ts.map +0 -1
  653. package/dist/components/atmosphere.d.ts +0 -18
  654. package/dist/components/atmosphere.d.ts.map +0 -1
  655. package/dist/components/environment.d.ts +0 -115
  656. package/dist/components/environment.d.ts.map +0 -1
  657. package/dist/deferred-lighting.d.ts +0 -13
  658. package/dist/deferred-lighting.d.ts.map +0 -1
  659. package/dist/dynamic-texture-store.d.ts +0 -42
  660. package/dist/dynamic-texture-store.d.ts.map +0 -1
  661. package/dist/environment/__tests__/failure-injection.test.d.ts +0 -2
  662. package/dist/environment/__tests__/failure-injection.test.d.ts.map +0 -1
  663. package/dist/environment/__tests__/generation-red.test.d.ts +0 -2
  664. package/dist/environment/__tests__/generation-red.test.d.ts.map +0 -1
  665. package/dist/environment/__tests__/generation.test.d.ts +0 -2
  666. package/dist/environment/__tests__/generation.test.d.ts.map +0 -1
  667. package/dist/environment/__tests__/graph-transaction.test.d.ts +0 -2
  668. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +0 -1
  669. package/dist/environment/__tests__/inspection-red.test.d.ts +0 -2
  670. package/dist/environment/__tests__/inspection-red.test.d.ts.map +0 -1
  671. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +0 -2
  672. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +0 -1
  673. package/dist/environment/__tests__/pipeline-topology.test.d.ts +0 -2
  674. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +0 -1
  675. package/dist/environment/__tests__/readiness.test.d.ts +0 -2
  676. package/dist/environment/__tests__/readiness.test.d.ts.map +0 -1
  677. package/dist/environment/__tests__/recovery.test.d.ts +0 -2
  678. package/dist/environment/__tests__/recovery.test.d.ts.map +0 -1
  679. package/dist/environment/__tests__/resize-dispose.test.d.ts +0 -2
  680. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +0 -1
  681. package/dist/environment/__tests__/signature-red.test.d.ts +0 -2
  682. package/dist/environment/__tests__/signature-red.test.d.ts.map +0 -1
  683. package/dist/environment/__tests__/signature.test.d.ts +0 -2
  684. package/dist/environment/__tests__/signature.test.d.ts.map +0 -1
  685. package/dist/environment/descriptors.d.ts +0 -2
  686. package/dist/environment/descriptors.d.ts.map +0 -1
  687. package/dist/environment/extracted-environment.d.ts +0 -53
  688. package/dist/environment/extracted-environment.d.ts.map +0 -1
  689. package/dist/environment/generation.d.ts +0 -62
  690. package/dist/environment/generation.d.ts.map +0 -1
  691. package/dist/environment/gpu-bundle.d.ts +0 -23
  692. package/dist/environment/gpu-bundle.d.ts.map +0 -1
  693. package/dist/environment/graph.d.ts +0 -108
  694. package/dist/environment/graph.d.ts.map +0 -1
  695. package/dist/environment/inspection.d.ts +0 -48
  696. package/dist/environment/inspection.d.ts.map +0 -1
  697. package/dist/environment/lifecycle.d.ts +0 -22
  698. package/dist/environment/lifecycle.d.ts.map +0 -1
  699. package/dist/environment/readiness.d.ts +0 -29
  700. package/dist/environment/readiness.d.ts.map +0 -1
  701. package/dist/environment/signature.d.ts +0 -70
  702. package/dist/environment/signature.d.ts.map +0 -1
  703. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +0 -2
  704. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +0 -1
  705. package/dist/extract/__tests__/environment-source.test.d.ts +0 -2
  706. package/dist/extract/__tests__/environment-source.test.d.ts.map +0 -1
  707. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +0 -2
  708. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  709. package/dist/extract/directional-csm.d.ts +0 -129
  710. package/dist/extract/directional-csm.d.ts.map +0 -1
  711. package/dist/extract/index.d.ts +0 -5
  712. package/dist/extract/index.d.ts.map +0 -1
  713. package/dist/extract/material-interface.d.ts +0 -56
  714. package/dist/extract/material-interface.d.ts.map +0 -1
  715. package/dist/extract/schema-readers.d.ts +0 -20
  716. package/dist/extract/schema-readers.d.ts.map +0 -1
  717. package/dist/features/graph-contribution.d.ts +0 -64
  718. package/dist/features/graph-contribution.d.ts.map +0 -1
  719. package/dist/features/index.d.ts +0 -21
  720. package/dist/features/index.d.ts.map +0 -1
  721. package/dist/features/morph/index.d.ts +0 -3
  722. package/dist/features/morph/index.d.ts.map +0 -1
  723. package/dist/features/morph/morph-bounds.d.ts +0 -42
  724. package/dist/features/morph/morph-bounds.d.ts.map +0 -1
  725. package/dist/features/scene-temporal.d.ts +0 -45
  726. package/dist/features/scene-temporal.d.ts.map +0 -1
  727. package/dist/features/taa-resolve.d.ts +0 -21
  728. package/dist/features/taa-resolve.d.ts.map +0 -1
  729. package/dist/frame-chain.d.ts +0 -14
  730. package/dist/frame-chain.d.ts.map +0 -1
  731. package/dist/gpu-driven/view-reference.d.ts.map +0 -1
  732. package/dist/gpu-resource-store.d.ts.map +0 -1
  733. package/dist/hdrp-cluster-membership.d.ts +0 -2
  734. package/dist/hdrp-cluster-membership.d.ts.map +0 -1
  735. package/dist/hdrp-pipeline.d.ts +0 -36
  736. package/dist/hdrp-pipeline.d.ts.map +0 -1
  737. package/dist/ibl/cubemap-projection.d.ts +0 -23
  738. package/dist/ibl/cubemap-projection.d.ts.map +0 -1
  739. package/dist/ibl/face-uniforms.d.ts +0 -65
  740. package/dist/ibl/face-uniforms.d.ts.map +0 -1
  741. package/dist/mesh-update-errors.d.ts +0 -71
  742. package/dist/mesh-update-errors.d.ts.map +0 -1
  743. package/dist/mipmap-generator.d.ts +0 -39
  744. package/dist/mipmap-generator.d.ts.map +0 -1
  745. package/dist/param-schema-projection-census.d.ts +0 -18
  746. package/dist/param-schema-projection-census.d.ts.map +0 -1
  747. package/dist/persistent-render-scene.d.ts +0 -158
  748. package/dist/persistent-render-scene.d.ts.map +0 -1
  749. package/dist/pipeline/index.d.ts +0 -11
  750. package/dist/pipeline/index.d.ts.map +0 -1
  751. package/dist/pipeline-errors.d.ts +0 -110
  752. package/dist/pipeline-errors.d.ts.map +0 -1
  753. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +0 -2
  754. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  755. package/dist/prepare/index.d.ts +0 -4
  756. package/dist/prepare/index.d.ts.map +0 -1
  757. package/dist/prepare/schema-readers.d.ts +0 -11
  758. package/dist/prepare/schema-readers.d.ts.map +0 -1
  759. package/dist/record/__tests__/environment-record.test.d.ts +0 -2
  760. package/dist/record/__tests__/environment-record.test.d.ts.map +0 -1
  761. package/dist/record/__tests__/frame-targets.unit.test.d.ts +0 -2
  762. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +0 -1
  763. package/dist/record/__tests__/membership-timing.unit.test.d.ts +0 -2
  764. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +0 -1
  765. package/dist/record/__tests__/render-submission.integration.test.d.ts +0 -2
  766. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +0 -1
  767. package/dist/record/__tests__/render-submission.perf.test.d.ts +0 -2
  768. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +0 -1
  769. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +0 -2
  770. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +0 -1
  771. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +0 -2
  772. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +0 -1
  773. package/dist/record/frame-observation.d.ts +0 -38
  774. package/dist/record/frame-observation.d.ts.map +0 -1
  775. package/dist/record/index.d.ts +0 -15
  776. package/dist/record/index.d.ts.map +0 -1
  777. package/dist/record/main-pass-skin.d.ts +0 -46
  778. package/dist/record/main-pass-skin.d.ts.map +0 -1
  779. package/dist/record/main-pass-sprite.d.ts +0 -69
  780. package/dist/record/main-pass-sprite.d.ts.map +0 -1
  781. package/dist/record/material-payload.d.ts +0 -43
  782. package/dist/record/material-payload.d.ts.map +0 -1
  783. package/dist/record/material-slot-plan.d.ts +0 -26
  784. package/dist/record/material-slot-plan.d.ts.map +0 -1
  785. package/dist/record/membership-timing.d.ts +0 -232
  786. package/dist/record/membership-timing.d.ts.map +0 -1
  787. package/dist/record/shadow-caster-uniform.d.ts +0 -8
  788. package/dist/record/shadow-caster-uniform.d.ts.map +0 -1
  789. package/dist/record/shadow-submit-mode.d.ts +0 -66
  790. package/dist/record/shadow-submit-mode.d.ts.map +0 -1
  791. package/dist/render-dispatch-membership.d.ts +0 -47
  792. package/dist/render-dispatch-membership.d.ts.map +0 -1
  793. package/dist/render-pipeline-context.d.ts +0 -289
  794. package/dist/render-pipeline-context.d.ts.map +0 -1
  795. package/dist/render-pipeline-target.d.ts +0 -16
  796. package/dist/render-pipeline-target.d.ts.map +0 -1
  797. package/dist/render-scene-projection.d.ts +0 -174
  798. package/dist/render-scene-projection.d.ts.map +0 -1
  799. package/dist/render-system-fold.d.ts +0 -266
  800. package/dist/render-system-fold.d.ts.map +0 -1
  801. package/dist/renderer/asset-service.d.ts +0 -10
  802. package/dist/renderer/asset-service.d.ts.map +0 -1
  803. package/dist/renderer/backend-selection.d.ts.map +0 -1
  804. package/dist/renderer/environment-classify.d.ts +0 -6
  805. package/dist/renderer/environment-classify.d.ts.map +0 -1
  806. package/dist/renderer/environment-error.d.ts +0 -13
  807. package/dist/renderer/environment-error.d.ts.map +0 -1
  808. package/dist/renderer/material/pipeline-projection.d.ts +0 -91
  809. package/dist/renderer/material/pipeline-projection.d.ts.map +0 -1
  810. package/dist/renderer/renderer-factory.d.ts +0 -289
  811. package/dist/renderer/renderer-factory.d.ts.map +0 -1
  812. package/dist/renderer.d.ts +0 -771
  813. package/dist/renderer.d.ts.map +0 -1
  814. package/dist/scene-utils/collect-subtree.d.ts +0 -11
  815. package/dist/scene-utils/collect-subtree.d.ts.map +0 -1
  816. package/dist/ssao-data.d.ts +0 -34
  817. package/dist/ssao-data.d.ts.map +0 -1
  818. package/dist/surface-format.d.ts +0 -10
  819. package/dist/surface-format.d.ts.map +0 -1
  820. package/dist/taa-history-store.d.ts +0 -88
  821. package/dist/taa-history-store.d.ts.map +0 -1
  822. package/dist/temporal-coverage.d.ts +0 -35
  823. package/dist/temporal-coverage.d.ts.map +0 -1
  824. package/dist/temporal-frame-transaction.d.ts +0 -92
  825. package/dist/temporal-frame-transaction.d.ts.map +0 -1
  826. package/dist/temporal-inspection.d.ts +0 -57
  827. package/dist/temporal-inspection.d.ts.map +0 -1
  828. package/dist/temporal-view.d.ts +0 -43
  829. package/dist/temporal-view.d.ts.map +0 -1
  830. package/dist/tilemap/resolve-tileset-runtime.d.ts +0 -23
  831. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +0 -1
  832. package/dist/urp-pipeline.d.ts +0 -4
  833. package/dist/urp-pipeline.d.ts.map +0 -1
  834. package/src/__tests__/analytic-sky-contract.test.ts +0 -27
  835. package/src/__tests__/analytic-sky-falsify-carriers.mjs +0 -43
  836. package/src/__tests__/analytic-sky-falsify.test.ts +0 -94
  837. package/src/__tests__/assets-runtime-handoff.integration.test.ts +0 -36
  838. package/src/__tests__/backend-selection.integration.test.ts +0 -11
  839. package/src/__tests__/camera-temporal.test-d.ts +0 -8
  840. package/src/__tests__/camera-temporal.test.ts +0 -188
  841. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +0 -18
  842. package/src/__tests__/environment-inspection.test.ts +0 -45
  843. package/src/__tests__/fog-ai-user.fixture.ts +0 -350
  844. package/src/__tests__/fog-custom-render-feature.fixture.ts +0 -33
  845. package/src/__tests__/fog-custom-render-feature.integration.test.ts +0 -76
  846. package/src/__tests__/fog-inspection.integration.test.ts +0 -127
  847. package/src/__tests__/fog-owner-state.integration.test.ts +0 -112
  848. package/src/__tests__/fog-pipeline-topology.integration.test.ts +0 -93
  849. package/src/__tests__/fog-public-surface.integration.test.ts +0 -60
  850. package/src/__tests__/fog-ray-contract.integration.test.ts +0 -73
  851. package/src/__tests__/fog-source-absence.integration.test.ts +0 -51
  852. package/src/__tests__/fog-temporal.integration.test.ts +0 -115
  853. package/src/__tests__/frame-chain.unit.test.ts +0 -26
  854. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +0 -27
  855. package/src/__tests__/hdrp-pipeline.unit.test.ts +0 -100
  856. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +0 -23
  857. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +0 -69
  858. package/src/__tests__/material-derived-payload.integration.test.ts +0 -164
  859. package/src/__tests__/materials.unit.test.ts +0 -25
  860. package/src/__tests__/param-schema-projection-census.unit.test.ts +0 -40
  861. package/src/__tests__/persistent-render-scene.unit.test.ts +0 -1311
  862. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +0 -167
  863. package/src/__tests__/pipeline-pass-trace.test.ts +0 -92
  864. package/src/__tests__/pipeline-stage-owner.test-d.ts +0 -13
  865. package/src/__tests__/plugin.test.ts +0 -25
  866. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +0 -129
  867. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +0 -180
  868. package/src/__tests__/public-pipeline-id.test-d.ts +0 -6
  869. package/src/__tests__/render-dispatch-membership.unit.test.ts +0 -117
  870. package/src/__tests__/render-feature-construction.unit.test.ts +0 -124
  871. package/src/__tests__/render-feature-error-code-owner.test-d.ts +0 -27
  872. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +0 -46
  873. package/src/__tests__/render-feature-graph.integration.test.ts +0 -205
  874. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +0 -200
  875. package/src/__tests__/render-feature-order.unit.test.ts +0 -66
  876. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +0 -107
  877. package/src/__tests__/render-feature-staging.unit.test.ts +0 -94
  878. package/src/__tests__/renderer-render-scene-public.test-d.ts +0 -27
  879. package/src/__tests__/scene-temporal-coverage.unit.test.ts +0 -259
  880. package/src/__tests__/sun-snapshot-consumers.test.ts +0 -35
  881. package/src/__tests__/surface-backend-kind-owner.test-d.ts +0 -42
  882. package/src/__tests__/taa-history-store.unit.test.ts +0 -196
  883. package/src/__tests__/temporal-frame-transaction.integration.test.ts +0 -537
  884. package/src/__tests__/temporal-inspection.unit.test.ts +0 -138
  885. package/src/assets/__tests__/asset-decoders.unit.test.ts +0 -92
  886. package/src/assets/__tests__/mipmap-generator.unit.test.ts +0 -52
  887. package/src/assets/__tests__/render-asset-port.unit.test.ts +0 -54
  888. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +0 -47
  889. package/src/components/__tests__/atmosphere-red.test.ts +0 -51
  890. package/src/components/__tests__/atmosphere.test.ts +0 -79
  891. package/src/components/__tests__/fog.test-d.ts +0 -49
  892. package/src/components/__tests__/fog.test.ts +0 -60
  893. package/src/components/atmosphere.ts +0 -64
  894. package/src/deferred-lighting.ts +0 -92
  895. package/src/dynamic-texture-store.ts +0 -111
  896. package/src/environment/README.md +0 -76
  897. package/src/environment/__tests__/failure-injection.test.ts +0 -50
  898. package/src/environment/__tests__/generation-red.test.ts +0 -64
  899. package/src/environment/__tests__/generation.test.ts +0 -37
  900. package/src/environment/__tests__/graph-transaction.test.ts +0 -85
  901. package/src/environment/__tests__/inspection-red.test.ts +0 -53
  902. package/src/environment/__tests__/lifecycle-evidence.test.ts +0 -40
  903. package/src/environment/__tests__/pipeline-topology.test.ts +0 -33
  904. package/src/environment/__tests__/readiness.test.ts +0 -42
  905. package/src/environment/__tests__/recovery.test.ts +0 -62
  906. package/src/environment/__tests__/resize-dispose.test.ts +0 -30
  907. package/src/environment/__tests__/signature-red.test.ts +0 -45
  908. package/src/environment/__tests__/signature.test.ts +0 -60
  909. package/src/environment/descriptors.ts +0 -7
  910. package/src/environment/extracted-environment.ts +0 -239
  911. package/src/environment/generation.ts +0 -158
  912. package/src/environment/gpu-bundle.ts +0 -144
  913. package/src/environment/graph.ts +0 -588
  914. package/src/environment/inspection.ts +0 -107
  915. package/src/environment/lifecycle.ts +0 -124
  916. package/src/environment/readiness.ts +0 -76
  917. package/src/environment/signature.ts +0 -185
  918. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +0 -391
  919. package/src/extract/__tests__/environment-source.test.ts +0 -105
  920. package/src/extract/__tests__/schema-readers.unit.test.ts +0 -16
  921. package/src/extract/directional-csm.ts +0 -959
  922. package/src/extract/index.ts +0 -10
  923. package/src/extract/material-interface.ts +0 -604
  924. package/src/extract/schema-readers.ts +0 -27
  925. package/src/features/graph-contribution.ts +0 -577
  926. package/src/features/index.ts +0 -100
  927. package/src/features/morph/index.ts +0 -24
  928. package/src/features/morph/morph-bounds.ts +0 -123
  929. package/src/features/scene-temporal.ts +0 -274
  930. package/src/features/taa-resolve.ts +0 -244
  931. package/src/frame-chain.ts +0 -21
  932. package/src/hdrp-cluster-membership.ts +0 -70
  933. package/src/ibl/cubemap-projection.ts +0 -60
  934. package/src/ibl/face-uniforms.ts +0 -150
  935. package/src/mesh-update-errors.ts +0 -113
  936. package/src/mipmap-generator.ts +0 -244
  937. package/src/param-schema-projection-census.ts +0 -73
  938. package/src/persistent-render-scene.ts +0 -1752
  939. package/src/pipeline/index.ts +0 -40
  940. package/src/pipeline-errors.ts +0 -172
  941. package/src/prepare/__tests__/schema-readers.unit.test.ts +0 -16
  942. package/src/prepare/index.ts +0 -8
  943. package/src/prepare/schema-readers.ts +0 -20
  944. package/src/record/__tests__/environment-record.test.ts +0 -35
  945. package/src/record/__tests__/frame-targets.unit.test.ts +0 -54
  946. package/src/record/__tests__/membership-timing.unit.test.ts +0 -524
  947. package/src/record/__tests__/render-submission.integration.test.ts +0 -76
  948. package/src/record/__tests__/render-submission.perf.test.ts +0 -141
  949. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +0 -88
  950. package/src/record/__tests__/view-ubo-layout.unit.test.ts +0 -101
  951. package/src/record/frame-observation.ts +0 -122
  952. package/src/record/index.ts +0 -15
  953. package/src/record/main-pass-skin.ts +0 -51
  954. package/src/record/main-pass-sprite.ts +0 -166
  955. package/src/record/material-payload.ts +0 -292
  956. package/src/record/material-slot-plan.ts +0 -68
  957. package/src/record/membership-timing.ts +0 -1012
  958. package/src/record/shadow-caster-uniform.ts +0 -37
  959. package/src/record/shadow-submit-mode.ts +0 -277
  960. package/src/render-dispatch-membership.ts +0 -155
  961. package/src/render-pipeline-context.ts +0 -332
  962. package/src/render-pipeline-target.ts +0 -96
  963. package/src/render-scene-projection.ts +0 -1738
  964. package/src/render-system-fold.ts +0 -531
  965. package/src/renderer/asset-service.ts +0 -32
  966. package/src/renderer/backend-selection.ts +0 -121
  967. package/src/renderer/environment-classify.ts +0 -30
  968. package/src/renderer/environment-error.ts +0 -19
  969. package/src/renderer/material/pipeline-projection.ts +0 -140
  970. package/src/renderer.ts +0 -940
  971. package/src/scene-utils/collect-subtree.ts +0 -40
  972. package/src/ssao-data.ts +0 -106
  973. package/src/surface-format.ts +0 -37
  974. package/src/taa-history-store.ts +0 -429
  975. package/src/temporal-coverage.ts +0 -106
  976. package/src/temporal-frame-transaction.ts +0 -301
  977. package/src/temporal-inspection.ts +0 -194
  978. package/src/temporal-view.ts +0 -174
  979. package/src/tilemap/resolve-tileset-runtime.ts +0 -72
@@ -1,1738 +0,0 @@
1
- import type {
2
- RenderSceneFact,
3
- RenderSceneFactInput,
4
- SceneCasterEligibility,
5
- SceneFactDiagnostic,
6
- SceneFactRevisionDomain,
7
- SceneFactRevisions,
8
- SceneMobility,
9
- } from './gpu-scene-schema';
10
- import type {
11
- RenderableReactiveReason,
12
- RenderableSnapshot,
13
- RenderableTemporalSnapshot,
14
- } from './render-system-extract';
15
-
16
- interface RenderSceneIdentity {
17
- readonly worldId: number;
18
- readonly entityKey: number;
19
- /** Generation observed by the producer when the operation was authored. */
20
- readonly expectedGeneration?: number;
21
- }
22
-
23
- export type RenderSceneOperation =
24
- | {
25
- readonly kind: 'create';
26
- readonly snapshot: RenderableSnapshot;
27
- readonly expectedGeneration?: number;
28
- }
29
- | (RenderSceneIdentity & {
30
- readonly kind: 'update-transform';
31
- readonly world: Float32Array;
32
- })
33
- | (RenderSceneIdentity & { readonly kind: 'remove' });
34
-
35
- export interface RenderSceneFactDelta {
36
- readonly slot: number;
37
- readonly generation: number;
38
- readonly changedDomains: readonly SceneFactRevisionDomain[];
39
- readonly previous: RenderSceneFact | undefined;
40
- readonly current: RenderSceneFact;
41
- }
42
-
43
- export interface RenderSceneApplyResult {
44
- readonly created: number;
45
- readonly updated: number;
46
- readonly removed: number;
47
- readonly recreated: number;
48
- readonly ignoredLateUpdates: number;
49
- readonly createdSlots: readonly RenderSceneProjectionSlot[];
50
- readonly updatedSlots: readonly RenderSceneProjectionSlot[];
51
- readonly removedSlots: readonly RenderSceneProjectionRecord[];
52
- readonly recreatedSlots: readonly RenderSceneProjectionSlot[];
53
- /** Fine-grained Scene Fact updates consumed by GPU tables and later views. */
54
- readonly factDeltas: readonly RenderSceneFactDelta[];
55
- /** Non-fatal diagnostics; malformed facts never become implicit casters. */
56
- readonly diagnostics: readonly SceneFactDiagnostic[];
57
- /** Spatial owner revisions produced by this projection update. */
58
- readonly spatialIndex?: SpatialIndexUpdate;
59
- }
60
-
61
- export interface RenderSceneProjectionRecord
62
- extends Omit<RenderSceneIdentity, 'expectedGeneration'> {
63
- readonly slot: number;
64
- readonly generation: number;
65
- }
66
-
67
- export interface RenderSceneProjectionInspection {
68
- readonly current: readonly RenderSceneProjectionRecord[];
69
- readonly lastSubmitted: {
70
- readonly epoch: number;
71
- readonly records: readonly RenderSceneProjectionRecord[];
72
- };
73
- readonly slotCapacity: number;
74
- readonly freeSlots: number;
75
- readonly factDiagnostics: readonly SceneFactDiagnostic[];
76
- readonly spatialIndex: SpatialIndexInspection;
77
- }
78
-
79
- export interface RenderSceneProjectionSlot extends RenderSceneProjectionRecord {
80
- readonly snapshot: RenderableSnapshot;
81
- readonly fact: RenderSceneFact;
82
- }
83
-
84
- type ProjectionSlot = RenderSceneProjectionSlot;
85
-
86
- function submittedIdentity(slot: number, generation: number): string {
87
- return `${slot}:${generation}`;
88
- }
89
-
90
- export interface RenderSceneSubmissionCapture {
91
- readonly revision: number;
92
- readonly slots: readonly {
93
- readonly slot: number;
94
- readonly current: RenderSceneProjectionSlot | undefined;
95
- }[];
96
- readonly visible: ReadonlySet<string>;
97
- }
98
-
99
- export interface RenderSceneSubmissionDelta {
100
- readonly epoch: number;
101
- readonly slots: readonly number[];
102
- }
103
-
104
- export type SpatialIndexOwnerKind = 'static-bvh' | 'dynamic-loose-tree';
105
-
106
- export interface SpatialQueryHit extends RenderSceneProjectionRecord {
107
- readonly owner: SpatialIndexOwnerKind;
108
- readonly mobility: SceneMobility;
109
- readonly worldAabb: Float32Array | undefined;
110
- }
111
-
112
- export interface SpatialQueryResult {
113
- readonly hits: readonly SpatialQueryHit[];
114
- readonly staticRevision: number;
115
- readonly dynamicRevision: number;
116
- readonly visitedNodes: number;
117
- readonly testedEntries: number;
118
- readonly falseNegativeSlots: readonly number[];
119
- }
120
-
121
- export interface SpatialIndexOwnerInspection {
122
- readonly revision: number;
123
- readonly entries: number;
124
- readonly boundedEntries: number;
125
- readonly unboundedEntries: number;
126
- readonly nodes: number;
127
- readonly rebuilds: number;
128
- readonly patches: number;
129
- readonly queries: number;
130
- readonly visitedNodes: number;
131
- readonly testedEntries: number;
132
- readonly returnedEntries: number;
133
- }
134
-
135
- export interface SpatialIndexInspection {
136
- readonly revision: number;
137
- readonly static: SpatialIndexOwnerInspection;
138
- readonly dynamic: SpatialIndexOwnerInspection & {
139
- readonly dynamicEntries: number;
140
- readonly unknownEntries: number;
141
- readonly reinserts: number;
142
- };
143
- readonly broadphaseQueries: number;
144
- readonly bruteForceComparisons: number;
145
- readonly falseNegatives: number;
146
- }
147
-
148
- export interface SpatialIndexUpdate {
149
- readonly revision: number;
150
- readonly staticRevision: number;
151
- readonly dynamicRevision: number;
152
- readonly staticChanged: boolean;
153
- readonly dynamicChanged: boolean;
154
- readonly inspection: SpatialIndexInspection;
155
- }
156
-
157
- interface SpatialRecord {
158
- readonly slot: number;
159
- readonly generation: number;
160
- readonly worldId: number;
161
- readonly entityKey: number;
162
- readonly mobility: SceneMobility;
163
- readonly worldAabb: Float32Array | undefined;
164
- }
165
-
166
- interface SpatialQueryOwnerResult {
167
- readonly records: readonly SpatialRecord[];
168
- readonly visitedNodes: number;
169
- readonly testedEntries: number;
170
- }
171
-
172
- interface ConservativeSpatialIndexOwner {
173
- query(bounds: Float32Array): SpatialQueryOwnerResult;
174
- }
175
-
176
- interface StaticBvhNode {
177
- readonly bounds: Float32Array;
178
- readonly left: StaticBvhNode | undefined;
179
- readonly right: StaticBvhNode | undefined;
180
- readonly record: SpatialRecord | undefined;
181
- }
182
-
183
- interface DynamicLooseNode {
184
- parent: DynamicLooseNode | undefined;
185
- left: DynamicLooseNode | undefined;
186
- right: DynamicLooseNode | undefined;
187
- bounds: Float32Array;
188
- record: SpatialRecord | undefined;
189
- }
190
-
191
- function spatialRecord(slot: RenderSceneProjectionSlot): SpatialRecord {
192
- return {
193
- slot: slot.slot,
194
- generation: slot.generation,
195
- worldId: slot.worldId,
196
- entityKey: slot.entityKey,
197
- mobility: slot.fact.mobility,
198
- worldAabb:
199
- slot.fact.bounds.status === 'present'
200
- ? new Float32Array(slot.fact.bounds.worldAabb)
201
- : undefined,
202
- };
203
- }
204
-
205
- function sameSpatialRecord(left: SpatialRecord | undefined, right: SpatialRecord): boolean {
206
- return (
207
- left !== undefined &&
208
- left.generation === right.generation &&
209
- left.worldId === right.worldId &&
210
- left.entityKey === right.entityKey &&
211
- left.mobility === right.mobility &&
212
- sameFloatArray(left.worldAabb, right.worldAabb)
213
- );
214
- }
215
-
216
- function mergeAabbInto(target: Float32Array, left: Float32Array, right: Float32Array): void {
217
- target[0] = Math.min(left[0] ?? 0, right[0] ?? 0);
218
- target[1] = Math.min(left[1] ?? 0, right[1] ?? 0);
219
- target[2] = Math.min(left[2] ?? 0, right[2] ?? 0);
220
- target[3] = Math.max(left[3] ?? 0, right[3] ?? 0);
221
- target[4] = Math.max(left[4] ?? 0, right[4] ?? 0);
222
- target[5] = Math.max(left[5] ?? 0, right[5] ?? 0);
223
- }
224
-
225
- function mergeAabb(left: Float32Array, right: Float32Array): Float32Array {
226
- const merged = new Float32Array(6);
227
- mergeAabbInto(merged, left, right);
228
- return merged;
229
- }
230
-
231
- function overlapsAabb(left: Float32Array, right: Float32Array): boolean {
232
- return (
233
- (left[3] ?? -Infinity) >= (right[0] ?? Infinity) &&
234
- (left[0] ?? Infinity) <= (right[3] ?? -Infinity) &&
235
- (left[4] ?? -Infinity) >= (right[1] ?? Infinity) &&
236
- (left[1] ?? Infinity) <= (right[4] ?? -Infinity) &&
237
- (left[5] ?? -Infinity) >= (right[2] ?? Infinity) &&
238
- (left[2] ?? Infinity) <= (right[5] ?? -Infinity)
239
- );
240
- }
241
-
242
- function containsAabb(outer: Float32Array, inner: Float32Array): boolean {
243
- return (
244
- (outer[0] ?? Infinity) <= (inner[0] ?? -Infinity) &&
245
- (outer[1] ?? Infinity) <= (inner[1] ?? -Infinity) &&
246
- (outer[2] ?? Infinity) <= (inner[2] ?? -Infinity) &&
247
- (outer[3] ?? -Infinity) >= (inner[3] ?? Infinity) &&
248
- (outer[4] ?? -Infinity) >= (inner[4] ?? Infinity) &&
249
- (outer[5] ?? -Infinity) >= (inner[5] ?? Infinity)
250
- );
251
- }
252
-
253
- function aabbCost(bounds: Float32Array): number {
254
- const x = Math.max(0, (bounds[3] ?? 0) - (bounds[0] ?? 0));
255
- const y = Math.max(0, (bounds[4] ?? 0) - (bounds[1] ?? 0));
256
- const z = Math.max(0, (bounds[5] ?? 0) - (bounds[2] ?? 0));
257
- return 2 * (x * y + x * z + y * z);
258
- }
259
-
260
- /** Compute the union surface area without allocating a temporary AABB. */
261
- function mergedAabbCost(left: Float32Array, right: Float32Array): number {
262
- const x = Math.max(
263
- 0,
264
- Math.max(left[3] ?? 0, right[3] ?? 0) - Math.min(left[0] ?? 0, right[0] ?? 0),
265
- );
266
- const y = Math.max(
267
- 0,
268
- Math.max(left[4] ?? 0, right[4] ?? 0) - Math.min(left[1] ?? 0, right[1] ?? 0),
269
- );
270
- const z = Math.max(
271
- 0,
272
- Math.max(left[5] ?? 0, right[5] ?? 0) - Math.min(left[2] ?? 0, right[2] ?? 0),
273
- );
274
- return 2 * (x * y + x * z + y * z);
275
- }
276
-
277
- function looseBounds(bounds: Float32Array): Float32Array {
278
- const extent = Math.max(
279
- (bounds[3] ?? 0) - (bounds[0] ?? 0),
280
- (bounds[4] ?? 0) - (bounds[1] ?? 0),
281
- (bounds[5] ?? 0) - (bounds[2] ?? 0),
282
- );
283
- const margin = Math.max(0.01, extent * 0.125);
284
- return new Float32Array([
285
- (bounds[0] ?? 0) - margin,
286
- (bounds[1] ?? 0) - margin,
287
- (bounds[2] ?? 0) - margin,
288
- (bounds[3] ?? 0) + margin,
289
- (bounds[4] ?? 0) + margin,
290
- (bounds[5] ?? 0) + margin,
291
- ]);
292
- }
293
-
294
- function buildStaticBvh(records: readonly SpatialRecord[]): StaticBvhNode | undefined {
295
- if (records.length === 0) return undefined;
296
- if (records.length === 1) {
297
- const record = records[0];
298
- if (record?.worldAabb === undefined) return undefined;
299
- return { bounds: record.worldAabb, left: undefined, right: undefined, record };
300
- }
301
- let bounds = records[0]?.worldAabb;
302
- if (bounds === undefined) return undefined;
303
- bounds = new Float32Array(bounds);
304
- for (let index = 1; index < records.length; index += 1) {
305
- const next = records[index]?.worldAabb;
306
- if (next !== undefined) bounds = mergeAabb(bounds, next);
307
- }
308
- const extents = [
309
- (bounds[3] ?? 0) - (bounds[0] ?? 0),
310
- (bounds[4] ?? 0) - (bounds[1] ?? 0),
311
- (bounds[5] ?? 0) - (bounds[2] ?? 0),
312
- ];
313
- let axis = 0;
314
- if ((extents[1] ?? 0) > (extents[axis] ?? 0)) axis = 1;
315
- if ((extents[2] ?? 0) > (extents[axis] ?? 0)) axis = 2;
316
- const ordered = [...records].sort((left, right) => {
317
- const leftBounds = left.worldAabb;
318
- const rightBounds = right.worldAabb;
319
- return (
320
- ((leftBounds?.[axis] ?? 0) + (leftBounds?.[axis + 3] ?? 0)) * 0.5 -
321
- ((rightBounds?.[axis] ?? 0) + (rightBounds?.[axis + 3] ?? 0)) * 0.5
322
- );
323
- });
324
- const middle = Math.floor(ordered.length / 2);
325
- const left = buildStaticBvh(ordered.slice(0, middle));
326
- const right = buildStaticBvh(ordered.slice(middle));
327
- if (left === undefined) return right;
328
- if (right === undefined) return left;
329
- return { bounds: mergeAabb(left.bounds, right.bounds), left, right, record: undefined };
330
- }
331
-
332
- function countStaticNodes(node: StaticBvhNode | undefined): number {
333
- return node === undefined ? 0 : 1 + countStaticNodes(node.left) + countStaticNodes(node.right);
334
- }
335
-
336
- class StaticBvhOwner implements ConservativeSpatialIndexOwner {
337
- private readonly records = new Map<number, SpatialRecord>();
338
- private readonly unbounded = new Map<number, SpatialRecord>();
339
- private root: StaticBvhNode | undefined;
340
- private nodeCount = 0;
341
- private revision = 0;
342
- private rebuilds = 0;
343
- private queries = 0;
344
- private visitedNodes = 0;
345
- private testedEntries = 0;
346
- private returnedEntries = 0;
347
-
348
- replace(records: readonly SpatialRecord[]): boolean {
349
- const next = new Map(records.map((record) => [record.slot, record]));
350
- const changed =
351
- next.size !== this.records.size ||
352
- [...next].some(([slot, record]) => !sameSpatialRecord(this.records.get(slot), record));
353
- if (!changed) return false;
354
- this.records.clear();
355
- this.unbounded.clear();
356
- for (const record of records) {
357
- this.records.set(record.slot, record);
358
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
359
- }
360
- this.rebuild();
361
- this.revision += 1;
362
- this.rebuilds += 1;
363
- return true;
364
- }
365
-
366
- patch(records: readonly SpatialRecord[], removedSlots: readonly number[]): boolean {
367
- let changed = false;
368
- for (const slot of removedSlots) {
369
- if (!this.records.delete(slot)) continue;
370
- this.unbounded.delete(slot);
371
- changed = true;
372
- }
373
- for (const record of records) {
374
- if (record.mobility !== 'static') {
375
- if (!this.records.delete(record.slot)) continue;
376
- this.unbounded.delete(record.slot);
377
- changed = true;
378
- continue;
379
- }
380
- if (sameSpatialRecord(this.records.get(record.slot), record)) continue;
381
- this.records.set(record.slot, record);
382
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
383
- else this.unbounded.delete(record.slot);
384
- changed = true;
385
- }
386
- if (!changed) return false;
387
- this.rebuild();
388
- this.revision += 1;
389
- this.rebuilds += 1;
390
- return true;
391
- }
392
-
393
- query(bounds: Float32Array): SpatialQueryOwnerResult {
394
- const records = [...this.unbounded.values()];
395
- let visitedNodes = 0;
396
- let testedEntries = this.unbounded.size;
397
- const stack = this.root === undefined ? [] : [this.root];
398
- while (stack.length > 0) {
399
- const node = stack.pop();
400
- if (node === undefined) continue;
401
- visitedNodes += 1;
402
- if (!overlapsAabb(node.bounds, bounds)) continue;
403
- if (node.record !== undefined) {
404
- testedEntries += 1;
405
- records.push(node.record);
406
- } else {
407
- if (node.left !== undefined) stack.push(node.left);
408
- if (node.right !== undefined) stack.push(node.right);
409
- }
410
- }
411
- this.queries += 1;
412
- this.visitedNodes += visitedNodes;
413
- this.testedEntries += testedEntries;
414
- this.returnedEntries += records.length;
415
- return { records, visitedNodes, testedEntries };
416
- }
417
-
418
- snapshot(): readonly SpatialRecord[] {
419
- return [...this.records.values()];
420
- }
421
-
422
- inspect(): SpatialIndexOwnerInspection {
423
- return {
424
- revision: this.revision,
425
- entries: this.records.size,
426
- boundedEntries: this.records.size - this.unbounded.size,
427
- unboundedEntries: this.unbounded.size,
428
- nodes: this.nodeCount,
429
- rebuilds: this.rebuilds,
430
- patches: 0,
431
- queries: this.queries,
432
- visitedNodes: this.visitedNodes,
433
- testedEntries: this.testedEntries,
434
- returnedEntries: this.returnedEntries,
435
- };
436
- }
437
-
438
- private rebuild(): void {
439
- this.root = buildStaticBvh(
440
- [...this.records.values()].filter((record) => record.worldAabb !== undefined),
441
- );
442
- this.nodeCount = countStaticNodes(this.root);
443
- }
444
- }
445
-
446
- class DynamicLooseTreeOwner implements ConservativeSpatialIndexOwner {
447
- private readonly records = new Map<number, SpatialRecord>();
448
- private readonly leaves = new Map<number, DynamicLooseNode>();
449
- private readonly unbounded = new Map<number, SpatialRecord>();
450
- private root: DynamicLooseNode | undefined;
451
- private nodeCount = 0;
452
- private dynamicEntries = 0;
453
- private unknownEntries = 0;
454
- private revision = 0;
455
- private patches = 0;
456
- private reinserts = 0;
457
- private queries = 0;
458
- private visitedNodes = 0;
459
- private testedEntries = 0;
460
- private returnedEntries = 0;
461
-
462
- replace(records: readonly SpatialRecord[]): boolean {
463
- const next = new Map(records.map((record) => [record.slot, record]));
464
- let changed = false;
465
- for (const slot of this.records.keys()) {
466
- if (!next.has(slot)) {
467
- this.remove(slot);
468
- changed = true;
469
- }
470
- }
471
- if (
472
- !changed &&
473
- [...next].every(([slot, record]) => sameSpatialRecord(this.records.get(slot), record))
474
- ) {
475
- return false;
476
- }
477
- this.records.clear();
478
- this.leaves.clear();
479
- this.unbounded.clear();
480
- this.root = undefined;
481
- this.nodeCount = 0;
482
- this.dynamicEntries = 0;
483
- this.unknownEntries = 0;
484
- for (const record of records) {
485
- this.records.set(record.slot, record);
486
- this.addCategory(record);
487
- if (record.worldAabb === undefined) this.unbounded.set(record.slot, record);
488
- }
489
- this.rebuild(records);
490
- this.patches += records.length;
491
- this.revision += 1;
492
- return true;
493
- }
494
-
495
- patch(records: readonly SpatialRecord[], removedSlots: readonly number[]): boolean {
496
- let changed = false;
497
- for (const slot of removedSlots) {
498
- if (!this.records.has(slot)) continue;
499
- this.remove(slot);
500
- changed = true;
501
- }
502
- for (const record of records) {
503
- if (record.mobility === 'static') {
504
- if (!this.records.has(record.slot)) continue;
505
- this.remove(record.slot);
506
- changed = true;
507
- continue;
508
- }
509
- if (sameSpatialRecord(this.records.get(record.slot), record)) continue;
510
- this.upsert(record);
511
- changed = true;
512
- }
513
- if (changed) this.revision += 1;
514
- return changed;
515
- }
516
-
517
- query(bounds: Float32Array): SpatialQueryOwnerResult {
518
- const records = [...this.unbounded.values()];
519
- let visitedNodes = 0;
520
- let testedEntries = this.unbounded.size;
521
- const stack = this.root === undefined ? [] : [this.root];
522
- while (stack.length > 0) {
523
- const node = stack.pop();
524
- if (node === undefined) continue;
525
- visitedNodes += 1;
526
- if (!overlapsAabb(node.bounds, bounds)) continue;
527
- if (node.record !== undefined) {
528
- testedEntries += 1;
529
- if (node.record.worldAabb === undefined || overlapsAabb(node.record.worldAabb, bounds)) {
530
- records.push(node.record);
531
- }
532
- } else {
533
- if (node.left !== undefined) stack.push(node.left);
534
- if (node.right !== undefined) stack.push(node.right);
535
- }
536
- }
537
- this.queries += 1;
538
- this.visitedNodes += visitedNodes;
539
- this.testedEntries += testedEntries;
540
- this.returnedEntries += records.length;
541
- return { records, visitedNodes, testedEntries };
542
- }
543
-
544
- snapshot(): readonly SpatialRecord[] {
545
- return [...this.records.values()];
546
- }
547
-
548
- inspect(): SpatialIndexInspection['dynamic'] {
549
- return {
550
- revision: this.revision,
551
- entries: this.records.size,
552
- boundedEntries: this.records.size - this.unbounded.size,
553
- unboundedEntries: this.unbounded.size,
554
- nodes: this.nodeCount,
555
- rebuilds: 0,
556
- patches: this.patches,
557
- queries: this.queries,
558
- visitedNodes: this.visitedNodes,
559
- testedEntries: this.testedEntries,
560
- returnedEntries: this.returnedEntries,
561
- dynamicEntries: this.dynamicEntries,
562
- unknownEntries: this.unknownEntries,
563
- reinserts: this.reinserts,
564
- };
565
- }
566
-
567
- private upsert(record: SpatialRecord): void {
568
- const previous = this.records.get(record.slot);
569
- if (previous !== undefined) this.removeCategory(previous);
570
- this.records.set(record.slot, record);
571
- this.addCategory(record);
572
- this.patches += 1;
573
- if (record.worldAabb === undefined) {
574
- this.removeLeaf(record.slot);
575
- this.unbounded.set(record.slot, record);
576
- return;
577
- }
578
- this.unbounded.delete(record.slot);
579
- const leaf = this.leaves.get(record.slot);
580
- if (
581
- leaf !== undefined &&
582
- previous?.generation === record.generation &&
583
- containsAabb(leaf.bounds, record.worldAabb)
584
- ) {
585
- leaf.record = record;
586
- return;
587
- }
588
- this.removeLeaf(record.slot);
589
- this.insertLeaf({
590
- parent: undefined,
591
- left: undefined,
592
- right: undefined,
593
- bounds: looseBounds(record.worldAabb),
594
- record,
595
- });
596
- if (leaf !== undefined) this.reinserts += 1;
597
- }
598
-
599
- private remove(slot: number): void {
600
- const previous = this.records.get(slot);
601
- if (previous === undefined) return;
602
- this.records.delete(slot);
603
- this.removeCategory(previous);
604
- this.unbounded.delete(slot);
605
- this.removeLeaf(slot);
606
- this.patches += 1;
607
- }
608
-
609
- private addCategory(record: SpatialRecord): void {
610
- if (record.mobility === 'dynamic') this.dynamicEntries += 1;
611
- else this.unknownEntries += 1;
612
- }
613
-
614
- private removeCategory(record: SpatialRecord): void {
615
- if (record.mobility === 'dynamic') this.dynamicEntries -= 1;
616
- else this.unknownEntries -= 1;
617
- }
618
-
619
- private rebuild(records: readonly SpatialRecord[]): void {
620
- const ordered = records
621
- .filter((record) => record.worldAabb !== undefined)
622
- .slice()
623
- .sort(
624
- (left, right) =>
625
- ((left.worldAabb?.[0] ?? 0) + (left.worldAabb?.[3] ?? 0)) * 0.5 -
626
- ((right.worldAabb?.[0] ?? 0) + (right.worldAabb?.[3] ?? 0)) * 0.5,
627
- );
628
- const build = (start: number, end: number): DynamicLooseNode | undefined => {
629
- if (start >= end) return undefined;
630
- if (end - start === 1) {
631
- const record = ordered[start];
632
- if (record === undefined || record.worldAabb === undefined) return undefined;
633
- const leaf: DynamicLooseNode = {
634
- parent: undefined,
635
- left: undefined,
636
- right: undefined,
637
- bounds: looseBounds(record.worldAabb),
638
- record,
639
- };
640
- this.leaves.set(record.slot, leaf);
641
- this.nodeCount += 1;
642
- return leaf;
643
- }
644
- const middle = start + Math.floor((end - start) / 2);
645
- const left = build(start, middle);
646
- const right = build(middle, end);
647
- if (left === undefined) return right;
648
- if (right === undefined) return left;
649
- const parent: DynamicLooseNode = {
650
- parent: undefined,
651
- left,
652
- right,
653
- bounds: mergeAabb(left.bounds, right.bounds),
654
- record: undefined,
655
- };
656
- left.parent = parent;
657
- right.parent = parent;
658
- this.nodeCount += 1;
659
- return parent;
660
- };
661
- this.root = build(0, ordered.length);
662
- }
663
-
664
- private insertLeaf(leaf: DynamicLooseNode): void {
665
- const slot = leaf.record?.slot;
666
- if (slot === undefined) return;
667
- this.leaves.set(slot, leaf);
668
- if (this.root === undefined) {
669
- this.root = leaf;
670
- this.nodeCount += 1;
671
- return;
672
- }
673
- let sibling = this.root;
674
- while (sibling.record === undefined) {
675
- const left = sibling.left;
676
- const right = sibling.right;
677
- if (left === undefined || right === undefined) break;
678
- const leftCost = mergedAabbCost(left.bounds, leaf.bounds) - aabbCost(left.bounds);
679
- const rightCost = mergedAabbCost(right.bounds, leaf.bounds) - aabbCost(right.bounds);
680
- sibling = leftCost <= rightCost ? left : right;
681
- }
682
- const previousParent = sibling.parent;
683
- const parent: DynamicLooseNode = {
684
- parent: previousParent,
685
- left: sibling,
686
- right: leaf,
687
- bounds: mergeAabb(sibling.bounds, leaf.bounds),
688
- record: undefined,
689
- };
690
- sibling.parent = parent;
691
- leaf.parent = parent;
692
- if (previousParent === undefined) this.root = parent;
693
- else if (previousParent.left === sibling) previousParent.left = parent;
694
- else previousParent.right = parent;
695
- this.nodeCount += 2;
696
- this.refit(parent);
697
- }
698
-
699
- private removeLeaf(slot: number): void {
700
- const leaf = this.leaves.get(slot);
701
- if (leaf === undefined) return;
702
- this.leaves.delete(slot);
703
- if (leaf === this.root) {
704
- this.root = undefined;
705
- this.nodeCount -= 1;
706
- return;
707
- }
708
- const parent = leaf.parent;
709
- const sibling = parent?.left === leaf ? parent.right : parent?.left;
710
- const grandparent = parent?.parent;
711
- if (sibling === undefined) return;
712
- sibling.parent = grandparent;
713
- if (grandparent === undefined) this.root = sibling;
714
- else if (grandparent.left === parent) grandparent.left = sibling;
715
- else grandparent.right = sibling;
716
- this.nodeCount -= 2;
717
- this.refit(grandparent);
718
- }
719
-
720
- private refit(start: DynamicLooseNode | undefined): void {
721
- let node = start;
722
- while (node !== undefined) {
723
- if (node.left !== undefined && node.right !== undefined) {
724
- // Parent nodes own their bounds, so update in place. Dynamic
725
- // transform/topology patches can refit thousands of ancestors per
726
- // frame; allocating a Float32Array at every ancestor turns an
727
- // O(delta log N) spatial update into a GC-heavy hot path.
728
- mergeAabbInto(node.bounds, node.left.bounds, node.right.bounds);
729
- }
730
- node = node.parent;
731
- }
732
- }
733
- }
734
-
735
- class RenderSceneSpatialIndex {
736
- private readonly staticOwner = new StaticBvhOwner();
737
- private readonly dynamicOwner = new DynamicLooseTreeOwner();
738
- private revision = 0;
739
- private broadphaseQueries = 0;
740
- private bruteForceComparisons = 0;
741
- private falseNegatives = 0;
742
-
743
- replace(slots: readonly RenderSceneProjectionSlot[]): SpatialIndexUpdate {
744
- const records = slots.map(spatialRecord);
745
- const staticChanged = this.staticOwner.replace(
746
- records.filter((record) => record.mobility === 'static'),
747
- );
748
- const dynamicChanged = this.dynamicOwner.replace(
749
- records.filter((record) => record.mobility !== 'static'),
750
- );
751
- if (staticChanged || dynamicChanged) this.revision += 1;
752
- const inspection = this.inspect();
753
- return {
754
- revision: this.revision,
755
- staticRevision: inspection.static.revision,
756
- dynamicRevision: inspection.dynamic.revision,
757
- staticChanged,
758
- dynamicChanged,
759
- inspection,
760
- };
761
- }
762
-
763
- patch(
764
- slots: readonly RenderSceneProjectionSlot[],
765
- removedSlots: readonly RenderSceneProjectionRecord[],
766
- ): SpatialIndexUpdate {
767
- const records = slots.map(spatialRecord);
768
- const removed = removedSlots.map((record) => record.slot);
769
- const staticChanged = this.staticOwner.patch(records, removed);
770
- const dynamicChanged = this.dynamicOwner.patch(records, removed);
771
- if (staticChanged || dynamicChanged) this.revision += 1;
772
- const inspection = this.inspect();
773
- return {
774
- revision: this.revision,
775
- staticRevision: inspection.static.revision,
776
- dynamicRevision: inspection.dynamic.revision,
777
- staticChanged,
778
- dynamicChanged,
779
- inspection,
780
- };
781
- }
782
-
783
- query(bounds: Float32Array, verifyAgainstBruteForce: boolean): SpatialQueryResult {
784
- if (bounds.length < 6 || ![...bounds.slice(0, 6)].every(Number.isFinite)) {
785
- throw new RangeError('spatial query requires a finite world AABB');
786
- }
787
- const fromStatic = this.staticOwner.query(bounds);
788
- const fromDynamic = this.dynamicOwner.query(bounds);
789
- const records = [...fromStatic.records, ...fromDynamic.records].sort(
790
- (left, right) => left.slot - right.slot,
791
- );
792
- const falseNegativeSlots: number[] = [];
793
- if (verifyAgainstBruteForce) {
794
- this.bruteForceComparisons += 1;
795
- const actual = new Set(records.map((record) => record.slot));
796
- for (const reference of this.bruteForce(bounds)) {
797
- if (!actual.has(reference.slot)) falseNegativeSlots.push(reference.slot);
798
- }
799
- this.falseNegatives += falseNegativeSlots.length;
800
- }
801
- this.broadphaseQueries += 1;
802
- const inspection = this.inspect();
803
- return {
804
- hits: records.map((record) => ({
805
- slot: record.slot,
806
- generation: record.generation,
807
- worldId: record.worldId,
808
- entityKey: record.entityKey,
809
- owner: record.mobility === 'static' ? 'static-bvh' : 'dynamic-loose-tree',
810
- mobility: record.mobility,
811
- worldAabb: record.worldAabb === undefined ? undefined : new Float32Array(record.worldAabb),
812
- })),
813
- staticRevision: inspection.static.revision,
814
- dynamicRevision: inspection.dynamic.revision,
815
- visitedNodes: fromStatic.visitedNodes + fromDynamic.visitedNodes,
816
- testedEntries: fromStatic.testedEntries + fromDynamic.testedEntries,
817
- falseNegativeSlots,
818
- };
819
- }
820
-
821
- inspect(): SpatialIndexInspection {
822
- return {
823
- revision: this.revision,
824
- static: this.staticOwner.inspect(),
825
- dynamic: this.dynamicOwner.inspect(),
826
- broadphaseQueries: this.broadphaseQueries,
827
- bruteForceComparisons: this.bruteForceComparisons,
828
- falseNegatives: this.falseNegatives,
829
- };
830
- }
831
-
832
- private bruteForce(bounds: Float32Array): readonly SpatialRecord[] {
833
- return [...this.staticOwner.snapshot(), ...this.dynamicOwner.snapshot()].filter(
834
- (record) => record.worldAabb === undefined || overlapsAabb(record.worldAabb, bounds),
835
- );
836
- }
837
- }
838
-
839
- interface PendingIdentity {
840
- readonly worldId: number;
841
- readonly entityKey: number;
842
- readonly initial: ProjectionSlot | undefined;
843
- current: RenderableSnapshot | undefined;
844
- removed: boolean;
845
- touched: boolean;
846
- }
847
-
848
- const FACT_DOMAINS: readonly SceneFactRevisionDomain[] = [
849
- 'transform',
850
- 'geometry',
851
- 'material',
852
- 'eligibility',
853
- 'space',
854
- 'batch',
855
- 'resource',
856
- ];
857
-
858
- const ZERO_REVISIONS: SceneFactRevisions = Object.freeze({
859
- transform: 0,
860
- geometry: 0,
861
- material: 0,
862
- eligibility: 0,
863
- space: 0,
864
- batch: 0,
865
- resource: 0,
866
- });
867
-
868
- function ownSnapshot(snapshot: RenderableSnapshot): RenderableSnapshot {
869
- const { temporal: _temporal, ...current } = snapshot;
870
- return {
871
- ...current,
872
- transform: { ...snapshot.transform, world: new Float32Array(snapshot.transform.world) },
873
- ...(snapshot.boundsWorld !== undefined && {
874
- boundsWorld: new Float32Array(snapshot.boundsWorld),
875
- }),
876
- ...(snapshot.candidateInstanceTransforms !== undefined && {
877
- candidateInstanceTransforms: new Float32Array(snapshot.candidateInstanceTransforms),
878
- }),
879
- ...(snapshot.localAabb !== undefined && { localAabb: new Float32Array(snapshot.localAabb) }),
880
- ...(snapshot.instances !== undefined && {
881
- instances: {
882
- ...snapshot.instances,
883
- transforms: new Float32Array(snapshot.instances.transforms),
884
- },
885
- }),
886
- ...(snapshot.spriteInstances !== undefined && {
887
- spriteInstances: {
888
- ...snapshot.spriteInstances,
889
- transforms: new Float32Array(snapshot.spriteInstances.transforms),
890
- regions: new Float32Array(snapshot.spriteInstances.regions),
891
- },
892
- }),
893
- ...(snapshot.skin !== undefined && {
894
- skin: {
895
- ...snapshot.skin,
896
- jointMatrices: new Float32Array(snapshot.skin.jointMatrices),
897
- },
898
- }),
899
- ...(snapshot.gpuDrivenDraws !== undefined && {
900
- gpuDrivenDraws: snapshot.gpuDrivenDraws.map((draw) => ({ ...draw })),
901
- }),
902
- ...(snapshot.morphWeights !== undefined && {
903
- morphWeights: new Float32Array(snapshot.morphWeights),
904
- }),
905
- materials: [...snapshot.materials],
906
- materialBindingSources: [...snapshot.materialBindingSources],
907
- };
908
- }
909
-
910
- function withWorld(snapshot: RenderableSnapshot, world: Float32Array): RenderableSnapshot {
911
- return ownSnapshot({
912
- ...snapshot,
913
- transform: { ...snapshot.transform, world: new Float32Array(world) },
914
- });
915
- }
916
-
917
- function sameFloatArray(left: Float32Array | undefined, right: Float32Array | undefined): boolean {
918
- if (left === right) return true;
919
- if (left === undefined || right === undefined || left.length !== right.length) return false;
920
- for (let index = 0; index < left.length; index += 1) {
921
- if (left[index] !== right[index]) return false;
922
- }
923
- return true;
924
- }
925
-
926
- interface ComparedObjectPairs {
927
- readonly leftToRight: Map<object, object>;
928
- readonly rightToLeft: Map<object, object>;
929
- }
930
-
931
- function sameValue(
932
- left: unknown,
933
- right: unknown,
934
- seen: ComparedObjectPairs = { leftToRight: new Map(), rightToLeft: new Map() },
935
- ): boolean {
936
- if (Object.is(left, right)) return true;
937
- if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object') {
938
- return false;
939
- }
940
- const previousRight = seen.leftToRight.get(left);
941
- if (previousRight !== undefined || seen.leftToRight.has(left)) return previousRight === right;
942
- const previousLeft = seen.rightToLeft.get(right);
943
- if (previousLeft !== undefined || seen.rightToLeft.has(right)) return previousLeft === left;
944
- seen.leftToRight.set(left, right);
945
- seen.rightToLeft.set(right, left);
946
- if (ArrayBuffer.isView(left) && ArrayBuffer.isView(right)) {
947
- if (left.byteLength !== right.byteLength) return false;
948
- const leftBytes = new Uint8Array(left.buffer, left.byteOffset, left.byteLength);
949
- const rightBytes = new Uint8Array(right.buffer, right.byteOffset, right.byteLength);
950
- for (let index = 0; index < leftBytes.length; index += 1) {
951
- if (leftBytes[index] !== rightBytes[index]) return false;
952
- }
953
- return true;
954
- }
955
- if (left instanceof Map && right instanceof Map) {
956
- if (left.size !== right.size) return false;
957
- for (const [key, value] of left) {
958
- if (!right.has(key) || !sameValue(value, right.get(key), seen)) return false;
959
- }
960
- return true;
961
- }
962
- if (Array.isArray(left) && Array.isArray(right)) {
963
- if (left.length !== right.length) return false;
964
- return left.every((value, index) => sameValue(value, right[index], seen));
965
- }
966
- const leftKeys = Object.keys(left).sort();
967
- const rightKeys = Object.keys(right).sort();
968
- if (
969
- leftKeys.length !== rightKeys.length ||
970
- leftKeys.some((key, index) => key !== rightKeys[index])
971
- ) {
972
- return false;
973
- }
974
- return leftKeys.every((key) =>
975
- sameValue(
976
- (left as Record<string, unknown>)[key],
977
- (right as Record<string, unknown>)[key],
978
- seen,
979
- ),
980
- );
981
- }
982
-
983
- function validMobility(value: unknown): SceneMobility {
984
- return value === 'static' || value === 'dynamic' || value === 'unknown' ? value : 'unknown';
985
- }
986
-
987
- function validCasterEligibility(value: unknown): SceneCasterEligibility {
988
- return value === 'eligible' || value === 'ineligible' || value === 'unknown' ? value : 'unknown';
989
- }
990
-
991
- function localBoundsFact(snapshot: RenderableSnapshot): RenderSceneFact['bounds'] {
992
- const local = snapshot.localAabb;
993
- if (local === undefined) return { status: 'missing', reason: 'missing-local-aabb' };
994
- const minX = local[0] ?? Number.NaN;
995
- const minY = local[1] ?? Number.NaN;
996
- const minZ = local[2] ?? Number.NaN;
997
- const maxX = local[3] ?? Number.NaN;
998
- const maxY = local[4] ?? Number.NaN;
999
- const maxZ = local[5] ?? Number.NaN;
1000
- if (
1001
- local.length < 6 ||
1002
- ![minX, minY, minZ, maxX, maxY, maxZ].every(Number.isFinite) ||
1003
- minX > maxX ||
1004
- minY > maxY ||
1005
- minZ > maxZ
1006
- ) {
1007
- return { status: 'missing', reason: 'invalid-local-aabb' };
1008
- }
1009
- const world = snapshot.transform.world;
1010
- if (world.length < 16 || !world.slice(0, 16).every(Number.isFinite)) {
1011
- return { status: 'missing', reason: 'invalid-world-transform' };
1012
- }
1013
- const m00 = world[0] ?? 0;
1014
- const m01 = world[1] ?? 0;
1015
- const m02 = world[2] ?? 0;
1016
- const m10 = world[4] ?? 0;
1017
- const m11 = world[5] ?? 0;
1018
- const m12 = world[6] ?? 0;
1019
- const m20 = world[8] ?? 0;
1020
- const m21 = world[9] ?? 0;
1021
- const m22 = world[10] ?? 0;
1022
- const tx = world[12] ?? 0;
1023
- const ty = world[13] ?? 0;
1024
- const tz = world[14] ?? 0;
1025
- const minimum = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
1026
- const maximum = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
1027
- for (const x of [minX, maxX]) {
1028
- for (const y of [minY, maxY]) {
1029
- for (const z of [minZ, maxZ]) {
1030
- const worldX = m00 * x + m10 * y + m20 * z + tx;
1031
- const worldY = m01 * x + m11 * y + m21 * z + ty;
1032
- const worldZ = m02 * x + m12 * y + m22 * z + tz;
1033
- minimum[0] = Math.min(minimum[0] as number, worldX);
1034
- minimum[1] = Math.min(minimum[1] as number, worldY);
1035
- minimum[2] = Math.min(minimum[2] as number, worldZ);
1036
- maximum[0] = Math.max(maximum[0] as number, worldX);
1037
- maximum[1] = Math.max(maximum[1] as number, worldY);
1038
- maximum[2] = Math.max(maximum[2] as number, worldZ);
1039
- }
1040
- }
1041
- }
1042
- return {
1043
- status: 'present',
1044
- localAabb: new Float32Array([minX, minY, minZ, maxX, maxY, maxZ]),
1045
- worldAabb: new Float32Array([
1046
- minimum[0] as number,
1047
- minimum[1] as number,
1048
- minimum[2] as number,
1049
- maximum[0] as number,
1050
- maximum[1] as number,
1051
- maximum[2] as number,
1052
- ]),
1053
- };
1054
- }
1055
-
1056
- function sameMaterials(left: RenderableSnapshot, right: RenderableSnapshot): boolean {
1057
- return sameValue(left.materials, right.materials) && sameValue(left.material, right.material);
1058
- }
1059
-
1060
- function diagnosticForBounds(
1061
- snapshot: RenderableSnapshot,
1062
- slot: number,
1063
- generation: number,
1064
- bounds: RenderSceneFact['bounds'],
1065
- ): SceneFactDiagnostic | undefined {
1066
- if (bounds.status === 'present') return undefined;
1067
- return {
1068
- code: 'missing-bounds',
1069
- slot,
1070
- generation,
1071
- worldId: snapshot.worldId,
1072
- entityKey: snapshot.entityKey,
1073
- reason: bounds.reason,
1074
- };
1075
- }
1076
-
1077
- function normalizeRevision(
1078
- value: number | undefined,
1079
- previous: number,
1080
- domain: SceneFactRevisionDomain,
1081
- snapshot: RenderableSnapshot,
1082
- slot: number,
1083
- generation: number,
1084
- diagnostics: SceneFactDiagnostic[],
1085
- ): number {
1086
- if (value === undefined) return previous;
1087
- if (!Number.isInteger(value) || value < 0 || value < previous) {
1088
- diagnostics.push({
1089
- code: 'invalid-revision',
1090
- slot,
1091
- generation,
1092
- worldId: snapshot.worldId,
1093
- entityKey: snapshot.entityKey,
1094
- domain,
1095
- reason: value < previous ? 'non-monotonic' : 'expected-non-negative-integer',
1096
- });
1097
- return previous;
1098
- }
1099
- return value;
1100
- }
1101
-
1102
- function factFor(
1103
- snapshot: RenderableSnapshot,
1104
- slot: number,
1105
- generation: number,
1106
- previous: RenderSceneFact | undefined,
1107
- changedDomains: ReadonlySet<SceneFactRevisionDomain>,
1108
- diagnostics: SceneFactDiagnostic[],
1109
- emitBoundsDiagnostic: boolean,
1110
- ): RenderSceneFact {
1111
- const bounds = localBoundsFact(snapshot);
1112
- if (emitBoundsDiagnostic) {
1113
- const boundsDiagnostic = diagnosticForBounds(snapshot, slot, generation, bounds);
1114
- if (boundsDiagnostic !== undefined) diagnostics.push(boundsDiagnostic);
1115
- }
1116
- const input: RenderSceneFactInput | undefined = snapshot.sceneFact;
1117
- const previousRevisions = previous?.revisions ?? ZERO_REVISIONS;
1118
- const revisions = Object.fromEntries(
1119
- FACT_DOMAINS.map((domain) => {
1120
- const explicit = input?.revisions?.[domain];
1121
- let value = normalizeRevision(
1122
- explicit,
1123
- previousRevisions[domain],
1124
- domain,
1125
- snapshot,
1126
- slot,
1127
- generation,
1128
- diagnostics,
1129
- );
1130
- if (explicit === undefined && changedDomains.has(domain)) value += 1;
1131
- if (
1132
- explicit !== undefined &&
1133
- changedDomains.has(domain) &&
1134
- value === previousRevisions[domain]
1135
- ) {
1136
- value += 1;
1137
- }
1138
- return [domain, value];
1139
- }),
1140
- ) as unknown as SceneFactRevisions;
1141
- return {
1142
- slot,
1143
- generation,
1144
- worldId: snapshot.worldId,
1145
- entityKey: snapshot.entityKey,
1146
- bounds,
1147
- mobility: validMobility(input?.mobility),
1148
- casterEligibility:
1149
- bounds.status === 'present' ? validCasterEligibility(input?.casterEligibility) : 'unknown',
1150
- revisions,
1151
- };
1152
- }
1153
-
1154
- function changedFactDomains(
1155
- previous: RenderSceneProjectionSlot,
1156
- next: RenderableSnapshot,
1157
- ): Set<SceneFactRevisionDomain> {
1158
- const changed = new Set<SceneFactRevisionDomain>();
1159
- if (!sameFloatArray(previous.snapshot.transform.world, next.transform.world)) {
1160
- changed.add('transform');
1161
- changed.add('space');
1162
- }
1163
- if (
1164
- previous.snapshot.assetHandle !== next.assetHandle ||
1165
- !sameFloatArray(previous.snapshot.localAabb, next.localAabb)
1166
- ) {
1167
- changed.add('geometry');
1168
- changed.add('space');
1169
- }
1170
- if (
1171
- !sameFloatArray(
1172
- previous.snapshot.candidateInstanceTransforms,
1173
- next.candidateInstanceTransforms,
1174
- ) ||
1175
- !sameFloatArray(previous.snapshot.boundsWorld, next.boundsWorld) ||
1176
- !sameValue(previous.snapshot.instances, next.instances) ||
1177
- !sameValue(previous.snapshot.spriteInstances, next.spriteInstances)
1178
- ) {
1179
- changed.add('space');
1180
- }
1181
- if (!sameValue(previous.snapshot.gpuDrivenDraws, next.gpuDrivenDraws)) {
1182
- changed.add('geometry');
1183
- changed.add('batch');
1184
- }
1185
- if (!sameMaterials(previous.snapshot, next)) {
1186
- changed.add('material');
1187
- changed.add('resource');
1188
- changed.add('batch');
1189
- }
1190
- if (
1191
- !sameValue(previous.snapshot.materialBindingSources, next.materialBindingSources) ||
1192
- !sameValue(previous.snapshot.materialBindingDiagnostics, next.materialBindingDiagnostics)
1193
- ) {
1194
- changed.add('resource');
1195
- }
1196
- const previousInput = previous.snapshot.sceneFact;
1197
- const nextInput = next.sceneFact;
1198
- if (validMobility(previousInput?.mobility) !== validMobility(nextInput?.mobility)) {
1199
- changed.add('space');
1200
- changed.add('eligibility');
1201
- }
1202
- if (
1203
- validCasterEligibility(previousInput?.casterEligibility) !==
1204
- validCasterEligibility(nextInput?.casterEligibility)
1205
- ) {
1206
- changed.add('eligibility');
1207
- }
1208
- for (const domain of FACT_DOMAINS) {
1209
- const nextRevision = nextInput?.revisions?.[domain];
1210
- if (nextRevision !== undefined && nextRevision !== previous.fact.revisions[domain]) {
1211
- changed.add(domain);
1212
- }
1213
- }
1214
- return changed;
1215
- }
1216
-
1217
- function temporalProducerChanged(previous: RenderableSnapshot, next: RenderableSnapshot): boolean {
1218
- return (
1219
- !sameValue(previous.skin?.jointMatrices, next.skin?.jointMatrices) ||
1220
- !sameFloatArray(previous.morphWeights, next.morphWeights)
1221
- );
1222
- }
1223
-
1224
- /**
1225
- * Renderer-owned persistent CPU scene projection.
1226
- *
1227
- * Operations are coalesced per `(worldId, entityKey)` before stable slots are
1228
- * touched. Slots carry generations so downstream GPU residency can reject
1229
- * stale work after removal and reuse. Each slot also owns the Scene Fact used
1230
- * by later spatial, visibility, batch, and upload owners.
1231
- */
1232
- export class RenderSceneProjection {
1233
- private readonly slots: Array<ProjectionSlot | undefined> = [];
1234
- private readonly lastSubmittedSlots: Array<ProjectionSlot | undefined> = [];
1235
- private readonly generations: number[] = [];
1236
- private readonly freeSlots: number[] = [];
1237
- private readonly slotsByWorld = new Map<number, Map<number, number>>();
1238
- private readonly slotsByMaterial = new Map<number, Set<number>>();
1239
- private materialized: readonly RenderableSnapshot[] | undefined;
1240
- private slotSnapshot: readonly RenderSceneProjectionSlot[] | undefined;
1241
- private factDiagnostics: readonly SceneFactDiagnostic[] = [];
1242
- private readonly spatialIndex = new RenderSceneSpatialIndex();
1243
- private readonly dirtySinceSubmitted = new Set<number>();
1244
- private lastSubmittedVisible = new Set<string>();
1245
- private revision = 0;
1246
- private submittedEpoch = 0;
1247
-
1248
- apply(operations: readonly RenderSceneOperation[]): RenderSceneApplyResult {
1249
- const pendingByWorld = new Map<number, Map<number, PendingIdentity>>();
1250
- const pendingOrder: PendingIdentity[] = [];
1251
- const diagnostics: SceneFactDiagnostic[] = [];
1252
- let ignoredLateUpdates = 0;
1253
-
1254
- const pendingFor = (worldId: number, entityKey: number): PendingIdentity => {
1255
- let entities = pendingByWorld.get(worldId);
1256
- if (entities === undefined) {
1257
- entities = new Map<number, PendingIdentity>();
1258
- pendingByWorld.set(worldId, entities);
1259
- }
1260
- let pending = entities.get(entityKey);
1261
- if (pending !== undefined) return pending;
1262
- const initial = this.lookup(worldId, entityKey);
1263
- pending = {
1264
- worldId,
1265
- entityKey,
1266
- initial,
1267
- current: initial?.snapshot,
1268
- removed: false,
1269
- touched: false,
1270
- };
1271
- entities.set(entityKey, pending);
1272
- pendingOrder.push(pending);
1273
- return pending;
1274
- };
1275
-
1276
- const acceptsGeneration = (
1277
- operation: RenderSceneOperation,
1278
- pending: PendingIdentity,
1279
- ): boolean => {
1280
- if (operation.expectedGeneration === undefined) return true;
1281
- const actualGeneration = pending.initial?.generation;
1282
- if (actualGeneration === operation.expectedGeneration) return true;
1283
- const diagnostic = {
1284
- code: 'stale-generation',
1285
- worldId: operation.kind === 'create' ? operation.snapshot.worldId : operation.worldId,
1286
- entityKey: operation.kind === 'create' ? operation.snapshot.entityKey : operation.entityKey,
1287
- expectedGeneration: operation.expectedGeneration,
1288
- reason: 'operation-generation-does-not-match-live-slot',
1289
- ...(actualGeneration === undefined ? {} : { actualGeneration }),
1290
- ...(pending.initial === undefined
1291
- ? {}
1292
- : { slot: pending.initial.slot, generation: pending.initial.generation }),
1293
- } satisfies SceneFactDiagnostic;
1294
- diagnostics.push(diagnostic);
1295
- return false;
1296
- };
1297
-
1298
- for (const operation of operations) {
1299
- if (operation.kind === 'create') {
1300
- const { worldId, entityKey } = operation.snapshot;
1301
- const pending = pendingFor(worldId, entityKey);
1302
- if (!acceptsGeneration(operation, pending)) continue;
1303
- pending.current = ownSnapshot(operation.snapshot);
1304
- pending.touched = true;
1305
- continue;
1306
- }
1307
- const pending = pendingFor(operation.worldId, operation.entityKey);
1308
- if (!acceptsGeneration(operation, pending)) {
1309
- if (operation.kind === 'update-transform') ignoredLateUpdates += 1;
1310
- continue;
1311
- }
1312
- if (operation.kind === 'remove') {
1313
- pending.current = undefined;
1314
- pending.removed = true;
1315
- pending.touched = true;
1316
- continue;
1317
- }
1318
- if (pending.current === undefined) {
1319
- ignoredLateUpdates += 1;
1320
- continue;
1321
- }
1322
- pending.touched = true;
1323
- pending.current = withWorld(pending.current, operation.world);
1324
- }
1325
-
1326
- let created = 0;
1327
- let updated = 0;
1328
- let removed = 0;
1329
- let recreated = 0;
1330
- const createdSlots: RenderSceneProjectionSlot[] = [];
1331
- const updatedSlots: RenderSceneProjectionSlot[] = [];
1332
- const removedSlots: RenderSceneProjectionRecord[] = [];
1333
- const recreatedSlots: RenderSceneProjectionSlot[] = [];
1334
- const factDeltas: RenderSceneFactDelta[] = [];
1335
- for (const pending of pendingOrder) {
1336
- if (!pending.touched) continue;
1337
- if (pending.initial === undefined) {
1338
- if (pending.current === undefined) continue;
1339
- const createdSlot = this.allocate(pending.current, diagnostics);
1340
- createdSlots.push(createdSlot);
1341
- factDeltas.push({
1342
- slot: createdSlot.slot,
1343
- generation: createdSlot.generation,
1344
- changedDomains: FACT_DOMAINS,
1345
- previous: undefined,
1346
- current: createdSlot.fact,
1347
- });
1348
- this.dirtySinceSubmitted.add(createdSlot.slot);
1349
- created += 1;
1350
- continue;
1351
- }
1352
- if (pending.current === undefined) {
1353
- this.release(pending.initial);
1354
- this.dirtySinceSubmitted.add(pending.initial.slot);
1355
- removedSlots.push(pending.initial);
1356
- removed += 1;
1357
- continue;
1358
- }
1359
- if (pending.removed) {
1360
- this.release(pending.initial);
1361
- const recreatedSlot = this.allocate(pending.current, diagnostics);
1362
- recreatedSlots.push(recreatedSlot);
1363
- factDeltas.push({
1364
- slot: recreatedSlot.slot,
1365
- generation: recreatedSlot.generation,
1366
- changedDomains: FACT_DOMAINS,
1367
- previous: pending.initial.fact,
1368
- current: recreatedSlot.fact,
1369
- });
1370
- this.dirtySinceSubmitted.add(recreatedSlot.slot);
1371
- recreated += 1;
1372
- continue;
1373
- }
1374
- const domains = changedFactDomains(pending.initial, pending.current);
1375
- const currentFact = factFor(
1376
- pending.current,
1377
- pending.initial.slot,
1378
- pending.initial.generation,
1379
- pending.initial.fact,
1380
- domains,
1381
- diagnostics,
1382
- domains.size > 0,
1383
- );
1384
- const updatedSlot: ProjectionSlot = {
1385
- ...pending.initial,
1386
- snapshot: pending.current,
1387
- fact: currentFact,
1388
- };
1389
- this.unindexMaterials(pending.initial);
1390
- this.slots[pending.initial.slot] = updatedSlot;
1391
- this.indexMaterials(updatedSlot);
1392
- updatedSlots.push(updatedSlot);
1393
- if (domains.size > 0) {
1394
- factDeltas.push({
1395
- slot: updatedSlot.slot,
1396
- generation: updatedSlot.generation,
1397
- changedDomains: FACT_DOMAINS.filter((domain) => domains.has(domain)),
1398
- previous: pending.initial.fact,
1399
- current: currentFact,
1400
- });
1401
- }
1402
- if (domains.size > 0 || temporalProducerChanged(pending.initial.snapshot, pending.current)) {
1403
- this.dirtySinceSubmitted.add(updatedSlot.slot);
1404
- }
1405
- updated += 1;
1406
- }
1407
-
1408
- this.factDiagnostics = diagnostics;
1409
- const changed = created + updated + removed + recreated > 0;
1410
- const result: RenderSceneApplyResult = {
1411
- created,
1412
- updated,
1413
- removed,
1414
- recreated,
1415
- ignoredLateUpdates,
1416
- createdSlots,
1417
- updatedSlots,
1418
- removedSlots,
1419
- recreatedSlots,
1420
- factDeltas,
1421
- diagnostics,
1422
- };
1423
- if (!changed) return result;
1424
- this.revision += 1;
1425
- this.invalidateSnapshots();
1426
- return {
1427
- ...result,
1428
- spatialIndex: this.spatialIndex.patch(
1429
- [...createdSlots, ...updatedSlots, ...recreatedSlots],
1430
- removedSlots,
1431
- ),
1432
- };
1433
- }
1434
-
1435
- materialize(): readonly RenderableSnapshot[] {
1436
- if (this.materialized !== undefined) return this.materialized;
1437
- const snapshots: RenderableSnapshot[] = [];
1438
- for (const slot of this.slots) {
1439
- if (slot !== undefined) snapshots.push(slot.snapshot);
1440
- }
1441
- this.materialized = Object.freeze(snapshots);
1442
- return this.materialized;
1443
- }
1444
-
1445
- slotsSnapshot(): readonly RenderSceneProjectionSlot[] {
1446
- if (this.slotSnapshot !== undefined) return this.slotSnapshot;
1447
- const records: RenderSceneProjectionSlot[] = [];
1448
- for (const slot of this.slots) {
1449
- if (slot !== undefined) records.push(slot);
1450
- }
1451
- this.slotSnapshot = Object.freeze(records);
1452
- return this.slotSnapshot;
1453
- }
1454
-
1455
- lastSubmittedSlotByIndex(slot: number): RenderSceneProjectionSlot | undefined {
1456
- return this.lastSubmittedSlots[slot];
1457
- }
1458
-
1459
- temporalSnapshotBySlot(slot: number): RenderableTemporalSnapshot | undefined {
1460
- const current = this.slots[slot];
1461
- return current === undefined ? undefined : this.temporalSnapshot(current);
1462
- }
1463
-
1464
- withTemporal(snapshot: RenderableSnapshot): RenderableSnapshot {
1465
- const slot = this.lookup(snapshot.worldId, snapshot.entityKey);
1466
- return slot === undefined ? snapshot : { ...snapshot, temporal: this.temporalSnapshot(slot) };
1467
- }
1468
-
1469
- wasLastSubmittedVisible(slot: number, generation: number): boolean {
1470
- return this.lastSubmittedVisible.has(submittedIdentity(slot, generation));
1471
- }
1472
-
1473
- captureSubmission(
1474
- visible: readonly Pick<RenderableSnapshot, 'worldId' | 'entityKey'>[],
1475
- ): RenderSceneSubmissionCapture {
1476
- const visibleSlots = new Set<string>();
1477
- for (const snapshot of visible) {
1478
- const slot = this.lookup(snapshot.worldId, snapshot.entityKey);
1479
- if (slot !== undefined) visibleSlots.add(submittedIdentity(slot.slot, slot.generation));
1480
- }
1481
- return {
1482
- revision: this.revision,
1483
- slots: [...this.dirtySinceSubmitted].map((slot) => ({ slot, current: this.slots[slot] })),
1484
- visible: visibleSlots,
1485
- };
1486
- }
1487
-
1488
- commitSubmission(capture: RenderSceneSubmissionCapture): RenderSceneSubmissionDelta {
1489
- if (capture.revision !== this.revision) {
1490
- throw new RangeError('render scene changed while its temporal submission was active');
1491
- }
1492
- for (const update of capture.slots) {
1493
- this.lastSubmittedSlots[update.slot] = update.current;
1494
- this.dirtySinceSubmitted.delete(update.slot);
1495
- }
1496
- this.lastSubmittedVisible = new Set(capture.visible);
1497
- this.submittedEpoch += 1;
1498
- this.invalidateSnapshots();
1499
- return {
1500
- epoch: this.submittedEpoch,
1501
- slots: capture.slots.map((update) => update.slot),
1502
- };
1503
- }
1504
-
1505
- /** O(1) stable-slot lookup for delta owners; avoids rescanning slotsSnapshot. */
1506
- slotByIndex(slot: number): RenderSceneProjectionSlot | undefined {
1507
- return this.slots[slot];
1508
- }
1509
-
1510
- has(worldId: number, entityKey: number): boolean {
1511
- return this.lookup(worldId, entityKey) !== undefined;
1512
- }
1513
-
1514
- record(worldId: number, entityKey: number): RenderSceneProjectionRecord | undefined {
1515
- const slot = this.lookup(worldId, entityKey);
1516
- if (slot === undefined) return undefined;
1517
- return { slot: slot.slot, generation: slot.generation, worldId, entityKey };
1518
- }
1519
-
1520
- snapshot(worldId: number, entityKey: number): RenderableSnapshot | undefined {
1521
- return this.lookup(worldId, entityKey)?.snapshot;
1522
- }
1523
-
1524
- slotsForMaterial(materialHandle: number): readonly RenderSceneProjectionSlot[] {
1525
- const slots = this.slotsByMaterial.get(materialHandle);
1526
- if (slots === undefined) return [];
1527
- const records: RenderSceneProjectionSlot[] = [];
1528
- for (const slot of slots) {
1529
- const record = this.slots[slot];
1530
- if (record !== undefined) records.push(record);
1531
- }
1532
- return records;
1533
- }
1534
-
1535
- querySpatialIndex(
1536
- worldAabb: Float32Array,
1537
- options: { readonly verifyAgainstBruteForce?: boolean } = {},
1538
- ): SpatialQueryResult {
1539
- return this.spatialIndex.query(worldAabb, options.verifyAgainstBruteForce === true);
1540
- }
1541
-
1542
- replaceCurrent(snapshots: readonly RenderableSnapshot[]): RenderSceneApplyResult {
1543
- const incoming = new Set(
1544
- snapshots.map((snapshot) => `${snapshot.worldId}:${snapshot.entityKey}`),
1545
- );
1546
- const operations: RenderSceneOperation[] = [];
1547
- for (const slot of this.slots) {
1548
- if (slot === undefined || incoming.has(`${slot.worldId}:${slot.entityKey}`)) continue;
1549
- operations.push({
1550
- kind: 'remove',
1551
- worldId: slot.worldId,
1552
- entityKey: slot.entityKey,
1553
- expectedGeneration: slot.generation,
1554
- });
1555
- }
1556
- for (const snapshot of snapshots) {
1557
- const live = this.lookup(snapshot.worldId, snapshot.entityKey);
1558
- operations.push({
1559
- kind: 'create',
1560
- snapshot,
1561
- ...(live === undefined ? {} : { expectedGeneration: live.generation }),
1562
- });
1563
- }
1564
- return this.apply(operations);
1565
- }
1566
-
1567
- reset(snapshots: readonly RenderableSnapshot[]): void {
1568
- this.slots.length = 0;
1569
- this.generations.length = 0;
1570
- this.freeSlots.length = 0;
1571
- this.slotsByWorld.clear();
1572
- this.slotsByMaterial.clear();
1573
- this.lastSubmittedSlots.length = 0;
1574
- this.lastSubmittedVisible.clear();
1575
- this.dirtySinceSubmitted.clear();
1576
- this.submittedEpoch = 0;
1577
- const diagnostics: SceneFactDiagnostic[] = [];
1578
- for (const snapshot of snapshots) this.allocate(ownSnapshot(snapshot), diagnostics);
1579
- for (const slot of this.slots) {
1580
- if (slot !== undefined) this.dirtySinceSubmitted.add(slot.slot);
1581
- }
1582
- this.factDiagnostics = diagnostics;
1583
- this.invalidateSnapshots();
1584
- this.spatialIndex.replace(this.slotsSnapshot());
1585
- this.revision += 1;
1586
- }
1587
-
1588
- inspect(): RenderSceneProjectionInspection {
1589
- const current: RenderSceneProjectionRecord[] = [];
1590
- const lastSubmitted: RenderSceneProjectionRecord[] = [];
1591
- for (const slot of this.slots) {
1592
- if (slot === undefined) continue;
1593
- current.push({
1594
- slot: slot.slot,
1595
- generation: slot.generation,
1596
- worldId: slot.worldId,
1597
- entityKey: slot.entityKey,
1598
- });
1599
- }
1600
- for (const slot of this.lastSubmittedSlots) {
1601
- if (slot === undefined) continue;
1602
- lastSubmitted.push({
1603
- slot: slot.slot,
1604
- generation: slot.generation,
1605
- worldId: slot.worldId,
1606
- entityKey: slot.entityKey,
1607
- });
1608
- }
1609
- return {
1610
- current,
1611
- lastSubmitted: { epoch: this.submittedEpoch, records: lastSubmitted },
1612
- slotCapacity: this.slots.length,
1613
- freeSlots: this.freeSlots.length,
1614
- factDiagnostics: this.factDiagnostics,
1615
- spatialIndex: this.spatialIndex.inspect(),
1616
- };
1617
- }
1618
-
1619
- private lookup(worldId: number, entityKey: number): ProjectionSlot | undefined {
1620
- const slot = this.slotsByWorld.get(worldId)?.get(entityKey);
1621
- return slot === undefined ? undefined : this.slots[slot];
1622
- }
1623
-
1624
- private temporalSnapshot(slot: ProjectionSlot): RenderableTemporalSnapshot {
1625
- const submitted = this.lastSubmittedSlots[slot.slot];
1626
- const sameGeneration = submitted?.generation === slot.generation;
1627
- const wasVisible =
1628
- sameGeneration &&
1629
- this.lastSubmittedVisible.has(submittedIdentity(slot.slot, slot.generation));
1630
- const changed =
1631
- sameGeneration && submitted !== undefined
1632
- ? changedFactDomains(submitted, slot.snapshot)
1633
- : new Set<SceneFactRevisionDomain>();
1634
- const reasons: RenderableReactiveReason[] = [];
1635
- if (!sameGeneration) {
1636
- reasons.push(submitted === undefined ? 'new-slot' : 'generation-reuse');
1637
- } else if (!wasVisible) {
1638
- reasons.push('reentered');
1639
- }
1640
- if (changed.has('geometry')) reasons.push('geometry-revision');
1641
- if (changed.has('material') || changed.has('resource')) reasons.push('material-revision');
1642
- const exactSkin =
1643
- slot.snapshot.skin === undefined ||
1644
- (sameGeneration &&
1645
- submitted?.snapshot.skin !== undefined &&
1646
- submitted.snapshot.skin.jointCount === slot.snapshot.skin.jointCount &&
1647
- submitted.snapshot.skin.jointMatrices.length === slot.snapshot.skin.jointMatrices.length);
1648
- const exactMorph =
1649
- slot.snapshot.morphWeights === undefined ||
1650
- (sameGeneration &&
1651
- submitted?.snapshot.morphWeights !== undefined &&
1652
- submitted.snapshot.morphWeights.length === slot.snapshot.morphWeights.length);
1653
- if (!exactSkin) reasons.push('skinning-deformation');
1654
- if (!exactMorph) reasons.push('morph-deformation');
1655
- const seedCurrent =
1656
- !sameGeneration ||
1657
- !wasVisible ||
1658
- changed.has('geometry') ||
1659
- changed.has('material') ||
1660
- changed.has('resource') ||
1661
- !exactSkin ||
1662
- !exactMorph;
1663
- const previous = seedCurrent || submitted === undefined ? slot.snapshot : submitted.snapshot;
1664
- return {
1665
- previousEpoch: seedCurrent ? undefined : this.submittedEpoch,
1666
- previousSource: seedCurrent ? 'current-seed' : 'last-submitted',
1667
- reactive: reasons.length > 0,
1668
- reactiveReasons: reasons,
1669
- previousTransform: previous.transform,
1670
- previousInstances: previous.instances,
1671
- previousSkin: previous.skin,
1672
- previousMorphWeights: previous.morphWeights,
1673
- };
1674
- }
1675
-
1676
- private allocate(
1677
- snapshot: RenderableSnapshot,
1678
- diagnostics: SceneFactDiagnostic[],
1679
- ): ProjectionSlot {
1680
- const reused = this.freeSlots.pop();
1681
- const slot = reused ?? this.slots.length;
1682
- const generation = reused === undefined ? 0 : (this.generations[slot] ?? -1) + 1;
1683
- const fact = factFor(snapshot, slot, generation, undefined, new Set(), diagnostics, true);
1684
- const record: ProjectionSlot = {
1685
- slot,
1686
- generation,
1687
- worldId: snapshot.worldId,
1688
- entityKey: snapshot.entityKey,
1689
- snapshot,
1690
- fact,
1691
- };
1692
- this.generations[slot] = generation;
1693
- this.slots[slot] = record;
1694
- let entities = this.slotsByWorld.get(snapshot.worldId);
1695
- if (entities === undefined) {
1696
- entities = new Map<number, number>();
1697
- this.slotsByWorld.set(snapshot.worldId, entities);
1698
- }
1699
- entities.set(snapshot.entityKey, slot);
1700
- this.indexMaterials(record);
1701
- return record;
1702
- }
1703
-
1704
- private release(record: ProjectionSlot): void {
1705
- this.slots[record.slot] = undefined;
1706
- this.unindexMaterials(record);
1707
- const entities = this.slotsByWorld.get(record.worldId);
1708
- entities?.delete(record.entityKey);
1709
- if (entities?.size === 0) this.slotsByWorld.delete(record.worldId);
1710
- this.freeSlots.push(record.slot);
1711
- }
1712
-
1713
- private indexMaterials(record: ProjectionSlot): void {
1714
- for (const material of record.snapshot.materials) {
1715
- const handle = material.materialHandle ?? 0;
1716
- let slots = this.slotsByMaterial.get(handle);
1717
- if (slots === undefined) {
1718
- slots = new Set();
1719
- this.slotsByMaterial.set(handle, slots);
1720
- }
1721
- slots.add(record.slot);
1722
- }
1723
- }
1724
-
1725
- private unindexMaterials(record: ProjectionSlot): void {
1726
- for (const material of record.snapshot.materials) {
1727
- const handle = material.materialHandle ?? 0;
1728
- const slots = this.slotsByMaterial.get(handle);
1729
- slots?.delete(record.slot);
1730
- if (slots?.size === 0) this.slotsByMaterial.delete(handle);
1731
- }
1732
- }
1733
-
1734
- private invalidateSnapshots(): void {
1735
- this.materialized = undefined;
1736
- this.slotSnapshot = undefined;
1737
- }
1738
- }