@forgeax/engine-render 0.1.28 → 0.1.29

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 (642) hide show
  1. package/README.md +627 -124
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/dynamic-geometry-host.d.ts +21 -0
  5. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  7. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +3 -1
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  11. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  12. package/dist/assembly/host-contract.d.ts +8 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +7 -0
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material-shader-policy.d.ts +3 -1
  17. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  18. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  19. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  20. package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
  21. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  22. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  23. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  24. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  25. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  26. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  27. package/dist/assembly/renderer-helpers.d.ts +3 -0
  28. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  29. package/dist/assembly/renderer-inspection.d.ts +4 -0
  30. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  31. package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
  32. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  33. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  34. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  35. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  36. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  37. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  38. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  41. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  42. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +7 -3
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  46. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  47. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  48. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  49. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  50. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  51. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  52. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  53. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  54. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  55. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  56. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  57. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  58. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  59. package/dist/authoring.mjs +2 -2
  60. package/dist/{chunk-JAASCMXA.mjs → chunk-33XZFTQU.mjs} +245 -39
  61. package/dist/chunk-33XZFTQU.mjs.map +1 -0
  62. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  63. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  64. package/dist/{chunk-J52NMQKR.mjs → chunk-BQVQOQJH.mjs} +1086 -838
  65. package/dist/chunk-BQVQOQJH.mjs.map +1 -0
  66. package/dist/{chunk-IQMKJLNU.mjs → chunk-BTWH7BP4.mjs} +386 -17
  67. package/dist/chunk-BTWH7BP4.mjs.map +1 -0
  68. package/dist/{chunk-MBU4ZVE7.mjs → chunk-FUODTTIA.mjs} +3921 -671
  69. package/dist/chunk-FUODTTIA.mjs.map +1 -0
  70. package/dist/{chunk-MYJ5RPJO.mjs → chunk-JQTSEI3Z.mjs} +3 -3
  71. package/dist/{chunk-MYJ5RPJO.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
  72. package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
  73. package/dist/chunk-NICXSHAT.mjs.map +1 -0
  74. package/dist/{chunk-J6KACNOH.mjs → chunk-NRNXBLIJ.mjs} +577 -7
  75. package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
  76. package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
  77. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  78. package/dist/{chunk-VSL23LZE.mjs → chunk-S4DNKQYQ.mjs} +1117 -445
  79. package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
  80. package/dist/components/camera.d.ts +62 -2
  81. package/dist/components/camera.d.ts.map +1 -1
  82. package/dist/components/index.d.ts +1 -0
  83. package/dist/components/index.d.ts.map +1 -1
  84. package/dist/components/instances.d.ts +6 -20
  85. package/dist/components/instances.d.ts.map +1 -1
  86. package/dist/components/scene-instance.d.ts +2 -1
  87. package/dist/components/scene-instance.d.ts.map +1 -1
  88. package/dist/components/screen-space-reflection.d.ts +14 -0
  89. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  90. package/dist/construct-renderer.mjs +12888 -7025
  91. package/dist/construct-renderer.mjs.map +1 -1
  92. package/dist/device/gpu-residency.d.ts +1 -12
  93. package/dist/device/gpu-residency.d.ts.map +1 -1
  94. package/dist/environment/background.d.ts +6 -0
  95. package/dist/environment/background.d.ts.map +1 -0
  96. package/dist/errors/gpu-driven.d.ts +6 -3
  97. package/dist/errors/gpu-driven.d.ts.map +1 -1
  98. package/dist/errors/render.d.ts +7 -4
  99. package/dist/errors/render.d.ts.map +1 -1
  100. package/dist/extract/camera.d.ts.map +1 -1
  101. package/dist/extract/gpu-driven.d.ts +33 -3
  102. package/dist/extract/gpu-driven.d.ts.map +1 -1
  103. package/dist/features/host.d.ts +23 -1
  104. package/dist/features/host.d.ts.map +1 -1
  105. package/dist/features/noise-texture.d.ts +17 -0
  106. package/dist/features/noise-texture.d.ts.map +1 -0
  107. package/dist/features/plan.d.ts +83 -2
  108. package/dist/features/plan.d.ts.map +1 -1
  109. package/dist/features/prepared-gpu-work.d.ts +37 -4
  110. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  111. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  112. package/dist/features/prepared-graphics.d.ts +5 -0
  113. package/dist/features/prepared-graphics.d.ts.map +1 -1
  114. package/dist/features/render-graph-compute.d.ts +5 -3
  115. package/dist/features/render-graph-compute.d.ts.map +1 -1
  116. package/dist/features/render-graph-contribution.d.ts +11 -3
  117. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  118. package/dist/features/render-graph-raster.d.ts +19 -3
  119. package/dist/features/render-graph-raster.d.ts.map +1 -1
  120. package/dist/features/types.d.ts +11 -0
  121. package/dist/features/types.d.ts.map +1 -1
  122. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  123. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  124. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  125. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  126. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  127. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  128. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  129. package/dist/gpu-driven/production-raster.d.ts +144 -23
  130. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  131. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  132. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  133. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  134. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  135. package/dist/gpu-scene-schema.d.ts +2 -8
  136. package/dist/gpu-scene-schema.d.ts.map +1 -1
  137. package/dist/gpu-scene.d.ts +14 -0
  138. package/dist/gpu-scene.d.ts.map +1 -1
  139. package/dist/gpu-texture-usage.d.ts +1 -0
  140. package/dist/gpu-texture-usage.d.ts.map +1 -1
  141. package/dist/hdrp-buffers.d.ts +6 -0
  142. package/dist/hdrp-buffers.d.ts.map +1 -1
  143. package/dist/ibl/frame-resources.d.ts +8 -0
  144. package/dist/ibl/frame-resources.d.ts.map +1 -0
  145. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  146. package/dist/index.d.ts +18 -8
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.mjs +8 -8
  149. package/dist/inspection-types.d.ts +164 -0
  150. package/dist/inspection-types.d.ts.map +1 -1
  151. package/dist/instances-derived-bounds.d.ts +11 -0
  152. package/dist/instances-derived-bounds.d.ts.map +1 -1
  153. package/dist/instances.d.ts +89 -44
  154. package/dist/instances.d.ts.map +1 -1
  155. package/dist/internal.d.ts +3 -0
  156. package/dist/internal.d.ts.map +1 -1
  157. package/dist/internal.mjs +117 -9
  158. package/dist/internal.mjs.map +1 -1
  159. package/dist/lifecycle.d.ts +2 -1
  160. package/dist/lifecycle.d.ts.map +1 -1
  161. package/dist/material-row.d.ts +5 -0
  162. package/dist/material-row.d.ts.map +1 -0
  163. package/dist/materials.d.ts +15 -0
  164. package/dist/materials.d.ts.map +1 -1
  165. package/dist/pbr-pipeline.d.ts +21 -5
  166. package/dist/pbr-pipeline.d.ts.map +1 -1
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  169. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  170. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  171. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  172. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  173. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  174. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  175. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  176. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  177. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  178. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  179. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  180. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  181. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  182. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  183. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  184. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  185. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  186. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  187. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  188. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  189. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  190. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  191. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  192. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  193. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  194. package/dist/pipeline/standard-output/types.d.ts +39 -0
  195. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  196. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  197. package/dist/pipeline/standard-post.d.ts +2 -2
  198. package/dist/pipeline/standard-post.d.ts.map +1 -1
  199. package/dist/pipeline-builder.d.ts +2 -1
  200. package/dist/pipeline-builder.d.ts.map +1 -1
  201. package/dist/pipeline-spec-types.d.ts +4 -0
  202. package/dist/pipeline-spec-types.d.ts.map +1 -1
  203. package/dist/pipeline-spec.d.ts +1 -9
  204. package/dist/pipeline-spec.d.ts.map +1 -1
  205. package/dist/points-lines/standard-owner.d.ts +1 -1
  206. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  207. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  208. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  209. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  210. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  211. package/dist/record/frame-lighting.d.ts +3 -3
  212. package/dist/record/frame-lighting.d.ts.map +1 -1
  213. package/dist/record/frame-snapshot.d.ts +106 -5
  214. package/dist/record/frame-snapshot.d.ts.map +1 -1
  215. package/dist/record/frame-targets.d.ts.map +1 -1
  216. package/dist/record/frame.d.ts +39 -4
  217. package/dist/record/frame.d.ts.map +1 -1
  218. package/dist/record/main-pass-geometry.d.ts +7 -8
  219. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  220. package/dist/record/main-pass-material.d.ts +38 -1
  221. package/dist/record/main-pass-material.d.ts.map +1 -1
  222. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  223. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  224. package/dist/record/main-pass.d.ts +12 -2
  225. package/dist/record/main-pass.d.ts.map +1 -1
  226. package/dist/record/mesh-ssbo.d.ts +15 -6
  227. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  228. package/dist/record/prepared-material-bindings.d.ts +19 -0
  229. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  230. package/dist/record/recovery-pipeline.d.ts +2 -9
  231. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  232. package/dist/record/render-context.d.ts +74 -26
  233. package/dist/record/render-context.d.ts.map +1 -1
  234. package/dist/record/shadow-pass.d.ts +62 -7
  235. package/dist/record/shadow-pass.d.ts.map +1 -1
  236. package/dist/record/skybox-post-pass.d.ts +1 -1
  237. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  238. package/dist/record/typed-frame-graph.d.ts +35 -7
  239. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  240. package/dist/record/view-ubo.d.ts +1 -0
  241. package/dist/record/view-ubo.d.ts.map +1 -1
  242. package/dist/recovery/render-system-candidate.d.ts +10 -2
  243. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  244. package/dist/recovery/render-system-roots.d.ts +11 -0
  245. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  246. package/dist/recovery/types.d.ts +76 -0
  247. package/dist/recovery/types.d.ts.map +1 -0
  248. package/dist/reflection/record-owner.d.ts +0 -2
  249. package/dist/reflection/record-owner.d.ts.map +1 -1
  250. package/dist/render-contract.d.ts +173 -30
  251. package/dist/render-contract.d.ts.map +1 -1
  252. package/dist/render-graph-primitives.d.ts +1 -0
  253. package/dist/render-graph-primitives.d.ts.map +1 -1
  254. package/dist/render-pipeline.d.ts +64 -5
  255. package/dist/render-pipeline.d.ts.map +1 -1
  256. package/dist/render-system-extract-tail.d.ts +7 -5
  257. package/dist/render-system-extract-tail.d.ts.map +1 -1
  258. package/dist/render-system-extract.d.ts +101 -41
  259. package/dist/render-system-extract.d.ts.map +1 -1
  260. package/dist/render-system-projections.d.ts +22 -0
  261. package/dist/render-system-projections.d.ts.map +1 -0
  262. package/dist/render-system.d.ts +27 -77
  263. package/dist/render-system.d.ts.map +1 -1
  264. package/dist/scene/render-scene-types.d.ts +14 -7
  265. package/dist/scene/render-scene-types.d.ts.map +1 -1
  266. package/dist/scene/render-scene.d.ts +29 -11
  267. package/dist/scene/render-scene.d.ts.map +1 -1
  268. package/dist/scene/shadow-visibility.d.ts +5 -0
  269. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  270. package/dist/ssr/admission.d.ts +70 -1
  271. package/dist/ssr/admission.d.ts.map +1 -1
  272. package/dist/ssr/compose.d.ts +13 -0
  273. package/dist/ssr/compose.d.ts.map +1 -0
  274. package/dist/ssr/errors.d.ts +35 -0
  275. package/dist/ssr/errors.d.ts.map +1 -1
  276. package/dist/ssr/graph.d.ts +60 -0
  277. package/dist/ssr/graph.d.ts.map +1 -0
  278. package/dist/ssr/history.d.ts +97 -0
  279. package/dist/ssr/history.d.ts.map +1 -0
  280. package/dist/ssr/hiz.d.ts +37 -0
  281. package/dist/ssr/hiz.d.ts.map +1 -0
  282. package/dist/ssr/inspection.d.ts +42 -0
  283. package/dist/ssr/inspection.d.ts.map +1 -0
  284. package/dist/ssr/resources.d.ts +58 -0
  285. package/dist/ssr/resources.d.ts.map +1 -0
  286. package/dist/ssr/temporal.d.ts +38 -0
  287. package/dist/ssr/temporal.d.ts.map +1 -0
  288. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  289. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  290. package/dist/systems/skin-palette-types.d.ts +15 -0
  291. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  292. package/dist/systems/transparent-dispatch.d.ts +9 -0
  293. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  294. package/dist/targets/material-source.d.ts +7 -0
  295. package/dist/targets/material-source.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts +7 -0
  297. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  298. package/dist/temporal/gpu.d.ts +8 -0
  299. package/dist/temporal/gpu.d.ts.map +1 -1
  300. package/dist/temporal/history.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +6 -6
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts +2 -1
  304. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  305. package/dist/temporal/temporal-view.d.ts +2 -0
  306. package/dist/temporal/temporal-view.d.ts.map +1 -1
  307. package/dist/typed-render-graph-primitives.d.ts +35 -1
  308. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  309. package/dist/typed-shadow-passes.d.ts +3 -1
  310. package/dist/typed-shadow-passes.d.ts.map +1 -1
  311. package/dist/volume/temporal.d.ts +6 -0
  312. package/dist/volume/temporal.d.ts.map +1 -1
  313. package/package.json +21 -20
  314. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  315. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  316. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  317. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  318. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  319. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  320. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  321. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  322. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  323. package/src/__tests__/factory-contract.integration.test.ts +67 -8
  324. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  325. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  326. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  327. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  328. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  329. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  330. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  331. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  332. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  333. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
  334. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  335. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  336. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
  337. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
  338. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
  339. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  340. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  341. package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
  342. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  343. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  344. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  345. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  346. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  347. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  348. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  349. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  350. package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
  351. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
  352. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  353. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  354. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  355. package/src/__tests__/gpu-scene.unit.test.ts +559 -33
  356. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  357. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  358. package/src/__tests__/instances-store.unit.test.ts +242 -39
  359. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  360. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  361. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  362. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  363. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  364. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  365. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  366. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  367. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  368. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  369. package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
  370. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  371. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  372. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  373. package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
  374. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  375. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  376. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  378. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
  379. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  380. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  381. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  382. package/src/__tests__/public-surface.test-d.ts +3 -0
  383. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  384. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
  385. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
  386. package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
  387. package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
  388. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  389. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  390. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  391. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  392. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  393. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  394. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  395. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  396. package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
  397. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  398. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  399. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  400. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  401. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +60 -0
  402. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  403. package/src/__tests__/shader-manifest-fixture.ts +39 -0
  404. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  405. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  406. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  407. package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
  408. package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
  409. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  410. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  411. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  412. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  413. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
  414. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
  415. package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
  416. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  417. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  418. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  419. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  420. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  421. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  422. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  423. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  424. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  425. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  426. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  427. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  428. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  429. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  430. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  431. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  432. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  433. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  434. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  435. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  436. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  437. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  438. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
  439. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  440. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  441. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  442. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  443. package/src/__tests__/standard-output.browser.test.ts +15 -0
  444. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  445. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
  446. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  447. package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
  448. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  449. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  450. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  451. package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
  452. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  453. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
  454. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  455. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  456. package/src/__tests__/taa-stability-feedback.ts +341 -0
  457. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  458. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  459. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  460. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  461. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  462. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  463. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  464. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  465. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  466. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  467. package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
  468. package/src/assembly/dynamic-geometry-host.ts +48 -0
  469. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  470. package/src/assembly/factory.ts +4 -0
  471. package/src/assembly/gpu-driven-owner.ts +29 -0
  472. package/src/assembly/host-contract.ts +10 -0
  473. package/src/assembly/material/assembly.ts +38 -0
  474. package/src/assembly/material-shader-policy.ts +71 -28
  475. package/src/assembly/recovery/failure-location.ts +62 -0
  476. package/src/assembly/recovery/renderer-recover.ts +19 -17
  477. package/src/assembly/renderer-facade.ts +12 -0
  478. package/src/assembly/renderer-feature-inspection.ts +13 -0
  479. package/src/assembly/renderer-frame-transaction.ts +63 -0
  480. package/src/assembly/renderer-helpers.ts +26 -0
  481. package/src/assembly/renderer-inspection.ts +6 -0
  482. package/src/assembly/shader-prewarm-policy.ts +32 -0
  483. package/src/assembly/skin-palette-owner.ts +21 -0
  484. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  485. package/src/assembly/webgpu-device-loss.ts +75 -0
  486. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  487. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  488. package/src/assembly/webgpu-ready.ts +142 -121
  489. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  490. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  491. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  492. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  493. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  494. package/src/assembly/webgpu-renderer.ts +666 -652
  495. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  496. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  497. package/src/components/camera.ts +287 -7
  498. package/src/components/index.ts +1 -0
  499. package/src/components/instances.ts +45 -18
  500. package/src/components/scene-instance.ts +2 -1
  501. package/src/components/screen-space-reflection.ts +21 -0
  502. package/src/components/sprite-animation.ts +2 -2
  503. package/src/components/sprite-instances.ts +1 -1
  504. package/src/device/gpu-residency.ts +34 -31
  505. package/src/environment/background.ts +263 -0
  506. package/src/errors/gpu-driven.ts +39 -5
  507. package/src/errors/render.ts +27 -3
  508. package/src/extract/camera.ts +26 -1
  509. package/src/extract/gpu-driven.ts +185 -10
  510. package/src/features/host.ts +237 -19
  511. package/src/features/noise-texture.ts +91 -0
  512. package/src/features/plan.ts +553 -24
  513. package/src/features/prepared-gpu-work.ts +631 -49
  514. package/src/features/prepared-graphics-store.ts +31 -0
  515. package/src/features/prepared-graphics.ts +5 -0
  516. package/src/features/render-graph-compute.ts +41 -8
  517. package/src/features/render-graph-contribution.ts +141 -3
  518. package/src/features/render-graph-raster.ts +143 -30
  519. package/src/features/types.ts +11 -0
  520. package/src/fullscreen-post-process-pass.ts +3 -0
  521. package/src/gpu-driven/batch-topology.ts +424 -102
  522. package/src/gpu-driven/pbr-program.ts +31 -0
  523. package/src/gpu-driven/prepared-draw.ts +29 -4
  524. package/src/gpu-driven/production-raster.ts +2267 -694
  525. package/src/gpu-driven/shadow-views.ts +539 -0
  526. package/src/gpu-driven/view-gpu.ts +188 -41
  527. package/src/gpu-scene-schema.ts +52 -11
  528. package/src/gpu-scene.ts +186 -99
  529. package/src/gpu-texture-usage.ts +1 -0
  530. package/src/hdrp-buffers.ts +72 -36
  531. package/src/ibl/frame-resources.ts +38 -0
  532. package/src/ibl/skylight-bind-group.ts +5 -4
  533. package/src/index.ts +109 -1
  534. package/src/inspection-types.ts +191 -0
  535. package/src/instances-derived-bounds.ts +258 -34
  536. package/src/instances.ts +459 -150
  537. package/src/internal.ts +22 -0
  538. package/src/lifecycle.ts +2 -0
  539. package/src/material-row.ts +145 -0
  540. package/src/materials.ts +44 -8
  541. package/src/pbr-pipeline.ts +159 -17
  542. package/src/pipeline/standard-forward-lane.ts +52 -24
  543. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  544. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  545. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  546. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  547. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  548. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  549. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  550. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  551. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  552. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  553. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  554. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  555. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  556. package/src/pipeline/standard-output/color-transform.ts +124 -0
  557. package/src/pipeline/standard-output/graph.ts +139 -0
  558. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  559. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  560. package/src/pipeline/standard-output/lut-state.ts +176 -0
  561. package/src/pipeline/standard-output/resources.ts +121 -0
  562. package/src/pipeline/standard-output/types.ts +58 -0
  563. package/src/pipeline/standard-pipeline.ts +192 -59
  564. package/src/pipeline/standard-post.ts +186 -27
  565. package/src/pipeline-builder.ts +16 -6
  566. package/src/pipeline-spec-types.ts +4 -0
  567. package/src/pipeline-spec.ts +37 -29
  568. package/src/points-lines/standard-owner.ts +6 -14
  569. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  570. package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
  571. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  572. package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
  573. package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
  574. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  575. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  576. package/src/record/dynamic-geometry-consumption.ts +59 -0
  577. package/src/record/frame-lighting.ts +12 -11
  578. package/src/record/frame-snapshot.ts +133 -23
  579. package/src/record/frame-targets.ts +9 -0
  580. package/src/record/frame.ts +725 -133
  581. package/src/record/main-pass-geometry.ts +149 -94
  582. package/src/record/main-pass-material.ts +115 -26
  583. package/src/record/main-pass-sprite-draws.ts +16 -107
  584. package/src/record/main-pass.ts +78 -8
  585. package/src/record/material-uniforms.ts +1 -1
  586. package/src/record/mesh-ssbo.ts +59 -15
  587. package/src/record/prepared-material-bindings.ts +234 -0
  588. package/src/record/recovery-pipeline.ts +59 -136
  589. package/src/record/render-context.ts +90 -22
  590. package/src/record/shadow-pass.ts +1231 -209
  591. package/src/record/skybox-post-pass.ts +14 -3
  592. package/src/record/typed-frame-graph.ts +1004 -44
  593. package/src/record/view-ubo.ts +11 -0
  594. package/src/recovery/render-system-candidate.ts +90 -66
  595. package/src/recovery/render-system-roots.ts +113 -0
  596. package/src/recovery/types.ts +77 -0
  597. package/src/reflection/record-owner.ts +26 -54
  598. package/src/render-contract.ts +195 -25
  599. package/src/render-graph-primitives.ts +6 -2
  600. package/src/render-pipeline.ts +70 -1
  601. package/src/render-system-extract-tail.ts +409 -160
  602. package/src/render-system-extract.ts +376 -102
  603. package/src/render-system-projections.ts +241 -0
  604. package/src/render-system.ts +681 -822
  605. package/src/scene/render-scene-types.ts +13 -4
  606. package/src/scene/render-scene.ts +569 -355
  607. package/src/scene/shadow-visibility.ts +21 -0
  608. package/src/ssr/admission.ts +380 -14
  609. package/src/ssr/compose.ts +144 -0
  610. package/src/ssr/errors.ts +48 -0
  611. package/src/ssr/graph.ts +777 -0
  612. package/src/ssr/history.ts +436 -0
  613. package/src/ssr/hiz.ts +124 -0
  614. package/src/ssr/inspection.ts +124 -0
  615. package/src/ssr/resources.ts +202 -0
  616. package/src/ssr/temporal.ts +164 -0
  617. package/src/systems/skin-palette-allocator.ts +495 -148
  618. package/src/systems/skin-palette-types.ts +17 -0
  619. package/src/systems/transparent-dispatch.ts +90 -0
  620. package/src/targets/material-source.ts +34 -0
  621. package/src/temporal/coverage.ts +1 -1
  622. package/src/temporal/frame-coordinator.ts +23 -2
  623. package/src/temporal/gpu.ts +74 -12
  624. package/src/temporal/history.ts +3 -1
  625. package/src/temporal/inspection.ts +2 -1
  626. package/src/temporal/standard-scene-data.ts +3 -1
  627. package/src/temporal/temporal-view.ts +3 -0
  628. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
  629. package/src/typed-render-graph-primitives.ts +266 -74
  630. package/src/typed-shadow-passes.ts +122 -12
  631. package/src/volume/temporal.ts +10 -0
  632. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  633. package/dist/chunk-GF523LHF.mjs.map +0 -1
  634. package/dist/chunk-IQMKJLNU.mjs.map +0 -1
  635. package/dist/chunk-J52NMQKR.mjs.map +0 -1
  636. package/dist/chunk-J6KACNOH.mjs.map +0 -1
  637. package/dist/chunk-JAASCMXA.mjs.map +0 -1
  638. package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
  639. package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
  640. package/dist/chunk-VSL23LZE.mjs.map +0 -1
  641. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  642. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -43,6 +43,179 @@ export const CAMERA_PROJECTION_PERSPECTIVE = 0;
43
43
  /** Numeric encoding of orthographic projection (schema value for `projection`). */
44
44
  export const CAMERA_PROJECTION_ORTHOGRAPHIC = 1;
45
45
 
46
+ /** Closed public exposure authoring contract shared by all camera routes. */
47
+ export type CameraExposure =
48
+ | { readonly kind: 'manual'; readonly multiplier: number }
49
+ | {
50
+ readonly kind: 'auto';
51
+ readonly fallback: number;
52
+ readonly compensationEv: number;
53
+ readonly rangeEv: readonly [min: number, max: number];
54
+ readonly rates: readonly [up: number, down: number];
55
+ };
56
+
57
+ /** Numeric encoding of manual exposure in the Camera SoA column. */
58
+ export const CAMERA_EXPOSURE_MODE_MANUAL = 0;
59
+ /** Numeric encoding of GPU-adapted exposure in the Camera SoA column. */
60
+ export const CAMERA_EXPOSURE_MODE_AUTO = 1;
61
+
62
+ /** Product-supported white-balance temperature range in Kelvin. */
63
+ export const CAMERA_TEMPERATURE_MIN = 1000;
64
+ export const CAMERA_TEMPERATURE_MAX = 40000;
65
+ /** Product-supported normalized tint range. */
66
+ export const CAMERA_TINT_MIN = -1;
67
+ export const CAMERA_TINT_MAX = 1;
68
+
69
+ /** Closed validation failures for the Camera authoring/column boundary. */
70
+ export type CameraErrorCode =
71
+ | 'camera-exposure-invalid'
72
+ | 'camera-color-grading-invalid'
73
+ | 'camera-exposure-mode-invalid'
74
+ | 'camera-tonemap-invalid'
75
+ | 'camera-antialias-invalid'
76
+ | 'camera-bloom-invalid';
77
+
78
+ export interface CameraErrorDetail {
79
+ readonly field: string;
80
+ readonly actual: number | string;
81
+ readonly expected: string;
82
+ }
83
+
84
+ /** Structured Camera error; callers can branch on the closed `code` union. */
85
+ export class CameraError<Code extends CameraErrorCode = CameraErrorCode> extends Error {
86
+ readonly code: Code;
87
+ readonly expected: string;
88
+ readonly hint: string;
89
+ readonly detail: CameraErrorDetail;
90
+
91
+ constructor(code: Code, field: string, actual: number | string, expected: string, hint: string) {
92
+ super(`${code}: ${field}=${String(actual)}; expected ${expected}`);
93
+ this.name = 'CameraError';
94
+ this.code = code;
95
+ this.expected = expected;
96
+ this.hint = hint;
97
+ this.detail = Object.freeze({ field, actual, expected });
98
+ }
99
+ }
100
+
101
+ function actualValue(value: unknown): number | string {
102
+ if (typeof value === 'number' || typeof value === 'string') return value;
103
+ try {
104
+ return JSON.stringify(value) ?? String(value);
105
+ } catch {
106
+ return String(value);
107
+ }
108
+ }
109
+
110
+ function cameraError<Code extends CameraErrorCode>(
111
+ code: Code,
112
+ field: string,
113
+ actual: unknown,
114
+ expected: string,
115
+ hint: string,
116
+ ): CameraError<Code> {
117
+ return new CameraError(code, field, actualValue(actual), expected, hint);
118
+ }
119
+
120
+ function finitePositive(value: number): boolean {
121
+ return Number.isFinite(value) && value > 0;
122
+ }
123
+
124
+ /** Validate the closed exposure union before it is projected into columns. */
125
+ export function validateCameraExposure(exposure: CameraExposure): CameraExposure {
126
+ if (typeof exposure !== 'object' || exposure === null) {
127
+ throw cameraError(
128
+ 'camera-exposure-invalid',
129
+ 'value',
130
+ exposure,
131
+ 'an object with kind manual or auto',
132
+ 'choose one member of the CameraExposure union',
133
+ );
134
+ }
135
+ if (exposure.kind === 'manual') {
136
+ if (!finitePositive(exposure.multiplier)) {
137
+ throw cameraError(
138
+ 'camera-exposure-invalid',
139
+ 'multiplier',
140
+ exposure.multiplier,
141
+ 'a finite number greater than zero',
142
+ 'set Camera.exposure to a positive finite manual multiplier',
143
+ );
144
+ }
145
+ return exposure;
146
+ }
147
+ if (exposure.kind === 'auto') {
148
+ const [min, max] = exposure.rangeEv;
149
+ const [up, down] = exposure.rates;
150
+ if (
151
+ !finitePositive(exposure.fallback) ||
152
+ !Number.isFinite(exposure.compensationEv) ||
153
+ !Number.isFinite(min) ||
154
+ !Number.isFinite(max) ||
155
+ min > max ||
156
+ !Number.isFinite(up) ||
157
+ !Number.isFinite(down) ||
158
+ up < 0 ||
159
+ down < 0
160
+ ) {
161
+ throw cameraError(
162
+ 'camera-exposure-invalid',
163
+ 'auto',
164
+ JSON.stringify(exposure),
165
+ 'finite fallback/compensation, an ordered range, and non-negative rates',
166
+ 'inspect fallback, compensationEv, rangeEv, and rates before rebuilding the camera',
167
+ );
168
+ }
169
+ return exposure;
170
+ }
171
+ throw cameraError(
172
+ 'camera-exposure-invalid',
173
+ 'kind',
174
+ (exposure as { readonly kind?: unknown }).kind,
175
+ "'manual' or 'auto'",
176
+ 'choose one member of the CameraExposure union',
177
+ );
178
+ }
179
+
180
+ /** Validate the Camera-owned white-balance and LUT authoring fields. */
181
+ export function validateCameraColorGrading(
182
+ temperature: number,
183
+ tint: number,
184
+ colorLutStrength: number,
185
+ ): void {
186
+ if (
187
+ !Number.isFinite(temperature) ||
188
+ temperature < CAMERA_TEMPERATURE_MIN ||
189
+ temperature > CAMERA_TEMPERATURE_MAX
190
+ ) {
191
+ throw cameraError(
192
+ 'camera-color-grading-invalid',
193
+ 'temperature',
194
+ temperature,
195
+ `a finite value in [${CAMERA_TEMPERATURE_MIN}, ${CAMERA_TEMPERATURE_MAX}]`,
196
+ 'set Camera.temperature to a supported Kelvin value',
197
+ );
198
+ }
199
+ if (!Number.isFinite(tint) || tint < CAMERA_TINT_MIN || tint > CAMERA_TINT_MAX) {
200
+ throw cameraError(
201
+ 'camera-color-grading-invalid',
202
+ 'tint',
203
+ tint,
204
+ `a finite value in [${CAMERA_TINT_MIN}, ${CAMERA_TINT_MAX}]`,
205
+ 'set Camera.tint to a normalized value between -1 and 1',
206
+ );
207
+ }
208
+ if (!Number.isFinite(colorLutStrength) || colorLutStrength < 0 || colorLutStrength > 1) {
209
+ throw cameraError(
210
+ 'camera-color-grading-invalid',
211
+ 'colorLutStrength',
212
+ colorLutStrength,
213
+ 'a finite value in [0, 1]',
214
+ 'set Camera.colorLutStrength to zero to disable the LUT or a blend in [0, 1]',
215
+ );
216
+ }
217
+ }
218
+
46
219
  /**
47
220
  * Map a `camera.projection` numeric value to the closed `CameraProjection`
48
221
  * string-literal union. Values other than 0 / 1 fall back to `'perspective'`
@@ -152,7 +325,13 @@ export function tonemapToU32(mode: Tonemap): number {
152
325
  case 'none':
153
326
  return TONEMAP_NONE;
154
327
  }
155
- throw new RangeError(`Invalid tonemap mode: ${String(mode)}.`);
328
+ throw cameraError(
329
+ 'camera-tonemap-invalid',
330
+ 'tonemap',
331
+ mode,
332
+ 'one of the closed Tonemap values',
333
+ 'select a supported Camera tonemap mode',
334
+ );
156
335
  }
157
336
 
158
337
  /**
@@ -192,8 +371,12 @@ export function antialiasFromF32(value: number): Antialias {
192
371
  if (value === ANTIALIAS_FXAA) return 'fxaa';
193
372
  if (value === ANTIALIAS_MSAA) return 'msaa';
194
373
  if (value === ANTIALIAS_TAA) return 'taa';
195
- throw new RangeError(
196
- `Invalid antialias value: ${value}. Expected ${ANTIALIAS_NONE} (none), ${ANTIALIAS_FXAA} (fxaa), ${ANTIALIAS_MSAA} (msaa), or ${ANTIALIAS_TAA} (taa).`,
374
+ throw cameraError(
375
+ 'camera-antialias-invalid',
376
+ 'antialias',
377
+ value,
378
+ `${ANTIALIAS_NONE}, ${ANTIALIAS_FXAA}, ${ANTIALIAS_MSAA}, or ${ANTIALIAS_TAA}`,
379
+ 'select a supported Camera antialias mode',
197
380
  );
198
381
  }
199
382
 
@@ -205,8 +388,8 @@ export function antialiasFromF32(value: number): Antialias {
205
388
  * `'off'` - default; no bloom post-processing (zero-overhead opt-out path)
206
389
  * `'on'` - bloom bright-pass + separable blur + composite pipeline
207
390
  *
208
- * Bloom is a discrete enum (0/1) — illegal values fail-fast with RangeError
209
- * (charter P3), matching antialiasFromF32 precedent.
391
+ * Bloom is a discrete enum (0/1) — illegal values fail-fast with the closed
392
+ * CameraError contract (charter P3), matching antialiasFromF32 precedent.
210
393
  */
211
394
  export type BloomEnabled = 'off' | 'on';
212
395
 
@@ -222,8 +405,12 @@ export const BLOOM_ENABLED = 1;
222
405
  export function bloomEnabledFromF32(value: number): BloomEnabled {
223
406
  if (value === BLOOM_DISABLED) return 'off';
224
407
  if (value === BLOOM_ENABLED) return 'on';
225
- throw new RangeError(
226
- `Invalid bloom value: ${value}. Expected ${BLOOM_DISABLED} (off) or ${BLOOM_ENABLED} (on).`,
408
+ throw cameraError(
409
+ 'camera-bloom-invalid',
410
+ 'bloom',
411
+ value,
412
+ `${BLOOM_DISABLED} or ${BLOOM_ENABLED}`,
413
+ 'select Camera bloom off or on',
227
414
  );
228
415
  }
229
416
 
@@ -313,7 +500,15 @@ export const Camera = defineComponent('Camera', {
313
500
  top: { type: 'f32', default: 1 },
314
501
  tonemap: { type: 'f32', default: 0 },
315
502
  exposure: { type: 'f32', default: 1.0 },
503
+ exposureMode: { type: 'f32', default: CAMERA_EXPOSURE_MODE_MANUAL },
504
+ compensationEv: { type: 'f32', default: 0 },
505
+ rangeEv: { type: 'array<f32, 2>', default: new Float32Array([-8, 8]) },
506
+ rates: { type: 'array<f32, 2>', default: new Float32Array([3, 1]) },
316
507
  whitePoint: { type: 'f32', default: 4.0 },
508
+ temperature: { type: 'f32', default: 6504 },
509
+ tint: { type: 'f32', default: 0 },
510
+ colorLut: { type: 'shared<TextureAsset>', default: 0 as never },
511
+ colorLutStrength: { type: 'f32', default: 0 },
317
512
  antialias: { type: 'f32', default: 0 },
318
513
  historyVersion: { type: 'u32', default: 0 },
319
514
  bloom: { type: 'f32', default: 0 },
@@ -356,6 +551,79 @@ export const Camera = defineComponent('Camera', {
356
551
  export type CameraData = ShapeOf<SchemaOf<typeof Camera>>;
357
552
  type CameraPod = CameraData;
358
553
 
554
+ /** Project the Camera SoA columns back into the public closed union. */
555
+ export function cameraExposureFromColumns(
556
+ input: Pick<CameraData, 'exposureMode' | 'exposure' | 'compensationEv' | 'rangeEv' | 'rates'>,
557
+ ): CameraExposure {
558
+ if (input.exposureMode === CAMERA_EXPOSURE_MODE_MANUAL) {
559
+ return validateCameraExposure({ kind: 'manual', multiplier: input.exposure });
560
+ }
561
+ if (input.exposureMode === CAMERA_EXPOSURE_MODE_AUTO) {
562
+ return validateCameraExposure({
563
+ kind: 'auto',
564
+ fallback: input.exposure,
565
+ compensationEv: input.compensationEv,
566
+ rangeEv: [input.rangeEv[0] ?? -8, input.rangeEv[1] ?? 8],
567
+ rates: [input.rates[0] ?? 3, input.rates[1] ?? 1],
568
+ });
569
+ }
570
+ throw cameraError(
571
+ 'camera-exposure-mode-invalid',
572
+ 'exposureMode',
573
+ input.exposureMode,
574
+ `${CAMERA_EXPOSURE_MODE_MANUAL} or ${CAMERA_EXPOSURE_MODE_AUTO}`,
575
+ 'set Camera.exposureMode to the manual or auto encoding',
576
+ );
577
+ }
578
+
579
+ function cameraExposureColumns(
580
+ exposure: CameraExposure,
581
+ ): Pick<CameraData, 'exposureMode' | 'exposure' | 'compensationEv' | 'rangeEv' | 'rates'> {
582
+ const checked = validateCameraExposure(exposure);
583
+ if (checked.kind === 'manual') {
584
+ return {
585
+ exposureMode: CAMERA_EXPOSURE_MODE_MANUAL,
586
+ exposure: checked.multiplier,
587
+ compensationEv: 0,
588
+ rangeEv: new Float32Array([-8, 8]),
589
+ rates: new Float32Array([3, 1]),
590
+ };
591
+ }
592
+ return {
593
+ exposureMode: CAMERA_EXPOSURE_MODE_AUTO,
594
+ exposure: checked.fallback,
595
+ compensationEv: checked.compensationEv,
596
+ rangeEv: new Float32Array(checked.rangeEv),
597
+ rates: new Float32Array(checked.rates),
598
+ };
599
+ }
600
+
601
+ interface CameraColorGradingOpts {
602
+ exposure?: CameraExposure;
603
+ temperature?: number;
604
+ tint?: number;
605
+ colorLut?: CameraPod['colorLut'];
606
+ colorLutStrength?: number;
607
+ }
608
+
609
+ function cameraColorGradingColumns(
610
+ opts: CameraColorGradingOpts,
611
+ ): ReturnType<typeof cameraExposureColumns> &
612
+ Pick<CameraData, 'temperature' | 'tint' | 'colorLut' | 'colorLutStrength'> {
613
+ const exposure = opts.exposure ?? { kind: 'manual', multiplier: 1 };
614
+ const temperature = opts.temperature ?? 6504;
615
+ const tint = opts.tint ?? 0;
616
+ const colorLutStrength = opts.colorLutStrength ?? 0;
617
+ validateCameraColorGrading(temperature, tint, colorLutStrength);
618
+ return {
619
+ ...cameraExposureColumns(exposure),
620
+ temperature,
621
+ tint,
622
+ colorLut: opts.colorLut ?? (0 as CameraPod['colorLut']),
623
+ colorLutStrength,
624
+ };
625
+ }
626
+
359
627
  // ─── Camera factory functions (w13 SSOT refactoring) ─────────────────────
360
628
  //
361
629
  // Standalone factory functions that return 20-field CameraPod objects
@@ -396,6 +664,11 @@ interface CameraPerspectiveOpts {
396
664
  * receive aspect-sync regardless of this flag.
397
665
  */
398
666
  autoAspect?: boolean;
667
+ exposure?: CameraExposure;
668
+ temperature?: number;
669
+ tint?: number;
670
+ colorLut?: CameraPod['colorLut'];
671
+ colorLutStrength?: number;
399
672
  }
400
673
 
401
674
  interface CameraOrthographicOpts {
@@ -405,6 +678,11 @@ interface CameraOrthographicOpts {
405
678
  top: number;
406
679
  near?: number;
407
680
  far?: number;
681
+ exposure?: CameraExposure;
682
+ temperature?: number;
683
+ tint?: number;
684
+ colorLut?: CameraPod['colorLut'];
685
+ colorLutStrength?: number;
408
686
  }
409
687
 
410
688
  /**
@@ -474,6 +752,7 @@ export function perspective(opts: CameraPerspectiveOpts): CameraPod {
474
752
  far: opts.far ?? 100,
475
753
  projection: CAMERA_PROJECTION_PERSPECTIVE,
476
754
  ...(opts.autoAspect !== undefined ? { autoAspect: opts.autoAspect } : {}),
755
+ ...cameraColorGradingColumns(opts),
477
756
  };
478
757
  }
479
758
 
@@ -513,5 +792,6 @@ export function orthographic(opts: CameraOrthographicOpts): CameraPod {
513
792
  right: opts.right,
514
793
  bottom: opts.bottom,
515
794
  top: opts.top,
795
+ ...cameraColorGradingColumns(opts),
516
796
  };
517
797
  }
@@ -27,6 +27,7 @@ export {
27
27
  type SceneInstanceOverrideRecord,
28
28
  type SceneInstanceState,
29
29
  } from './scene-instance';
30
+ export * from './screen-space-reflection';
30
31
  export {
31
32
  SKYBOX_MODE_CUBEMAP,
32
33
  SkyboxBackground,
@@ -1,23 +1,50 @@
1
+ // @forgeax/engine-render - renderer-owned large instance association.
2
+ //
3
+ // The ECS component deliberately carries only a stable collection identity.
4
+ // Matrix bytes, revision, capacity, dirty ranges, GPU residency and fallback
5
+ // policy belong to InstanceCollectionStore, exposed from the same Renderer.
6
+ // This keeps large payloads out of the ECS managed BufferPool while retaining
7
+ // ordinary query and entity-lifetime semantics.
8
+ //
9
+ // Authoring example:
10
+ //
11
+ // const transforms = new Float32Array(instanceCount * 16);
12
+ // for (let index = 0; index < instanceCount; index += 1) {
13
+ // const offset = index * 16;
14
+ // transforms[offset] = 1;
15
+ // transforms[offset + 5] = 1;
16
+ // transforms[offset + 10] = 1;
17
+ // transforms[offset + 15] = 1;
18
+ // }
19
+ // const collection = renderer.instances.create({
20
+ // transforms,
21
+ // }).unwrap();
22
+ // world.spawn(
23
+ // { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
24
+ // { component: MeshRenderer, data: {} },
25
+ // { component: Instances, data: { collectionId: collection.collectionId } },
26
+ // );
27
+ //
28
+ // Updates stay on the renderer owner and publish one revision:
29
+ //
30
+ // renderer.instances.update(collection.collectionId, {
31
+ // start: 12,
32
+ // transforms: patch,
33
+ // });
34
+ //
35
+ // Render extraction snapshots the validated packed column-major matrices once
36
+ // per frame. Direct, GPU-driven and fallback lanes consume that same detached
37
+ // projection; callers never split one logical collection into ECS chunks.
38
+
1
39
  import { defineComponent } from '@forgeax/engine-ecs';
40
+ import type { InstanceCollectionData } from '../instances';
2
41
 
3
- /**
4
- * World-owned local transforms for one explicit instanced renderable.
5
- * Packed column-major mat4 values compose as entityWorld * instanceLocal.
6
- * ECS owns copying, mutation and entity lifetime, including large arrays.
7
- * Renderer extraction derives its own snapshot and GPU residency; neither
8
- * authoring nor glTF SceneAsset lowering requires a Renderer identity.
9
- *
10
- * @example
11
- * const transforms = new Float32Array(20_000 * 16);
12
- * for (let i = 0; i < 20_000; i++) {
13
- * transforms[i * 16] = transforms[i * 16 + 5] =
14
- * transforms[i * 16 + 10] = transforms[i * 16 + 15] = 1;
15
- * }
16
- * const entity = world.spawn({ component: Instances, data: { transforms } }).unwrap();
17
- * world.set(entity, Instances, { transforms }).unwrap();
18
- */
42
+ /** Per-entity association with a renderer-owned instance collection. */
19
43
  export const Instances = defineComponent('Instances', {
20
- transforms: { type: 'array<f32>' },
44
+ collectionId: { type: 'u32', default: 0 },
21
45
  });
22
46
 
23
- export type InstancesData = { readonly transforms: Float32Array };
47
+ /** Type-level hint for the `data` object at the Instances spawn site. */
48
+ export type InstancesData = InstanceCollectionData;
49
+
50
+ export type { InstanceCollectionId } from '../instances';
@@ -37,7 +37,8 @@
37
37
  // `world.get(root, SceneInstance)` path as another component)
38
38
 
39
39
  import { defineComponent, type EntityHandle } from '@forgeax/engine-ecs';
40
- import type { LocalEntityId, MountOverride } from '@forgeax/engine-types';
40
+ import type { MountOverride } from '@forgeax/engine-scene';
41
+ import type { LocalEntityId } from '@forgeax/engine-types';
41
42
 
42
43
  /**
43
44
  * Per-component, per-field override record carried in `SceneInstanceState`.
@@ -0,0 +1,21 @@
1
+ // @forgeax/engine-render - ScreenSpaceReflection authoring component.
2
+ //
3
+ // The component is an opt-in camera effect. It carries only the three
4
+ // bounded authoring values; all graph, resource, history, and backend state
5
+ // remains renderer-owned.
6
+
7
+ import { defineComponent, type SchemaOf, type ShapeOf } from '@forgeax/engine-ecs';
8
+
9
+ /**
10
+ * Schema-derived ScreenSpaceReflection authoring data.
11
+ *
12
+ * The defaults are conservative and are validated against the active camera
13
+ * view range before a spatial candidate is admitted.
14
+ */
15
+ export const ScreenSpaceReflection = defineComponent('ScreenSpaceReflection', {
16
+ maxDistance: { type: 'f32', default: 40 },
17
+ thickness: { type: 'f32', default: 0.2 },
18
+ maxRoughness: { type: 'f32', default: 0.6 },
19
+ });
20
+
21
+ export type ScreenSpaceReflectionData = ShapeOf<SchemaOf<typeof ScreenSpaceReflection>>;
@@ -31,8 +31,8 @@
31
31
  // Why array<f32> (variable) and not array<f32, N> (fixed) for regions?
32
32
  // The length `frameCount * 4` is data-dependent: `frameCount` is itself a
33
33
  // per-entity column read at runtime, not a schema-time literal. Same
34
- // shape as M1 `Instances.transforms: 'array<f32>'` whose length depends
35
- // on the live instance count; D-6 codifies the precedent.
34
+ // shape as the renderer-owned 3D instance collection snapshot whose length
35
+ // depends on the live instance count; the owners remain separate.
36
36
  //
37
37
  // dt accumulator clock model (requirements section 2.5 q6 + plan-strategy
38
38
  // section 2 D-5):
@@ -41,7 +41,7 @@
41
41
  // composes per instance:
42
42
  // world_position[i] = entity_world * instances_local[i] * vertex_position
43
43
  // `SpriteInstances.transforms[i*16..i*16+15]` is interpreted as a local-
44
- // space transform under the entity, exactly like `Instances.transforms`.
44
+ // space transform under the entity, matching the 3D collection projection.
45
45
  // Set the entity's `Transform` to identity to make `instances_local[i]`
46
46
  // directly world-space.
47
47
  //
@@ -38,10 +38,7 @@ import {
38
38
  prepareMipmaps,
39
39
  } from '@forgeax/engine-assets-runtime';
40
40
  import type { World } from '@forgeax/engine-ecs';
41
- import {
42
- PROCEDURAL_FLOATS_PER_VERTEX,
43
- type VertexLayoutProjection,
44
- } from '@forgeax/engine-geometry';
41
+ import { deriveVertexCount, type VertexLayoutProjection } from '@forgeax/engine-geometry';
45
42
  import { halfFloat } from '@forgeax/engine-math';
46
43
  import {
47
44
  type Buffer,
@@ -101,7 +98,6 @@ import {
101
98
  runIblPrecompute,
102
99
  } from '../ibl/IblPipelineCache';
103
100
  import type { RhiErrorListenerRegistry } from '../lifecycle';
104
- import type { RecoveryColdWorkGuard } from '../record/render-context';
105
101
  import {
106
102
  type CubeRenderData,
107
103
  deriveRenderDataCubemap,
@@ -372,6 +368,23 @@ function packMeshLodGeometry(
372
368
  }
373
369
  lowerData.push(projected.value);
374
370
  }
371
+ if (
372
+ deriveVertexCount(root.vertices, rootData.layoutProjection) === undefined ||
373
+ lowerMeshes.some((mesh, index) => {
374
+ const data = lowerData[index];
375
+ return (
376
+ data === undefined || deriveVertexCount(mesh.vertices, data.layoutProjection) === undefined
377
+ );
378
+ })
379
+ ) {
380
+ return err(
381
+ new RhiError({
382
+ code: 'asset-not-registered',
383
+ expected: 'every MeshAsset LOD vertex byte length to match its layout projection stride',
384
+ hint: 'reimport the LOD chain so interleaved vertex bytes match attributes',
385
+ }),
386
+ );
387
+ }
375
388
  if (
376
389
  lowerData.some(
377
390
  (data) =>
@@ -479,14 +492,6 @@ export interface MeshGpuHandles {
479
492
  readonly iboBytes: number;
480
493
  readonly indexCount: number;
481
494
  readonly indexFormat: 'uint16' | 'uint32';
482
- /**
483
- * Vertex stride discriminator (feat-20260611). `'12F'` = 48 B
484
- * (position+normal+uv+tangent); `'18F'` = 72 B (12F + skinIndex(uint16x4) +
485
- * skinWeight(float32x4)). Mirrors `MeshRenderData.layout` in render-data.ts
486
- * and `MeshRenderData.layout` -- the residency and render-data layout
487
- * fields are the same union and move together.
488
- */
489
- readonly layout: '12F' | '18F';
490
495
  /** Geometry-owned vertex layout projection used by every GPU consumer. */
491
496
  readonly layoutProjection: VertexLayoutProjection;
492
497
  /**
@@ -497,7 +502,7 @@ export interface MeshGpuHandles {
497
502
  * MeshRenderData.uvSetCount.
498
503
  */
499
504
  readonly uvSetCount: number;
500
- /** Vertex count uses 18F for skin or the geometry-owned canonical base stride. */
505
+ /** Vertex count derived from the geometry-owned layout projection. */
501
506
  readonly vertexCount: number;
502
507
  /** True when `MeshAsset.indices` is present (indexed draw path). */
503
508
  readonly indexed: boolean;
@@ -547,7 +552,6 @@ export class GpuResidencyCache {
547
552
  // Hardware-probe caps injected at `configureGpuDevice`; guards the HDR cubemap
548
553
  // path (_uploadCubemapFromEquirect) when `rgba16floatRenderable` is false.
549
554
  private caps: RhiCaps | undefined = undefined;
550
- private recoveryColdWorkGuard: RecoveryColdWorkGuard | undefined;
551
555
  private deviceEpoch = 0;
552
556
  private textureGeneration = 0;
553
557
 
@@ -657,9 +661,6 @@ export class GpuResidencyCache {
657
661
  }
658
662
 
659
663
  /** Arm the first-published-frame assertion on this generation's store. */
660
- setRecoveryColdWorkGuard(guard: RecoveryColdWorkGuard | undefined): void {
661
- this.recoveryColdWorkGuard = guard;
662
- }
663
664
 
664
665
  /**
665
666
  * Wrap a raw RHI Buffer handle into a GpuBuffer. The wrapper holds a
@@ -1023,7 +1024,6 @@ export class GpuResidencyCache {
1023
1024
  const key = this.worldKey(handleSlot(handle), worldId);
1024
1025
  const existing = this.samplerGpuHandles.get(key);
1025
1026
  if (existing !== undefined) return ok(existing);
1026
- this.recoveryColdWorkGuard?.noteUploadColdWork();
1027
1027
  const device = this.gpuDevice;
1028
1028
  if (device === undefined) {
1029
1029
  return err(
@@ -1159,7 +1159,6 @@ export class GpuResidencyCache {
1159
1159
  const key = this.worldKey(id, worldId);
1160
1160
  const existing = this.meshGpuHandles.get(key);
1161
1161
  if (existing !== undefined) return ok(existing);
1162
- this.recoveryColdWorkGuard?.noteUploadColdWork();
1163
1162
  const projected = deriveRenderDataMesh(pod);
1164
1163
  if (!projected.ok) return projected;
1165
1164
  return this.uploadMeshById(key, pod, projected.value, lodMeshes);
@@ -1168,7 +1167,6 @@ export class GpuResidencyCache {
1168
1167
  const texKey = this.worldKey(id, worldId);
1169
1168
  const existing = this.textureGpuHandles.get(texKey);
1170
1169
  if (existing !== undefined) return ok(existing);
1171
- this.recoveryColdWorkGuard?.noteUploadColdWork();
1172
1170
  const projected = deriveRenderDataTexture(pod);
1173
1171
  if (!projected.ok) return projected;
1174
1172
  const decoded: DecodedImage = decodedFromTexture(pod);
@@ -2010,6 +2008,16 @@ export class GpuResidencyCache {
2010
2008
  );
2011
2009
  }
2012
2010
 
2011
+ const vertexCount = deriveVertexCount(mesh.vertices, renderData.layoutProjection);
2012
+ if (vertexCount === undefined) {
2013
+ return err(
2014
+ new RhiError({
2015
+ code: 'asset-not-registered',
2016
+ expected: 'MeshAsset.vertices byteLength to be divisible by its layout projection stride',
2017
+ hint: 'reimport the mesh so the interleaved vertex bytes match attributes',
2018
+ }),
2019
+ );
2020
+ }
2013
2021
  const packed = packMeshLodGeometry(mesh, renderData, lodMeshes);
2014
2022
  if (!packed.ok) return packed;
2015
2023
  const { vertices, indices, lodRanges } = packed.value;
@@ -2068,14 +2076,9 @@ export class GpuResidencyCache {
2068
2076
  iboBytes: indices === undefined ? 0 : indexBytes,
2069
2077
  indexCount: mesh.indices === undefined ? 0 : mesh.indices.length,
2070
2078
  indexFormat: indices instanceof Uint32Array ? 'uint32' : 'uint16',
2071
- layout: renderData.layoutProjection.attributes.some(
2072
- (attribute) => attribute.key === 'skinIndex' || attribute.key === 'skinWeight',
2073
- )
2074
- ? '18F'
2075
- : '12F',
2076
2079
  layoutProjection: renderData.layoutProjection,
2077
2080
  uvSetCount: 1 + extraUvSets,
2078
- vertexCount: mesh.vertices.byteLength / renderData.layoutProjection.arrayStride,
2081
+ vertexCount,
2079
2082
  indexed: mesh.indices !== undefined,
2080
2083
  topology: renderData.submeshes[0]?.topology ?? 'triangle-list',
2081
2084
  submeshes: renderData.submeshes,
@@ -2102,6 +2105,8 @@ export class GpuResidencyCache {
2102
2105
  if (entry === undefined) return;
2103
2106
 
2104
2107
  const newVertexBytes = newVertices.byteLength;
2108
+ const newVertexCount = deriveVertexCount(newVertices, entry.layoutProjection);
2109
+ if (newVertexCount === undefined) return;
2105
2110
  const indexBytesUnpadded = newIndices.byteLength;
2106
2111
  const newIndexBytes = ((indexBytesUnpadded + 3) >> 2) << 2;
2107
2112
 
@@ -2131,10 +2136,9 @@ export class GpuResidencyCache {
2131
2136
  iboBytes: entry.iboBytes,
2132
2137
  indexCount: newIndices.length,
2133
2138
  indexFormat: 'uint16',
2134
- layout: '12F',
2135
2139
  layoutProjection: entry.layoutProjection,
2136
2140
  uvSetCount: entry.uvSetCount,
2137
- vertexCount: newVertices.length / PROCEDURAL_FLOATS_PER_VERTEX,
2141
+ vertexCount: newVertexCount,
2138
2142
  indexed: true,
2139
2143
  topology: entry.topology,
2140
2144
  submeshes: nextSubmeshes,
@@ -2175,10 +2179,9 @@ export class GpuResidencyCache {
2175
2179
  iboBytes: newIndexBytes,
2176
2180
  indexCount: newIndices.length,
2177
2181
  indexFormat: 'uint16',
2178
- layout: '12F',
2179
2182
  layoutProjection: entry.layoutProjection,
2180
2183
  uvSetCount: entry.uvSetCount,
2181
- vertexCount: newVertices.length / PROCEDURAL_FLOATS_PER_VERTEX,
2184
+ vertexCount: newVertexCount,
2182
2185
  indexed: true,
2183
2186
  topology: entry.topology,
2184
2187
  submeshes: nextSubmeshes,