@forgeax/engine-render 0.1.31 → 0.1.33

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 (293) hide show
  1. package/README.md +447 -34
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/fxaa-registration.d.ts +4 -0
  5. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  6. package/dist/assembly/lod-observation.d.ts +4 -0
  7. package/dist/assembly/lod-observation.d.ts.map +1 -0
  8. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  9. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  10. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  11. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  12. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  13. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  14. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  15. package/dist/assembly/webgpu-ready.d.ts +3 -2
  16. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  17. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  18. package/dist/bloom-admission.d.ts +13 -0
  19. package/dist/bloom-admission.d.ts.map +1 -0
  20. package/dist/{chunk-FUUO4UND.mjs → chunk-3RTCJTH4.mjs} +12 -9
  21. package/dist/chunk-3RTCJTH4.mjs.map +1 -0
  22. package/dist/{chunk-NO4WZCAH.mjs → chunk-LEAXOMYJ.mjs} +3 -3
  23. package/dist/{chunk-NO4WZCAH.mjs.map → chunk-LEAXOMYJ.mjs.map} +1 -1
  24. package/dist/{chunk-JRBDO2KB.mjs → chunk-NB2S7ZRX.mjs} +166 -10
  25. package/dist/chunk-NB2S7ZRX.mjs.map +1 -0
  26. package/dist/{chunk-7MQ3XBSP.mjs → chunk-NNQL7CB3.mjs} +4 -4
  27. package/dist/{chunk-7MQ3XBSP.mjs.map → chunk-NNQL7CB3.mjs.map} +1 -1
  28. package/dist/{chunk-C3DDSXYK.mjs → chunk-OO3DRYK7.mjs} +171 -230
  29. package/dist/chunk-OO3DRYK7.mjs.map +1 -0
  30. package/dist/{chunk-S5UE2T5P.mjs → chunk-PLAXOOX5.mjs} +608 -7
  31. package/dist/chunk-PLAXOOX5.mjs.map +1 -0
  32. package/dist/{chunk-PSEQ6QPH.mjs → chunk-VOZWDM3L.mjs} +295 -198
  33. package/dist/chunk-VOZWDM3L.mjs.map +1 -0
  34. package/dist/{chunk-MDQJPY3T.mjs → chunk-ZDQWGQW7.mjs} +10 -4
  35. package/dist/chunk-ZDQWGQW7.mjs.map +1 -0
  36. package/dist/components/atmosphere.d.ts +2 -0
  37. package/dist/components/atmosphere.d.ts.map +1 -1
  38. package/dist/components/camera.d.ts +20 -4
  39. package/dist/components/camera.d.ts.map +1 -1
  40. package/dist/components/depth-of-field.d.ts +28 -0
  41. package/dist/components/depth-of-field.d.ts.map +1 -0
  42. package/dist/components/directional-light.d.ts +2 -1
  43. package/dist/components/directional-light.d.ts.map +1 -1
  44. package/dist/components/index.d.ts +1 -0
  45. package/dist/components/index.d.ts.map +1 -1
  46. package/dist/components/mesh-filter.d.ts +6 -5
  47. package/dist/components/mesh-filter.d.ts.map +1 -1
  48. package/dist/components/motion-blur.d.ts +1 -0
  49. package/dist/components/motion-blur.d.ts.map +1 -1
  50. package/dist/construct-renderer.mjs +3746 -837
  51. package/dist/construct-renderer.mjs.map +1 -1
  52. package/dist/device/gpu-residency.d.ts +6 -0
  53. package/dist/device/gpu-residency.d.ts.map +1 -1
  54. package/dist/environment/analytic-fog.d.ts +6 -0
  55. package/dist/environment/analytic-fog.d.ts.map +1 -0
  56. package/dist/errors/render.d.ts +6 -2
  57. package/dist/errors/render.d.ts.map +1 -1
  58. package/dist/extract/camera.d.ts.map +1 -1
  59. package/dist/extract/contracts.d.ts +7 -0
  60. package/dist/extract/contracts.d.ts.map +1 -1
  61. package/dist/extract/environment.d.ts +2 -0
  62. package/dist/extract/environment.d.ts.map +1 -1
  63. package/dist/features/depth-of-field/depth-of-field-assembly.d.ts +19 -0
  64. package/dist/features/depth-of-field/depth-of-field-assembly.d.ts.map +1 -0
  65. package/dist/features/depth-of-field/depth-of-field-feature.d.ts +43 -0
  66. package/dist/features/depth-of-field/depth-of-field-feature.d.ts.map +1 -0
  67. package/dist/features/depth-of-field/depth-of-field-inspection.d.ts +34 -0
  68. package/dist/features/depth-of-field/depth-of-field-inspection.d.ts.map +1 -0
  69. package/dist/features/depth-of-field/depth-of-field-params.d.ts +83 -0
  70. package/dist/features/depth-of-field/depth-of-field-params.d.ts.map +1 -0
  71. package/dist/features/error-reporting.d.ts +13 -0
  72. package/dist/features/error-reporting.d.ts.map +1 -0
  73. package/dist/features/host.d.ts +5 -0
  74. package/dist/features/host.d.ts.map +1 -1
  75. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  76. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  77. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  78. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  79. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  80. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  81. package/dist/features/plan.d.ts +7 -4
  82. package/dist/features/plan.d.ts.map +1 -1
  83. package/dist/features/prepared-gpu-work.d.ts +9 -5
  84. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  85. package/dist/features/render-graph-compute.d.ts.map +1 -1
  86. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  87. package/dist/features/types.d.ts +19 -1
  88. package/dist/features/types.d.ts.map +1 -1
  89. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  90. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  91. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  92. package/dist/gpu-driven/production-raster.d.ts +3 -1
  93. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  94. package/dist/gpu-driven/view-gpu.d.ts +9 -0
  95. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  96. package/dist/gpu-scene.d.ts +6 -1
  97. package/dist/gpu-scene.d.ts.map +1 -1
  98. package/dist/index.d.ts +8 -3
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.mjs +6 -5
  101. package/dist/index.mjs.map +1 -1
  102. package/dist/inspection-types.d.ts +78 -2
  103. package/dist/inspection-types.d.ts.map +1 -1
  104. package/dist/instances.d.ts +15 -1
  105. package/dist/instances.d.ts.map +1 -1
  106. package/dist/internal.mjs +6 -6
  107. package/dist/mesh-material-bindings.d.ts +3 -0
  108. package/dist/mesh-material-bindings.d.ts.map +1 -1
  109. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  110. package/dist/pipeline/standard-output/types.d.ts +4 -2
  111. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts +28 -19
  113. package/dist/pipeline/standard-post.d.ts.map +1 -1
  114. package/dist/pipeline-spec.d.ts +2 -2
  115. package/dist/plugin.d.ts.map +1 -1
  116. package/dist/record/frame-snapshot.d.ts +24 -1
  117. package/dist/record/frame-snapshot.d.ts.map +1 -1
  118. package/dist/record/frame-targets.d.ts.map +1 -1
  119. package/dist/record/frame.d.ts +5 -2
  120. package/dist/record/frame.d.ts.map +1 -1
  121. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  122. package/dist/record/main-pass.d.ts.map +1 -1
  123. package/dist/record/mesh-ssbo.d.ts +6 -5
  124. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  125. package/dist/record/render-context.d.ts +12 -28
  126. package/dist/record/render-context.d.ts.map +1 -1
  127. package/dist/record/shadow-pass.d.ts.map +1 -1
  128. package/dist/record/skybox-post-pass.d.ts +5 -3
  129. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  130. package/dist/record/typed-frame-graph.d.ts +8 -1
  131. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  132. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  133. package/dist/render-contract.d.ts +32 -5
  134. package/dist/render-contract.d.ts.map +1 -1
  135. package/dist/render-graph-primitives.d.ts +2 -0
  136. package/dist/render-graph-primitives.d.ts.map +1 -1
  137. package/dist/render-pipeline.d.ts +15 -1
  138. package/dist/render-pipeline.d.ts.map +1 -1
  139. package/dist/render-system-extract-tail.d.ts.map +1 -1
  140. package/dist/render-system-extract.d.ts +26 -5
  141. package/dist/render-system-extract.d.ts.map +1 -1
  142. package/dist/render-system.d.ts +9 -2
  143. package/dist/render-system.d.ts.map +1 -1
  144. package/dist/scene/render-scene.d.ts +2 -0
  145. package/dist/scene/render-scene.d.ts.map +1 -1
  146. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  147. package/dist/temporal/frame.d.ts +7 -0
  148. package/dist/temporal/frame.d.ts.map +1 -1
  149. package/dist/temporal/index.mjs +5 -5
  150. package/dist/temporal/view.d.ts +6 -1
  151. package/dist/temporal/view.d.ts.map +1 -1
  152. package/dist/typed-render-graph-primitives.d.ts +10 -7
  153. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  154. package/dist/volume/component.d.ts +0 -1
  155. package/dist/volume/component.d.ts.map +1 -1
  156. package/dist/volume/passes.d.ts.map +1 -1
  157. package/dist/volume/temporal.d.ts +3 -1
  158. package/dist/volume/temporal.d.ts.map +1 -1
  159. package/package.json +21 -21
  160. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  161. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  162. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  163. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  164. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  165. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  166. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  167. package/src/__tests__/factory-contract.integration.test.ts +331 -68
  168. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  169. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  170. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +12 -0
  171. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
  172. package/src/__tests__/gpu-driven-production.integration.test.ts +27 -1
  173. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +1 -1
  174. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  175. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +11 -0
  176. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  177. package/src/__tests__/gpu-scene.unit.test.ts +91 -0
  178. package/src/__tests__/instances-store.unit.test.ts +90 -0
  179. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  180. package/src/__tests__/motion-blur-compute.dawn.test.ts +583 -0
  181. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +49 -0
  182. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  183. package/src/__tests__/public-surface.test-d.ts +8 -0
  184. package/src/__tests__/render-error-code-owner.test-d.ts +2 -0
  185. package/src/__tests__/render-feature-error-reporting.unit.test.ts +24 -0
  186. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  187. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +31 -0
  188. package/src/__tests__/renderer-frame-transaction.integration.test.ts +7 -1
  189. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  190. package/src/__tests__/skinned-shadow-caster.test.ts +2 -0
  191. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  192. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  193. package/src/__tests__/standard-pipeline.integration.test.ts +18 -8
  194. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  195. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  196. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  197. package/src/__tests__/volume-optics-oracle.unit.test.ts +3 -1
  198. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +177 -13
  199. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +447 -61
  200. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  201. package/src/__tests__/volumetric-fog-topology.unit.test.ts +19 -3
  202. package/src/assembly/analytic-fog-registration.ts +14 -0
  203. package/src/assembly/fxaa-registration.ts +17 -0
  204. package/src/assembly/lod-observation.ts +12 -0
  205. package/src/assembly/motion-blur-registration.ts +17 -0
  206. package/src/assembly/renderer-facade.ts +2 -0
  207. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  208. package/src/assembly/webgpu-ready-contract.ts +8 -3
  209. package/src/assembly/webgpu-ready.ts +186 -250
  210. package/src/assembly/webgpu-renderer.ts +30 -45
  211. package/src/bloom-admission.ts +21 -0
  212. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  213. package/src/components/atmosphere.ts +4 -0
  214. package/src/components/camera.ts +66 -10
  215. package/src/components/depth-of-field.ts +45 -0
  216. package/src/components/directional-light.ts +2 -1
  217. package/src/components/index.ts +1 -0
  218. package/src/components/mesh-filter.ts +11 -9
  219. package/src/components/motion-blur.ts +1 -0
  220. package/src/device/gpu-residency.ts +56 -12
  221. package/src/environment/analytic-fog.ts +44 -0
  222. package/src/environment/background.ts +2 -2
  223. package/src/errors/render.ts +14 -1
  224. package/src/extract/camera.ts +42 -9
  225. package/src/extract/contracts.ts +7 -0
  226. package/src/extract/environment.ts +4 -0
  227. package/src/features/depth-of-field/__tests__/depth-of-field-params.unit.test.ts +943 -0
  228. package/src/features/depth-of-field/depth-of-field-assembly.ts +100 -0
  229. package/src/features/depth-of-field/depth-of-field-feature.ts +295 -0
  230. package/src/features/depth-of-field/depth-of-field-inspection.ts +237 -0
  231. package/src/features/depth-of-field/depth-of-field-params.ts +556 -0
  232. package/src/features/error-reporting.ts +78 -0
  233. package/src/features/host.ts +26 -13
  234. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  235. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  236. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  237. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  238. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  239. package/src/features/plan.ts +25 -8
  240. package/src/features/prepared-gpu-work.ts +86 -35
  241. package/src/features/render-graph-compute.ts +13 -5
  242. package/src/features/render-graph-contribution.ts +2 -0
  243. package/src/features/types.ts +18 -1
  244. package/src/gpu-driven/material-artifacts.ts +2 -7
  245. package/src/gpu-driven/prepared-draw.ts +15 -10
  246. package/src/gpu-driven/production-raster.ts +83 -7
  247. package/src/gpu-driven/view-gpu.ts +17 -0
  248. package/src/gpu-scene.ts +188 -21
  249. package/src/index.ts +64 -0
  250. package/src/inspection-types.ts +98 -2
  251. package/src/instances.ts +93 -0
  252. package/src/mesh-material-bindings.ts +4 -0
  253. package/src/pipeline/standard-output/graph.ts +3 -0
  254. package/src/pipeline/standard-output/types.ts +4 -1
  255. package/src/pipeline/standard-post.ts +324 -76
  256. package/src/pipeline-spec.ts +5 -5
  257. package/src/plugin.ts +2 -0
  258. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  259. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -1
  260. package/src/record/frame-snapshot.ts +31 -2
  261. package/src/record/frame-targets.ts +10 -6
  262. package/src/record/frame.ts +202 -28
  263. package/src/record/main-pass-geometry.ts +30 -1
  264. package/src/record/main-pass-sprite-draws.ts +6 -1
  265. package/src/record/main-pass.ts +1 -5
  266. package/src/record/mesh-ssbo.ts +43 -6
  267. package/src/record/render-context.ts +12 -28
  268. package/src/record/shadow-pass.ts +6 -1
  269. package/src/record/skybox-post-pass.ts +122 -196
  270. package/src/record/typed-frame-graph.ts +259 -15
  271. package/src/recovery/render-system-candidate.ts +28 -10
  272. package/src/render-contract.ts +34 -4
  273. package/src/render-graph-primitives.ts +8 -1
  274. package/src/render-pipeline.ts +22 -1
  275. package/src/render-system-extract-tail.ts +103 -13
  276. package/src/render-system-extract.ts +148 -38
  277. package/src/render-system.ts +332 -119
  278. package/src/scene/render-scene.ts +85 -4
  279. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  280. package/src/temporal/frame-coordinator.ts +8 -1
  281. package/src/temporal/frame.ts +20 -0
  282. package/src/temporal/view.ts +13 -2
  283. package/src/typed-render-graph-primitives.ts +124 -48
  284. package/src/volume/component.ts +0 -1
  285. package/src/volume/passes.ts +8 -4
  286. package/src/volume/resources.ts +1 -1
  287. package/src/volume/temporal.ts +11 -0
  288. package/dist/chunk-C3DDSXYK.mjs.map +0 -1
  289. package/dist/chunk-FUUO4UND.mjs.map +0 -1
  290. package/dist/chunk-JRBDO2KB.mjs.map +0 -1
  291. package/dist/chunk-MDQJPY3T.mjs.map +0 -1
  292. package/dist/chunk-PSEQ6QPH.mjs.map +0 -1
  293. package/dist/chunk-S5UE2T5P.mjs.map +0 -1
package/src/index.ts CHANGED
@@ -37,6 +37,14 @@ export {
37
37
  ANTIALIAS_TAA,
38
38
  BLOOM_DISABLED,
39
39
  BLOOM_ENABLED,
40
+ CAMERA_BLOOM_INTENSITY_MAX,
41
+ CAMERA_BLOOM_INTENSITY_MIN,
42
+ CAMERA_BLOOM_SCATTER_MAX,
43
+ CAMERA_BLOOM_SCATTER_MIN,
44
+ CAMERA_BLOOM_SOFT_KNEE_MAX,
45
+ CAMERA_BLOOM_SOFT_KNEE_MIN,
46
+ CAMERA_BLOOM_THRESHOLD_MAX,
47
+ CAMERA_BLOOM_THRESHOLD_MIN,
40
48
  CAMERA_EXPOSURE_MODE_AUTO,
41
49
  CAMERA_EXPOSURE_MODE_MANUAL,
42
50
  CAMERA_PROJECTION_ORTHOGRAPHIC,
@@ -59,6 +67,7 @@ export {
59
67
  TONEMAP_NONE,
60
68
  TONEMAP_REINHARD,
61
69
  TONEMAP_REINHARD_EXTENDED,
70
+ validateCameraBloom,
62
71
  validateCameraColorGrading,
63
72
  validateCameraExposure,
64
73
  } from './components/camera.js';
@@ -74,6 +83,16 @@ export {
74
83
  cubeCameraUpdateIntentFromF32,
75
84
  cubeCameraUpdateIntentToF32,
76
85
  } from './components/cube-camera.js';
86
+ export {
87
+ DepthOfField,
88
+ type DepthOfFieldData,
89
+ type DepthOfFieldQuality,
90
+ DepthOfFieldQualityValue,
91
+ type DepthOfFieldSide,
92
+ DepthOfFieldSideValue,
93
+ depthOfFieldQualityFromF32,
94
+ depthOfFieldSideFromF32,
95
+ } from './components/depth-of-field.js';
77
96
  export * from './components/directional-light.js';
78
97
  export {
79
98
  DynamicResolution,
@@ -145,6 +164,10 @@ export {
145
164
  createDynamicGeometryLifecycle,
146
165
  DynamicGeometryError,
147
166
  } from './dynamic-geometry.js';
167
+ // The environment selector owns this structured recovery error. Keep the
168
+ // class on the public environment path so consumers can branch by `code` and
169
+ // inspect its typed `detail` without importing an owner-private module.
170
+ export { SunCardinalityError } from './environment/frame.js';
148
171
  export type {
149
172
  EnvironmentInspection,
150
173
  EnvironmentInspectionFailure,
@@ -196,6 +219,41 @@ export {
196
219
  type VisibilityResolution,
197
220
  type VisibilitySnapshot,
198
221
  } from './extract/visibility.js';
222
+ export {
223
+ DEFAULT_DEPTH_OF_FIELD_PARAMS,
224
+ DEPTH_OF_FIELD_PARAMS_BYTE_SIZE,
225
+ type DepthOfFieldCameraInput,
226
+ type DepthOfFieldErrorCode,
227
+ type DepthOfFieldErrorDetail,
228
+ type DepthOfFieldParams,
229
+ type DepthOfFieldRequestFailure,
230
+ DepthOfFieldValidationError,
231
+ depthOfFieldQualityCode,
232
+ depthOfFieldRequestFailure,
233
+ depthOfFieldSideCode,
234
+ depthOfFieldTapCount,
235
+ packDepthOfFieldParams,
236
+ resolveDepthOfFieldParams,
237
+ signedDepthOfFieldCoC,
238
+ validateDepthOfFieldFrameParams,
239
+ validateDepthOfFieldParams,
240
+ } from './features/depth-of-field/depth-of-field-params.js';
241
+ export type {
242
+ MotionBlurInvalidParamsDetail,
243
+ MotionBlurParams,
244
+ MotionBlurSampleTier,
245
+ } from './features/motion-blur/motion-blur-params.js';
246
+ export {
247
+ DEFAULT_MOTION_BLUR_PARAMS,
248
+ effectiveMotionBlurSampleCount,
249
+ isMotionBlurIntervalValid,
250
+ MotionBlurValidationError,
251
+ motionBlurExposureScale,
252
+ motionBlurSampleDelta,
253
+ motionBlurTemporalDemand,
254
+ resolveMotionBlurParams,
255
+ validateMotionBlurParams,
256
+ } from './features/motion-blur/motion-blur-params.js';
199
257
  export type {
200
258
  RenderFeatureLogicalTarget,
201
259
  RenderFeatureMaterialShaderBindingContract,
@@ -216,6 +274,7 @@ export type {
216
274
  RenderFeatureHiddenEntityReport,
217
275
  RenderFeatureShaderModuleMode,
218
276
  RenderFeatureStatus,
277
+ RenderFeatureSubmission,
219
278
  RenderFeatureWorldVisibilitySnapshot,
220
279
  } from './features/types.js';
221
280
  export {
@@ -232,6 +291,8 @@ export {
232
291
  } from './ibl/kernel-cache.js';
233
292
  export type {
234
293
  BloomInspection,
294
+ DepthOfFieldInspection,
295
+ DepthOfFieldInspectionStatus,
235
296
  GpuDrivenLane,
236
297
  GpuDrivenLaneReason,
237
298
  GpuDrivenLaneSummary,
@@ -241,7 +302,10 @@ export type {
241
302
  LightInspection,
242
303
  LodOcclusionInspection,
243
304
  MaterialTextureSourceInspection,
305
+ MotionBlurExecutionPass,
306
+ MotionBlurExecutionReceipt,
244
307
  MotionBlurInspection,
308
+ MotionBlurInspectionLane,
245
309
  MotionBlurInspectionStatus,
246
310
  ReflectionFallbackFailureStage,
247
311
  ReflectionFallbackInspection,
@@ -9,6 +9,7 @@ import type {
9
9
  GpuDrivenPreparationErrorCode,
10
10
  GpuDrivenPreparationErrorDetail,
11
11
  } from './errors/gpu-driven';
12
+ import type { DepthOfFieldRequestFailure } from './features/depth-of-field/depth-of-field-params';
12
13
  import type { PointsLinesInspection } from './points-lines/inspection';
13
14
  import type { LodOcclusionInspection } from './scene/visibility/inspection';
14
15
  import type { SsrAdmissionIdentity } from './ssr/identity';
@@ -91,6 +92,10 @@ export type BloomGraphStatus = 'empty' | 'valid' | 'invalid';
91
92
  export interface BloomInspection {
92
93
  readonly graphStatus: BloomGraphStatus;
93
94
  readonly enabled: boolean;
95
+ readonly levelCount: number;
96
+ readonly levelDimensions: readonly { readonly width: number; readonly height: number }[];
97
+ readonly downsamplePassCount: number;
98
+ readonly upsamplePassCount: number;
94
99
  readonly targetCount: number;
95
100
  readonly targetBytes: number;
96
101
  readonly resourceCount: number;
@@ -98,10 +103,30 @@ export interface BloomInspection {
98
103
  readonly encodeCount: number;
99
104
  readonly bindGroupCount: number;
100
105
  readonly uploadCount: number;
106
+ /** Descriptor-derived bytes for the active Bloom target child in the compiled graph. */
101
107
  readonly residentChildBytes: number;
102
108
  readonly generation: number;
103
109
  readonly state: 'off' | 'active' | 'retiring';
104
110
  }
111
+
112
+ export const emptyBloomInspection = (): BloomInspection => ({
113
+ graphStatus: 'empty',
114
+ enabled: false,
115
+ levelCount: 0,
116
+ levelDimensions: [],
117
+ downsamplePassCount: 0,
118
+ upsamplePassCount: 0,
119
+ targetCount: 0,
120
+ targetBytes: 0,
121
+ resourceCount: 0,
122
+ passCount: 0,
123
+ encodeCount: 0,
124
+ bindGroupCount: 0,
125
+ uploadCount: 0,
126
+ residentChildBytes: 0,
127
+ generation: 0,
128
+ state: 'off',
129
+ });
105
130
  export type { TransmissionInspection } from './transmission/inspection';
106
131
 
107
132
  export interface BatchTopologyInspection {
@@ -554,18 +579,89 @@ export interface TemporalTargetInspection {
554
579
  }
555
580
 
556
581
  /** Detached, bounded Motion Blur facts; no graph, device, target, or history handle. */
557
- export type MotionBlurInspectionStatus = 'off' | 'active' | 'reset' | 'invalid';
582
+ export type MotionBlurInspectionStatus = 'off' | 'active' | 'reset' | 'limited' | 'invalid';
583
+ export type MotionBlurInspectionLane = 'compute' | 'raster-limited';
584
+
585
+ /**
586
+ * Submission receipt for the admitted compute lane. This is derived from the
587
+ * compiled graph and the resolved feature dispatches after a successful
588
+ * queue submit; capability intent alone never produces this receipt.
589
+ */
590
+ export interface MotionBlurExecutionPass {
591
+ readonly name: 'motion-blur-tile-summary' | 'motion-blur';
592
+ readonly kind: 'compute';
593
+ readonly entryPoint: 'tile_summary' | 'reconstruct';
594
+ readonly workgroups: readonly [number, number, number];
595
+ }
596
+
597
+ export interface MotionBlurExecutionReceipt {
598
+ readonly frameId: number;
599
+ readonly deviceGeneration: number;
600
+ readonly graphGeneration: number;
601
+ readonly program: 'motion-blur-compute';
602
+ readonly outputFormat: 'rgba16float';
603
+ readonly passes: readonly [MotionBlurExecutionPass, MotionBlurExecutionPass];
604
+ }
605
+
606
+ /** Bounded renderer-owned Depth of Field facts; no graph or GPU handles. */
607
+ export type DepthOfFieldInspectionStatus = 'off' | 'active' | 'reset' | 'invalid' | 'unsupported';
608
+
609
+ export interface DepthOfFieldInspection {
610
+ readonly enabled: boolean;
611
+ readonly status: DepthOfFieldInspectionStatus;
612
+ readonly requested: {
613
+ readonly focusDistance: number;
614
+ readonly fStop: number;
615
+ readonly sensorHeight: number;
616
+ readonly maxRadiusPixels: number;
617
+ readonly quality: 'low' | 'medium' | 'high';
618
+ readonly blurSide: 'both' | 'near' | 'far';
619
+ };
620
+ readonly effective?: DepthOfFieldInspection['requested'];
621
+ readonly focalLength: number;
622
+ readonly outputExtent: { readonly width: number; readonly height: number };
623
+ readonly workExtent: { readonly width: number; readonly height: number };
624
+ readonly tapCount: 0 | 16 | 32 | 64;
625
+ readonly passCount: number;
626
+ readonly textureBytes: number;
627
+ readonly transparentPolicy: 'opaque-depth-approximation';
628
+ readonly graphGeneration: number;
629
+ readonly deviceGeneration: number;
630
+ readonly lastKnownGood: boolean;
631
+ /** Structured authoring validation facts, when admission rejected the request. */
632
+ readonly error?: DepthOfFieldRequestFailure;
633
+ readonly fallbackReason?:
634
+ | 'zero-radius'
635
+ | 'orthographic-unsupported'
636
+ | 'invalid-params'
637
+ | 'shader-not-ready'
638
+ | 'candidate-failed'
639
+ | 'capability-unavailable'
640
+ | undefined;
641
+ }
558
642
 
559
643
  export interface MotionBlurInspection {
560
644
  readonly enabled: boolean;
561
645
  readonly status: MotionBlurInspectionStatus;
646
+ /** Capability-selected implementation lane; raster is explicitly limited. */
647
+ readonly lane: MotionBlurInspectionLane;
562
648
  readonly shutterAngle: number;
563
649
  readonly maxRadiusPixels: number;
564
650
  readonly sampleCount: number;
651
+ /** Target presentation rate used by the accepted exposure calculation. */
652
+ readonly targetFps: number;
653
+ /** Bounded tier selected from the authored sample budget. */
654
+ readonly effectiveSampleCount: 0 | 4 | 8 | 16;
565
655
  readonly temporalDemand: 'none' | 'scene-data-temporal-v1';
566
656
  readonly passName: 'motion-blur';
567
657
  readonly historyWrites: 0;
568
- readonly lastFailure?: 'invalid-params' | 'scene-data-unavailable';
658
+ /** Zero when demand is disabled; compute uses one summary plus one fused pass. */
659
+ readonly passCount: 0 | 1 | 2;
660
+ readonly tapBudget: 0 | 4 | 8 | 16;
661
+ /** Present only when the current accepted frame executed both compute passes. */
662
+ readonly execution?: MotionBlurExecutionReceipt;
663
+ readonly resetReason?: import('./temporal/view').TemporalResetReason;
664
+ readonly lastFailure?: 'invalid-params' | 'scene-data-unavailable' | 'submit-failure';
569
665
  }
570
666
 
571
667
  export type RenderSceneResyncReason =
package/src/instances.ts CHANGED
@@ -41,6 +41,8 @@ export function instanceUploadRangesForResident(
41
41
 
42
42
  export interface InstanceCollectionSnapshot extends InstanceCollectionInfo {
43
43
  readonly transforms: Float32Array;
44
+ /** Unique identity generations that travel with an instance through reorder. */
45
+ readonly generations: Uint32Array;
44
46
  readonly dirtyRanges: readonly InstanceDirtyRange[];
45
47
  }
46
48
 
@@ -171,6 +173,7 @@ export type InstanceCollectionResult<T> = Result<T, InstanceCollectionError>;
171
173
  interface CollectionRecord {
172
174
  readonly id: InstanceCollectionId;
173
175
  transforms: Float32Array;
176
+ generations: Uint32Array;
174
177
  count: number;
175
178
  capacity: number;
176
179
  revision: number;
@@ -307,6 +310,7 @@ function missing(
307
310
  */
308
311
  export class InstanceCollectionStore {
309
312
  private nextId = 1;
313
+ private nextInstanceGeneration = 1;
310
314
  private epochValue = 0;
311
315
  private disposed = false;
312
316
  private readonly records = new Map<InstanceCollectionId, CollectionRecord>();
@@ -330,9 +334,11 @@ export class InstanceCollectionStore {
330
334
  if (invalidPayload !== undefined) return err(invalidPayload);
331
335
  const id = this.nextId++ as InstanceCollectionId;
332
336
  const count = input.transforms.length / MATRIX_STRIDE;
337
+ const generations = this.allocateGenerations(count);
333
338
  const record: CollectionRecord = {
334
339
  id,
335
340
  transforms: new Float32Array(input.transforms),
341
+ generations,
336
342
  count,
337
343
  capacity: nextCapacity(Math.max(INITIAL_CAPACITY, count)),
338
344
  revision: 1,
@@ -348,13 +354,26 @@ export class InstanceCollectionStore {
348
354
  replace(
349
355
  id: InstanceCollectionId,
350
356
  transforms: Float32Array,
357
+ /** Prior identity generations in the replacement order; omitted rows are new. */
358
+ generations?: Uint32Array,
351
359
  ): InstanceCollectionResult<InstanceCollectionInfo> {
352
360
  const record = this.live('replace', id);
353
361
  if (!record.ok) return record;
354
362
  const invalidPayload = validateTransforms('replace', transforms, id);
355
363
  if (invalidPayload !== undefined) return err(invalidPayload);
356
364
  const count = transforms.length / MATRIX_STRIDE;
365
+ const generationResult =
366
+ generations === undefined
367
+ ? ok(this.allocateGenerations(count))
368
+ : this.validateReplacementGenerations(generations, count, id);
369
+ if (!generationResult.ok) return generationResult;
370
+ // Replacement is a topology boundary by default. A producer that keeps
371
+ // logical instance identity through compaction/reorder may pass the prior
372
+ // generation tokens in their new order; the record stage then maps the
373
+ // real previous transform by token instead of by draw ordinal.
374
+ const replacementGenerations = generationResult.value;
357
375
  record.value.transforms = new Float32Array(transforms);
376
+ record.value.generations = replacementGenerations;
358
377
  record.value.count = count;
359
378
  record.value.capacity = Math.max(record.value.capacity, nextCapacity(Math.max(1, count)));
360
379
  record.value.revision += 1;
@@ -402,6 +421,11 @@ export class InstanceCollectionStore {
402
421
  record.value.dirtyRanges = [];
403
422
  }
404
423
  record.value.transforms.set(input.transforms, input.start * MATRIX_STRIDE);
424
+ // An update changes a pose while retaining the same ordinal identity.
425
+ // Keep its generation stable so the record stage can pair this current
426
+ // transform with the last submitted transform and expose real velocity.
427
+ // `replace` is the explicit topology boundary that advances generations
428
+ // for compaction, reorder, retirement, and newly occupied ordinals.
405
429
  record.value.revision += 1;
406
430
  appendDirtyRange(record.value, input.start, input.start + span);
407
431
  this.epochValue += 1;
@@ -505,6 +529,7 @@ export class InstanceCollectionStore {
505
529
  const result = {
506
530
  ...this.info(value),
507
531
  transforms: new Float32Array(value.transforms),
532
+ generations: new Uint32Array(value.generations),
508
533
  dirtyRanges: value.dirtyRanges.map((range) => ({ ...range })),
509
534
  };
510
535
  // Keep the current ranges stable for repeated reads by entities sharing
@@ -513,6 +538,16 @@ export class InstanceCollectionStore {
513
538
  return ok(result);
514
539
  }
515
540
 
541
+ /**
542
+ * Read a detached matrix view without advancing the render-consumption
543
+ * cursor. Inspection and picking may call this between authoring updates;
544
+ * the next renderer snapshot must still receive the complete dirty union.
545
+ */
546
+ peek(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionSnapshot> {
547
+ const record = this.live('inspect', id);
548
+ return record.ok ? ok(this.detachedSnapshot(record.value)) : record;
549
+ }
550
+
516
551
  release(id: InstanceCollectionId): InstanceCollectionResult<void> {
517
552
  const record = this.records.get(id);
518
553
  if (record === undefined) return err(missing('release', id));
@@ -569,6 +604,15 @@ export class InstanceCollectionStore {
569
604
  return record === undefined ? err(missing(operation, id)) : ok(record);
570
605
  }
571
606
 
607
+ private detachedSnapshot(record: CollectionRecord): InstanceCollectionSnapshot {
608
+ return {
609
+ ...this.info(record),
610
+ transforms: new Float32Array(record.transforms),
611
+ generations: new Uint32Array(record.generations),
612
+ dirtyRanges: record.dirtyRanges.map((range) => ({ ...range })),
613
+ };
614
+ }
615
+
572
616
  private info(record: CollectionRecord): InstanceCollectionInfo {
573
617
  return Object.freeze({
574
618
  collectionId: record.id,
@@ -578,6 +622,55 @@ export class InstanceCollectionStore {
578
622
  });
579
623
  }
580
624
 
625
+ private allocateGenerations(count: number): Uint32Array {
626
+ const generations = new Uint32Array(count);
627
+ for (let index = 0; index < count; index += 1) {
628
+ generations[index] = this.nextInstanceGeneration;
629
+ this.nextInstanceGeneration = (this.nextInstanceGeneration + 1) >>> 0 || 1;
630
+ }
631
+ return generations;
632
+ }
633
+
634
+ private validateReplacementGenerations(
635
+ generations: Uint32Array,
636
+ count: number,
637
+ collectionId: InstanceCollectionId,
638
+ ): InstanceCollectionResult<Uint32Array> {
639
+ if (!(generations instanceof Uint32Array) || generations.length !== count) {
640
+ return err(
641
+ invalid(
642
+ 'replace',
643
+ `generations is a Uint32Array with ${count} entries`,
644
+ generations instanceof Uint32Array ? generations.length : typeof generations,
645
+ collectionId,
646
+ { requestedBytes: generations?.byteLength ?? 0, cause: 'invalid-generation-shape' },
647
+ ),
648
+ );
649
+ }
650
+ const seen = new Set<number>();
651
+ for (const generation of generations) {
652
+ if (generation === 0 || seen.has(generation)) {
653
+ return err(
654
+ invalid(
655
+ 'replace',
656
+ 'generations contain unique non-zero identity tokens',
657
+ generation,
658
+ collectionId,
659
+ {
660
+ requestedBytes: generations.byteLength,
661
+ cause: 'invalid-generation-identity',
662
+ },
663
+ ),
664
+ );
665
+ }
666
+ seen.add(generation);
667
+ if (generation >= this.nextInstanceGeneration) {
668
+ this.nextInstanceGeneration = (generation + 1) >>> 0 || 1;
669
+ }
670
+ }
671
+ return ok(new Uint32Array(generations));
672
+ }
673
+
581
674
  private projectInspection(record: CollectionRecord): InstanceCollectionInspection {
582
675
  const residency = this.residency.get(record.id);
583
676
  return Object.freeze({
@@ -112,6 +112,8 @@ export interface MeshMaterialBindingResidency {
112
112
  /** Public read-only observation of the bindings used by the last frame. */
113
113
  export interface MeshMaterialBindingObservation {
114
114
  readonly worldId: number;
115
+ /** Stable World identity for cross-world inspection; worldId is only a frame slot. */
116
+ readonly worldIdentity?: string;
115
117
  readonly entityKey: number;
116
118
  readonly bindings: readonly ResolvedMeshMaterialBinding[];
117
119
  readonly diagnostics: readonly MeshMaterialBindingDiagnostic[];
@@ -143,6 +145,7 @@ const EMPTY_RESIDENCY: MeshMaterialBindingResidency = Object.freeze({
143
145
  */
144
146
  export function projectMeshMaterialBindingObservation(input: {
145
147
  readonly worldId: number;
148
+ readonly worldIdentity?: string;
146
149
  readonly entityKey: number;
147
150
  readonly bindings: readonly ResolvedMeshMaterialBinding[];
148
151
  readonly diagnostics: readonly MeshMaterialBindingDiagnostic[];
@@ -168,6 +171,7 @@ export function projectMeshMaterialBindingObservation(input: {
168
171
  });
169
172
  return {
170
173
  worldId: input.worldId,
174
+ ...(input.worldIdentity === undefined ? {} : { worldIdentity: input.worldIdentity }),
171
175
  entityKey: input.entityKey,
172
176
  bindings: Object.freeze([...input.bindings]),
173
177
  diagnostics: Object.freeze([...input.diagnostics]),
@@ -26,6 +26,7 @@ function requestedStages(input: StandardOutputRequest): StandardOutputLogicalSta
26
26
  const stages: StandardOutputLogicalStage[] = [];
27
27
  if (input.temporal) stages.push('temporal');
28
28
  if (input.meter) stages.push('meter');
29
+ if (input.dof === true) stages.push('dof');
29
30
  if (input.bloom) stages.push('bloom');
30
31
  if (input.exposure || input.whiteBalance) stages.push('exposure-white-balance');
31
32
  stages.push('tone');
@@ -43,6 +44,7 @@ function physicalStages(
43
44
  case 'temporal':
44
45
  case 'meter':
45
46
  case 'bloom':
47
+ case 'dof':
46
48
  case 'exposure-white-balance':
47
49
  return { name, input: LINEAR_HDR_DOMAIN, output: LINEAR_HDR_DOMAIN };
48
50
  case 'tone':
@@ -68,6 +70,7 @@ export function createStandardOutputPlan(input: StandardOutputRequest): Standard
68
70
  temporal: input.temporal,
69
71
  meter: input.meter,
70
72
  bloom: input.bloom,
73
+ dof: input.dof === true,
71
74
  exposure: input.exposure,
72
75
  whiteBalance: input.whiteBalance,
73
76
  lut: input.lut,
@@ -3,6 +3,7 @@ import type { ColorValueDomain } from '@forgeax/engine-render-graph';
3
3
  export const STANDARD_OUTPUT_LOGICAL_STAGES = [
4
4
  'temporal',
5
5
  'meter',
6
+ 'dof',
6
7
  'bloom',
7
8
  'exposure-white-balance',
8
9
  'tone',
@@ -26,6 +27,8 @@ export interface StandardOutputRequest {
26
27
  readonly temporal: boolean;
27
28
  readonly meter: boolean;
28
29
  readonly bloom: boolean;
30
+ /** Built-in spatial DoF stage; false keeps the path exact-zero. */
31
+ readonly dof?: boolean;
29
32
  readonly exposure: boolean;
30
33
  readonly whiteBalance: boolean;
31
34
  readonly lut: boolean;
@@ -44,7 +47,7 @@ export interface StandardOutputPlan {
44
47
  readonly features: Readonly<
45
48
  Pick<
46
49
  StandardOutputRequest,
47
- 'temporal' | 'meter' | 'bloom' | 'exposure' | 'whiteBalance' | 'lut' | 'fxaa'
50
+ 'temporal' | 'meter' | 'bloom' | 'dof' | 'exposure' | 'whiteBalance' | 'lut' | 'fxaa'
48
51
  >
49
52
  >;
50
53
  readonly outputEncoding: StandardOutputEncoding;