@forgeax/engine-runtime 0.1.2

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 (937) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +183 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/active-camera.unit.test.d.ts +2 -0
  5. package/dist/__tests__/active-camera.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/animation-graph-add.unit.test.d.ts +2 -0
  7. package/dist/__tests__/animation-graph-add.unit.test.d.ts.map +1 -0
  8. package/dist/__tests__/animation-graph-asset-union.test-d.d.ts +2 -0
  9. package/dist/__tests__/animation-graph-asset-union.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/animation-graph-blend.unit.test.d.ts +2 -0
  11. package/dist/__tests__/animation-graph-blend.unit.test.d.ts.map +1 -0
  12. package/dist/__tests__/animation-graph-build.unit.test.d.ts +2 -0
  13. package/dist/__tests__/animation-graph-build.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/animation-graph-clip-missing.unit.test.d.ts +2 -0
  15. package/dist/__tests__/animation-graph-clip-missing.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/animation-graph-clip.unit.test.d.ts +2 -0
  17. package/dist/__tests__/animation-graph-clip.unit.test.d.ts.map +1 -0
  18. package/dist/__tests__/animation-graph-default-path.integration.test.d.ts +2 -0
  19. package/dist/__tests__/animation-graph-default-path.integration.test.d.ts.map +1 -0
  20. package/dist/__tests__/animation-graph-describe.unit.test.d.ts +2 -0
  21. package/dist/__tests__/animation-graph-describe.unit.test.d.ts.map +1 -0
  22. package/dist/__tests__/animation-graph-errors.unit.test.d.ts +2 -0
  23. package/dist/__tests__/animation-graph-errors.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/animation-graph-nesting.unit.test.d.ts +2 -0
  25. package/dist/__tests__/animation-graph-nesting.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts +2 -0
  27. package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts +2 -0
  29. package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/animation-nslot.unit.test.d.ts +2 -0
  31. package/dist/__tests__/animation-nslot.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts +2 -0
  33. package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/append-injection.test.d.ts +2 -0
  35. package/dist/__tests__/append-injection.test.d.ts.map +1 -0
  36. package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts +2 -0
  37. package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/asi-world-ci-config.unit.test.d.ts +2 -0
  39. package/dist/__tests__/asi-world-ci-config.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/asi-world-smoke.unit.test.d.ts +2 -0
  41. package/dist/__tests__/asi-world-smoke.unit.test.d.ts.map +1 -0
  42. package/dist/__tests__/asset-registry-scene.test-d.d.ts +2 -0
  43. package/dist/__tests__/asset-registry-scene.test-d.d.ts.map +1 -0
  44. package/dist/__tests__/bind-group-cache-binding.test.d.ts +2 -0
  45. package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +1 -0
  46. package/dist/__tests__/bind-group-cache-frame.test.d.ts +2 -0
  47. package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +1 -0
  48. package/dist/__tests__/bind-group-cache-keying.test.d.ts +2 -0
  49. package/dist/__tests__/bind-group-cache-keying.test.d.ts.map +1 -0
  50. package/dist/__tests__/block-upload-math.unit.test.d.ts +2 -0
  51. package/dist/__tests__/block-upload-math.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/builtin-shader-register-e2e.test.d.ts +2 -0
  53. package/dist/__tests__/builtin-shader-register-e2e.test.d.ts.map +1 -0
  54. package/dist/__tests__/cache-false-eviction.test.d.ts +2 -0
  55. package/dist/__tests__/cache-false-eviction.test.d.ts.map +1 -0
  56. package/dist/__tests__/cache-isolation-matrix.test.d.ts +2 -0
  57. package/dist/__tests__/cache-isolation-matrix.test.d.ts.map +1 -0
  58. package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts +2 -0
  59. package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts.map +1 -0
  60. package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts +2 -0
  61. package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts.map +1 -0
  62. package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts +2 -0
  63. package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts.map +1 -0
  64. package/dist/__tests__/collect-scene-asset.test.d.ts +3 -0
  65. package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -0
  66. package/dist/__tests__/collect-subtree.unit.test.d.ts +2 -0
  67. package/dist/__tests__/collect-subtree.unit.test.d.ts.map +1 -0
  68. package/dist/__tests__/collect-transient-children-absent.test.d.ts +2 -0
  69. package/dist/__tests__/collect-transient-children-absent.test.d.ts.map +1 -0
  70. package/dist/__tests__/collect-transient-roundtrip.test.d.ts +2 -0
  71. package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -0
  72. package/dist/__tests__/collect-transient-skip.test.d.ts +3 -0
  73. package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -0
  74. package/dist/__tests__/components.test-d.d.ts +2 -0
  75. package/dist/__tests__/components.test-d.d.ts.map +1 -0
  76. package/dist/__tests__/components.unit.test.d.ts +2 -0
  77. package/dist/__tests__/components.unit.test.d.ts.map +1 -0
  78. package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts +2 -0
  79. package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts.map +1 -0
  80. package/dist/__tests__/create-renderer-assembly.integration.test.d.ts +2 -0
  81. package/dist/__tests__/create-renderer-assembly.integration.test.d.ts.map +1 -0
  82. package/dist/__tests__/createRenderer-dispose.test.d.ts +2 -0
  83. package/dist/__tests__/createRenderer-dispose.test.d.ts.map +1 -0
  84. package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts +2 -0
  85. package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts.map +1 -0
  86. package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts +2 -0
  87. package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts.map +1 -0
  88. package/dist/__tests__/createRenderer.unit.test.d.ts +2 -0
  89. package/dist/__tests__/createRenderer.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts +2 -0
  91. package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts.map +1 -0
  92. package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts +2 -0
  93. package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts.map +1 -0
  94. package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts +2 -0
  95. package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts.map +1 -0
  96. package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts +2 -0
  97. package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts.map +1 -0
  98. package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts +2 -0
  99. package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts.map +1 -0
  100. package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts +2 -0
  101. package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts.map +1 -0
  102. package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts +2 -0
  103. package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts.map +1 -0
  104. package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts +2 -0
  105. package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts.map +1 -0
  106. package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts +2 -0
  107. package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts.map +1 -0
  108. package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts +2 -0
  109. package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts.map +1 -0
  110. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +2 -0
  111. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +1 -0
  112. package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts +2 -0
  113. package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts.map +1 -0
  114. package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts +2 -0
  115. package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts.map +1 -0
  116. package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts +2 -0
  117. package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts.map +1 -0
  118. package/dist/__tests__/dawn/tonemap.dawn.test.d.ts +2 -0
  119. package/dist/__tests__/dawn/tonemap.dawn.test.d.ts.map +1 -0
  120. package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts +2 -0
  121. package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts.map +1 -0
  122. package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts +2 -0
  123. package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts.map +1 -0
  124. package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts +2 -0
  125. package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts.map +1 -0
  126. package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts +2 -0
  127. package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts.map +1 -0
  128. package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts +2 -0
  129. package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts.map +1 -0
  130. package/dist/__tests__/derive-bgl-integration.test.d.ts +2 -0
  131. package/dist/__tests__/derive-bgl-integration.test.d.ts.map +1 -0
  132. package/dist/__tests__/derive-render-data-skin.unit.test.d.ts +2 -0
  133. package/dist/__tests__/derive-render-data-skin.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +2 -0
  135. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +1 -0
  136. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +2 -0
  137. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +1 -0
  138. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +2 -0
  139. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +1 -0
  140. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +2 -0
  141. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +1 -0
  142. package/dist/__tests__/draw-published.d.ts +5 -0
  143. package/dist/__tests__/draw-published.d.ts.map +1 -0
  144. package/dist/__tests__/environment-error-exhaustive.test-d.d.ts +8 -0
  145. package/dist/__tests__/environment-error-exhaustive.test-d.d.ts.map +1 -0
  146. package/dist/__tests__/equirect-bc6h.integration.test.d.ts +2 -0
  147. package/dist/__tests__/equirect-bc6h.integration.test.d.ts.map +1 -0
  148. package/dist/__tests__/error-exhaustive.test.d.ts +2 -0
  149. package/dist/__tests__/error-exhaustive.test.d.ts.map +1 -0
  150. package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts +2 -0
  151. package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts.map +1 -0
  152. package/dist/__tests__/extract-frames-merge.test.d.ts +2 -0
  153. package/dist/__tests__/extract-frames-merge.test.d.ts.map +1 -0
  154. package/dist/__tests__/extract-frames-reset.test.d.ts +2 -0
  155. package/dist/__tests__/extract-frames-reset.test.d.ts.map +1 -0
  156. package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts +2 -0
  157. package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts.map +1 -0
  158. package/dist/__tests__/fog-producer-manifest.d.ts +131 -0
  159. package/dist/__tests__/fog-producer-manifest.d.ts.map +1 -0
  160. package/dist/__tests__/fog-producer-pixel-probe.d.ts +42 -0
  161. package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +1 -0
  162. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +2 -0
  163. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +1 -0
  164. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +2 -0
  165. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +1 -0
  166. package/dist/__tests__/fog-producer-real-fixture.d.ts +5 -0
  167. package/dist/__tests__/fog-producer-real-fixture.d.ts.map +1 -0
  168. package/dist/__tests__/fog-producer-vfx-effect.d.ts +3 -0
  169. package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +1 -0
  170. package/dist/__tests__/fog-scene-asset.integration.test.d.ts +2 -0
  171. package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +1 -0
  172. package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts +2 -0
  173. package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts.map +1 -0
  174. package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts +2 -0
  175. package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts.map +1 -0
  176. package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts +2 -0
  177. package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts.map +1 -0
  178. package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts +2 -0
  179. package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts.map +1 -0
  180. package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts +2 -0
  181. package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts.map +1 -0
  182. package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts +2 -0
  183. package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts.map +1 -0
  184. package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts +2 -0
  185. package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts.map +1 -0
  186. package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts +2 -0
  187. package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts.map +1 -0
  188. package/dist/__tests__/geometry.unit.test.d.ts +2 -0
  189. package/dist/__tests__/geometry.unit.test.d.ts.map +1 -0
  190. package/dist/__tests__/glyph-tilemap-worldid.test.d.ts +2 -0
  191. package/dist/__tests__/glyph-tilemap-worldid.test.d.ts.map +1 -0
  192. package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts +2 -0
  193. package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts.map +1 -0
  194. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +2 -0
  195. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +1 -0
  196. package/dist/__tests__/gpu-resource.test.d.ts +2 -0
  197. package/dist/__tests__/gpu-resource.test.d.ts.map +1 -0
  198. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +2 -0
  199. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +1 -0
  200. package/dist/__tests__/hdrp-buffers.unit.test.d.ts +2 -0
  201. package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +1 -0
  202. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +2 -0
  203. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +1 -0
  204. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +2 -0
  205. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +1 -0
  206. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +2 -0
  207. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +1 -0
  208. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +2 -0
  209. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +1 -0
  210. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +2 -0
  211. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +1 -0
  212. package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts +2 -0
  213. package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts.map +1 -0
  214. package/dist/__tests__/helpers/mock-shader-registry.d.ts +11 -0
  215. package/dist/__tests__/helpers/mock-shader-registry.d.ts.map +1 -0
  216. package/dist/__tests__/helpers/primitive-world.d.ts +8 -0
  217. package/dist/__tests__/helpers/primitive-world.d.ts.map +1 -0
  218. package/dist/__tests__/helpers/register-runtime-components.d.ts +4 -0
  219. package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -0
  220. package/dist/__tests__/helpers/register-scene-components.d.ts +4 -0
  221. package/dist/__tests__/helpers/register-scene-components.d.ts.map +1 -0
  222. package/dist/__tests__/helpers/render-asset-port.d.ts +15 -0
  223. package/dist/__tests__/helpers/render-asset-port.d.ts.map +1 -0
  224. package/dist/__tests__/helpers/scene-asset-port.d.ts +9 -0
  225. package/dist/__tests__/helpers/scene-asset-port.d.ts.map +1 -0
  226. package/dist/__tests__/helpers/tilemap-assets.d.ts +6 -0
  227. package/dist/__tests__/helpers/tilemap-assets.d.ts.map +1 -0
  228. package/dist/__tests__/instances.test-d.d.ts +2 -0
  229. package/dist/__tests__/instances.test-d.d.ts.map +1 -0
  230. package/dist/__tests__/light-attenuation-formula.test.d.ts +2 -0
  231. package/dist/__tests__/light-attenuation-formula.test.d.ts.map +1 -0
  232. package/dist/__tests__/light-casters-9-light.browser.test.d.ts +2 -0
  233. package/dist/__tests__/light-casters-9-light.browser.test.d.ts.map +1 -0
  234. package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts +2 -0
  235. package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts.map +1 -0
  236. package/dist/__tests__/light-snapshot.test-d.d.ts +2 -0
  237. package/dist/__tests__/light-snapshot.test-d.d.ts.map +1 -0
  238. package/dist/__tests__/lights-vec-negative.unit.test.d.ts +2 -0
  239. package/dist/__tests__/lights-vec-negative.unit.test.d.ts.map +1 -0
  240. package/dist/__tests__/lights.unit.test.d.ts +2 -0
  241. package/dist/__tests__/lights.unit.test.d.ts.map +1 -0
  242. package/dist/__tests__/m3-vec-negative.unit.test.d.ts +2 -0
  243. package/dist/__tests__/m3-vec-negative.unit.test.d.ts.map +1 -0
  244. package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts +2 -0
  245. package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts.map +1 -0
  246. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +2 -0
  247. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +1 -0
  248. package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts +2 -0
  249. package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts.map +1 -0
  250. package/dist/__tests__/materials.unit.test.d.ts +2 -0
  251. package/dist/__tests__/materials.unit.test.d.ts.map +1 -0
  252. package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts +2 -0
  253. package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts.map +1 -0
  254. package/dist/__tests__/mip-gate.unit.test.d.ts +2 -0
  255. package/dist/__tests__/mip-gate.unit.test.d.ts.map +1 -0
  256. package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts +2 -0
  257. package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts.map +1 -0
  258. package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts +2 -0
  259. package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts.map +1 -0
  260. package/dist/__tests__/name.unit.test.d.ts +2 -0
  261. package/dist/__tests__/name.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/pass-selector.unit.test.d.ts +2 -0
  263. package/dist/__tests__/pass-selector.unit.test.d.ts.map +1 -0
  264. package/dist/__tests__/pbr-pipeline.unit.test.d.ts +2 -0
  265. package/dist/__tests__/pbr-pipeline.unit.test.d.ts.map +1 -0
  266. package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts +2 -0
  267. package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts.map +1 -0
  268. package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts +2 -0
  269. package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts.map +1 -0
  270. package/dist/__tests__/pipeline-layout-selection.test.d.ts +2 -0
  271. package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +1 -0
  272. package/dist/__tests__/pipeline-spec.test.d.ts +2 -0
  273. package/dist/__tests__/pipeline-spec.test.d.ts.map +1 -0
  274. package/dist/__tests__/pipeline.unit.test.d.ts +2 -0
  275. package/dist/__tests__/pipeline.unit.test.d.ts.map +1 -0
  276. package/dist/__tests__/point-light-shadow.browser.test.d.ts +2 -0
  277. package/dist/__tests__/point-light-shadow.browser.test.d.ts.map +1 -0
  278. package/dist/__tests__/point-light-shadow.dawn.test.d.ts +2 -0
  279. package/dist/__tests__/point-light-shadow.dawn.test.d.ts.map +1 -0
  280. package/dist/__tests__/point-light-shadow.unit.test.d.ts +2 -0
  281. package/dist/__tests__/point-light-shadow.unit.test.d.ts.map +1 -0
  282. package/dist/__tests__/post-process-error-codes.unit.test.d.ts +2 -0
  283. package/dist/__tests__/post-process-error-codes.unit.test.d.ts.map +1 -0
  284. package/dist/__tests__/post-process-params-component.unit.test.d.ts +2 -0
  285. package/dist/__tests__/post-process-params-component.unit.test.d.ts.map +1 -0
  286. package/dist/__tests__/post-process-params-extract.unit.test.d.ts +2 -0
  287. package/dist/__tests__/post-process-params-extract.unit.test.d.ts.map +1 -0
  288. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +2 -0
  289. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +1 -0
  290. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +2 -0
  291. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +1 -0
  292. package/dist/__tests__/postprocess-camera-consistency.test.d.ts +2 -0
  293. package/dist/__tests__/postprocess-camera-consistency.test.d.ts.map +1 -0
  294. package/dist/__tests__/profiler-assembly.integration.test.d.ts +2 -0
  295. package/dist/__tests__/profiler-assembly.integration.test.d.ts.map +1 -0
  296. package/dist/__tests__/propagate-transforms.dawn.test.d.ts +2 -0
  297. package/dist/__tests__/propagate-transforms.dawn.test.d.ts.map +1 -0
  298. package/dist/__tests__/record-worldid-isolation.test.d.ts +2 -0
  299. package/dist/__tests__/record-worldid-isolation.test.d.ts.map +1 -0
  300. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +11 -0
  301. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -0
  302. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +11 -0
  303. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  304. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  305. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  306. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  307. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  308. package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts +2 -0
  309. package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts.map +1 -0
  310. package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts +2 -0
  311. package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts.map +1 -0
  312. package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts +2 -0
  313. package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts.map +1 -0
  314. package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts +2 -0
  315. package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts.map +1 -0
  316. package/dist/__tests__/render-feature-recover.integration.test.d.ts +2 -0
  317. package/dist/__tests__/render-feature-recover.integration.test.d.ts.map +1 -0
  318. package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts +2 -0
  319. package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts.map +1 -0
  320. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +2 -0
  321. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +1 -0
  322. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +2 -0
  323. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +1 -0
  324. package/dist/__tests__/render-schema-consumer.integration.test.d.ts +2 -0
  325. package/dist/__tests__/render-schema-consumer.integration.test.d.ts.map +1 -0
  326. package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts +2 -0
  327. package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts.map +1 -0
  328. package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts +2 -0
  329. package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts.map +1 -0
  330. package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts +2 -0
  331. package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts.map +1 -0
  332. package/dist/__tests__/render-system-extract.test.d.ts +2 -0
  333. package/dist/__tests__/render-system-extract.test.d.ts.map +1 -0
  334. package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts +2 -0
  335. package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts.map +1 -0
  336. package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts +2 -0
  337. package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts.map +1 -0
  338. package/dist/__tests__/render-system-fold-material.unit.test.d.ts +2 -0
  339. package/dist/__tests__/render-system-fold-material.unit.test.d.ts.map +1 -0
  340. package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts +2 -0
  341. package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts.map +1 -0
  342. package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts +2 -0
  343. package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts.map +1 -0
  344. package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts +2 -0
  345. package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts.map +1 -0
  346. package/dist/__tests__/render-system-fold.dawn.test.d.ts +2 -0
  347. package/dist/__tests__/render-system-fold.dawn.test.d.ts.map +1 -0
  348. package/dist/__tests__/render-system-mega.test.d.ts +2 -0
  349. package/dist/__tests__/render-system-mega.test.d.ts.map +1 -0
  350. package/dist/__tests__/render-system-owner-split-contract.test.d.ts +2 -0
  351. package/dist/__tests__/render-system-owner-split-contract.test.d.ts.map +1 -0
  352. package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts +2 -0
  353. package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts.map +1 -0
  354. package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts +2 -0
  355. package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts.map +1 -0
  356. package/dist/__tests__/render-system-record.test.d.ts +2 -0
  357. package/dist/__tests__/render-system-record.test.d.ts.map +1 -0
  358. package/dist/__tests__/render-system-record.unit.test.d.ts +2 -0
  359. package/dist/__tests__/render-system-record.unit.test.d.ts.map +1 -0
  360. package/dist/__tests__/render-system-skin-bg.unit.test.d.ts +2 -0
  361. package/dist/__tests__/render-system-skin-bg.unit.test.d.ts.map +1 -0
  362. package/dist/__tests__/renderer-consumer.test-d.d.ts +2 -0
  363. package/dist/__tests__/renderer-consumer.test-d.d.ts.map +1 -0
  364. package/dist/__tests__/renderer-health.unit.test.d.ts +2 -0
  365. package/dist/__tests__/renderer-health.unit.test.d.ts.map +1 -0
  366. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  367. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  368. package/dist/__tests__/renderer-recover.unit.test.d.ts +2 -0
  369. package/dist/__tests__/renderer-recover.unit.test.d.ts.map +1 -0
  370. package/dist/__tests__/renderer-result.test-d.d.ts +2 -0
  371. package/dist/__tests__/renderer-result.test-d.d.ts.map +1 -0
  372. package/dist/__tests__/renderer-surface.unit.test.d.ts +2 -0
  373. package/dist/__tests__/renderer-surface.unit.test.d.ts.map +1 -0
  374. package/dist/__tests__/resolve-depth-only-view.test.d.ts +2 -0
  375. package/dist/__tests__/resolve-depth-only-view.test.d.ts.map +1 -0
  376. package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts +2 -0
  377. package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts.map +1 -0
  378. package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts +2 -0
  379. package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts.map +1 -0
  380. package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts +2 -0
  381. package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts.map +1 -0
  382. package/dist/__tests__/roots-to-scene-asset.test.d.ts +2 -0
  383. package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -0
  384. package/dist/__tests__/runtime-authority-scan.unit.test.d.ts +2 -0
  385. package/dist/__tests__/runtime-authority-scan.unit.test.d.ts.map +1 -0
  386. package/dist/__tests__/runtime-domain-residue.unit.test.d.ts +2 -0
  387. package/dist/__tests__/runtime-domain-residue.unit.test.d.ts.map +1 -0
  388. package/dist/__tests__/scene-equirect-roundtrip.test.d.ts +2 -0
  389. package/dist/__tests__/scene-equirect-roundtrip.test.d.ts.map +1 -0
  390. package/dist/__tests__/scene-instance-bridge.integration.test.d.ts +2 -0
  391. package/dist/__tests__/scene-instance-bridge.integration.test.d.ts.map +1 -0
  392. package/dist/__tests__/scene-instance-component.test.d.ts +2 -0
  393. package/dist/__tests__/scene-instance-component.test.d.ts.map +1 -0
  394. package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts +2 -0
  395. package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts.map +1 -0
  396. package/dist/__tests__/serialize-scene-asset.test.d.ts +2 -0
  397. package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -0
  398. package/dist/__tests__/shadow-caster-empty-schema.test.d.ts +2 -0
  399. package/dist/__tests__/shadow-caster-empty-schema.test.d.ts.map +1 -0
  400. package/dist/__tests__/shadow-csm-atlas.test.d.ts +2 -0
  401. package/dist/__tests__/shadow-csm-atlas.test.d.ts.map +1 -0
  402. package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts +2 -0
  403. package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts.map +1 -0
  404. package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts +2 -0
  405. package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts.map +1 -0
  406. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +2 -0
  407. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +1 -0
  408. package/dist/__tests__/shadow-csm-component.test.d.ts +2 -0
  409. package/dist/__tests__/shadow-csm-component.test.d.ts.map +1 -0
  410. package/dist/__tests__/shadow-csm-extract.test.d.ts +2 -0
  411. package/dist/__tests__/shadow-csm-extract.test.d.ts.map +1 -0
  412. package/dist/__tests__/shadow-csm-orthoz.test.d.ts +2 -0
  413. package/dist/__tests__/shadow-csm-orthoz.test.d.ts.map +1 -0
  414. package/dist/__tests__/shadow-csm-pssm.test.d.ts +2 -0
  415. package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +1 -0
  416. package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts +2 -0
  417. package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts.map +1 -0
  418. package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts +2 -0
  419. package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts.map +1 -0
  420. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +2 -0
  421. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +1 -0
  422. package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts +2 -0
  423. package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts.map +1 -0
  424. package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts +2 -0
  425. package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts.map +1 -0
  426. package/dist/__tests__/shadow-csm-ubo.test.d.ts +2 -0
  427. package/dist/__tests__/shadow-csm-ubo.test.d.ts.map +1 -0
  428. package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts +2 -0
  429. package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts.map +1 -0
  430. package/dist/__tests__/shadow-csm-viewport.test.d.ts +2 -0
  431. package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +1 -0
  432. package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts +2 -0
  433. package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts.map +1 -0
  434. package/dist/__tests__/shadow-m1.dawn.test.d.ts +2 -0
  435. package/dist/__tests__/shadow-m1.dawn.test.d.ts.map +1 -0
  436. package/dist/__tests__/shadow-m2.dawn.test.d.ts +2 -0
  437. package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +1 -0
  438. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +2 -0
  439. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +1 -0
  440. package/dist/__tests__/shadow-m3-calibrate.d.ts +83 -0
  441. package/dist/__tests__/shadow-m3-calibrate.d.ts.map +1 -0
  442. package/dist/__tests__/shadow-m3.dawn.test.d.ts +2 -0
  443. package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +1 -0
  444. package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts +2 -0
  445. package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts.map +1 -0
  446. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +2 -0
  447. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +1 -0
  448. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +2 -0
  449. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +1 -0
  450. package/dist/__tests__/skin-error-exhaustive.test-d.d.ts +11 -0
  451. package/dist/__tests__/skin-error-exhaustive.test-d.d.ts.map +1 -0
  452. package/dist/__tests__/skin-errors.unit.test.d.ts +2 -0
  453. package/dist/__tests__/skin-errors.unit.test.d.ts.map +1 -0
  454. package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts +2 -0
  455. package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts.map +1 -0
  456. package/dist/__tests__/skin-parented-double-transform.test.d.ts +14 -0
  457. package/dist/__tests__/skin-parented-double-transform.test.d.ts.map +1 -0
  458. package/dist/__tests__/skylight-lazy-projection.test.d.ts +2 -0
  459. package/dist/__tests__/skylight-lazy-projection.test.d.ts.map +1 -0
  460. package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts +2 -0
  461. package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts.map +1 -0
  462. package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts +2 -0
  463. package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts.map +1 -0
  464. package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts +2 -0
  465. package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts.map +1 -0
  466. package/dist/__tests__/sprite-lit-extract-branch.test.d.ts +2 -0
  467. package/dist/__tests__/sprite-lit-extract-branch.test.d.ts.map +1 -0
  468. package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts +2 -0
  469. package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts.map +1 -0
  470. package/dist/__tests__/sprite-param-values.test-d.d.ts +2 -0
  471. package/dist/__tests__/sprite-param-values.test-d.d.ts.map +1 -0
  472. package/dist/__tests__/ssao-bgl.test.d.ts +2 -0
  473. package/dist/__tests__/ssao-bgl.test.d.ts.map +1 -0
  474. package/dist/__tests__/ssao-buffers.test.d.ts +2 -0
  475. package/dist/__tests__/ssao-buffers.test.d.ts.map +1 -0
  476. package/dist/__tests__/ssao-data.test.d.ts +2 -0
  477. package/dist/__tests__/ssao-data.test.d.ts.map +1 -0
  478. package/dist/__tests__/ssao-errors.test.d.ts +2 -0
  479. package/dist/__tests__/ssao-errors.test.d.ts.map +1 -0
  480. package/dist/__tests__/ssao-manifest.test.d.ts +2 -0
  481. package/dist/__tests__/ssao-manifest.test.d.ts.map +1 -0
  482. package/dist/__tests__/ssao-passes.test.d.ts +2 -0
  483. package/dist/__tests__/ssao-passes.test.d.ts.map +1 -0
  484. package/dist/__tests__/ssao-pipelines.test.d.ts +2 -0
  485. package/dist/__tests__/ssao-pipelines.test.d.ts.map +1 -0
  486. package/dist/__tests__/ssao-uniform-layout.test.d.ts +2 -0
  487. package/dist/__tests__/ssao-uniform-layout.test.d.ts.map +1 -0
  488. package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
  489. package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
  490. package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts +2 -0
  491. package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts.map +1 -0
  492. package/dist/__tests__/swap-chain-format.unit.test.d.ts +2 -0
  493. package/dist/__tests__/swap-chain-format.unit.test.d.ts.map +1 -0
  494. package/dist/__tests__/systems.unit.test.d.ts +2 -0
  495. package/dist/__tests__/systems.unit.test.d.ts.map +1 -0
  496. package/dist/__tests__/temporal-off-path.unit.test.d.ts +2 -0
  497. package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +1 -0
  498. package/dist/__tests__/text.unit.test.d.ts +2 -0
  499. package/dist/__tests__/text.unit.test.d.ts.map +1 -0
  500. package/dist/__tests__/tilemap-childed-despawn.test.d.ts +2 -0
  501. package/dist/__tests__/tilemap-childed-despawn.test.d.ts.map +1 -0
  502. package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts +2 -0
  503. package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts.map +1 -0
  504. package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts +2 -0
  505. package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts.map +1 -0
  506. package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts +2 -0
  507. package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts.map +1 -0
  508. package/dist/__tests__/tilemap-chunk-extract.test.d.ts +2 -0
  509. package/dist/__tests__/tilemap-chunk-extract.test.d.ts.map +1 -0
  510. package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts +2 -0
  511. package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts.map +1 -0
  512. package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts +2 -0
  513. package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts.map +1 -0
  514. package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts +2 -0
  515. package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts.map +1 -0
  516. package/dist/__tests__/tilemap-material-cache.test.d.ts +2 -0
  517. package/dist/__tests__/tilemap-material-cache.test.d.ts.map +1 -0
  518. package/dist/__tests__/tilemap-multi-atlas.test.d.ts +2 -0
  519. package/dist/__tests__/tilemap-multi-atlas.test.d.ts.map +1 -0
  520. package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts +2 -0
  521. package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts.map +1 -0
  522. package/dist/__tests__/tilemap-region-pack.test.d.ts +2 -0
  523. package/dist/__tests__/tilemap-region-pack.test.d.ts.map +1 -0
  524. package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts +2 -0
  525. package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts.map +1 -0
  526. package/dist/__tests__/tilemap-uv-inset.test.d.ts +2 -0
  527. package/dist/__tests__/tilemap-uv-inset.test.d.ts.map +1 -0
  528. package/dist/__tests__/tilemap-validate.test.d.ts +2 -0
  529. package/dist/__tests__/tilemap-validate.test.d.ts.map +1 -0
  530. package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts +2 -0
  531. package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts.map +1 -0
  532. package/dist/__tests__/transient-fields-collect.test.d.ts +2 -0
  533. package/dist/__tests__/transient-fields-collect.test.d.ts.map +1 -0
  534. package/dist/__tests__/transitional-authoring.integration.test.d.ts +2 -0
  535. package/dist/__tests__/transitional-authoring.integration.test.d.ts.map +1 -0
  536. package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts +2 -0
  537. package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts.map +1 -0
  538. package/dist/__tests__/variant-selection.unit.test.d.ts +2 -0
  539. package/dist/__tests__/variant-selection.unit.test.d.ts.map +1 -0
  540. package/dist/__tests__/vertex-attribute-layout.test.d.ts +2 -0
  541. package/dist/__tests__/vertex-attribute-layout.test.d.ts.map +1 -0
  542. package/dist/__tests__/video-cache-regression.unit.test.d.ts +2 -0
  543. package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +1 -0
  544. package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts +2 -0
  545. package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts.map +1 -0
  546. package/dist/__tests__/view-ubo-layout.browser.test.d.ts +2 -0
  547. package/dist/__tests__/view-ubo-layout.browser.test.d.ts.map +1 -0
  548. package/dist/__tests__/world-entity-key.test.d.ts +2 -0
  549. package/dist/__tests__/world-entity-key.test.d.ts.map +1 -0
  550. package/dist/__tests__/world-scene-despawn.test.d.ts +2 -0
  551. package/dist/__tests__/world-scene-despawn.test.d.ts.map +1 -0
  552. package/dist/__tests__/world-scene-instantiate.test.d.ts +2 -0
  553. package/dist/__tests__/world-scene-instantiate.test.d.ts.map +1 -0
  554. package/dist/__tests__/world-scene-nested.test.d.ts +2 -0
  555. package/dist/__tests__/world-scene-nested.test.d.ts.map +1 -0
  556. package/dist/__tests__/world-scene-override.test.d.ts +2 -0
  557. package/dist/__tests__/world-scene-override.test.d.ts.map +1 -0
  558. package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts +2 -0
  559. package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts.map +1 -0
  560. package/dist/asset-contributions.d.ts +3 -0
  561. package/dist/asset-contributions.d.ts.map +1 -0
  562. package/dist/asset-kind.d.ts +4 -0
  563. package/dist/asset-kind.d.ts.map +1 -0
  564. package/dist/collect-scene-asset.d.ts +16 -0
  565. package/dist/collect-scene-asset.d.ts.map +1 -0
  566. package/dist/components/__tests__/camera.test-d.d.ts +2 -0
  567. package/dist/components/__tests__/camera.test-d.d.ts.map +1 -0
  568. package/dist/components/__tests__/camera.test.d.ts +2 -0
  569. package/dist/components/__tests__/camera.test.d.ts.map +1 -0
  570. package/dist/components/__tests__/child-of.test.d.ts +2 -0
  571. package/dist/components/__tests__/child-of.test.d.ts.map +1 -0
  572. package/dist/components/__tests__/sprite-animation.test-d.d.ts +2 -0
  573. package/dist/components/__tests__/sprite-animation.test-d.d.ts.map +1 -0
  574. package/dist/components/__tests__/sprite-instances.unit.test.d.ts +2 -0
  575. package/dist/components/__tests__/sprite-instances.unit.test.d.ts.map +1 -0
  576. package/dist/components/__tests__/sprite-region-override.test-d.d.ts +2 -0
  577. package/dist/components/__tests__/sprite-region-override.test-d.d.ts.map +1 -0
  578. package/dist/components/__tests__/tile-layer.test-d.d.ts +2 -0
  579. package/dist/components/__tests__/tile-layer.test-d.d.ts.map +1 -0
  580. package/dist/components/__tests__/tile-layer.unit.test.d.ts +2 -0
  581. package/dist/components/__tests__/tile-layer.unit.test.d.ts.map +1 -0
  582. package/dist/components/__tests__/tilemap.test-d.d.ts +2 -0
  583. package/dist/components/__tests__/tilemap.test-d.d.ts.map +1 -0
  584. package/dist/components/__tests__/transform-vec-schema.test.d.ts +2 -0
  585. package/dist/components/__tests__/transform-vec-schema.test.d.ts.map +1 -0
  586. package/dist/create-renderer-env-classify.d.ts +21 -0
  587. package/dist/create-renderer-env-classify.d.ts.map +1 -0
  588. package/dist/createRenderer.d.ts +3 -0
  589. package/dist/createRenderer.d.ts.map +1 -0
  590. package/dist/dev-import-transport.d.ts +24 -0
  591. package/dist/dev-import-transport.d.ts.map +1 -0
  592. package/dist/errors/environment.d.ts +2 -0
  593. package/dist/errors/environment.d.ts.map +1 -0
  594. package/dist/errors/sprite-animation.d.ts +3 -0
  595. package/dist/errors/sprite-animation.d.ts.map +1 -0
  596. package/dist/index.d.ts +280 -0
  597. package/dist/index.d.ts.map +1 -0
  598. package/dist/index.mjs +814 -0
  599. package/dist/index.mjs.map +1 -0
  600. package/dist/scene-asset-port.d.ts +17 -0
  601. package/dist/scene-asset-port.d.ts.map +1 -0
  602. package/dist/scene-collect-errors.d.ts +22 -0
  603. package/dist/scene-collect-errors.d.ts.map +1 -0
  604. package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts +2 -0
  605. package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts.map +1 -0
  606. package/dist/scene-utils/mount-override-fold.d.ts +16 -0
  607. package/dist/scene-utils/mount-override-fold.d.ts.map +1 -0
  608. package/dist/shadow-m3-calibrate.d.ts +40 -0
  609. package/dist/shadow-m3-calibrate.d.ts.map +1 -0
  610. package/dist/sprite-param-values.d.ts +62 -0
  611. package/dist/sprite-param-values.d.ts.map +1 -0
  612. package/dist/systems/__tests__/_xorshift.d.ts +28 -0
  613. package/dist/systems/__tests__/_xorshift.d.ts.map +1 -0
  614. package/dist/systems/__tests__/argsort-in-place.test.d.ts +2 -0
  615. package/dist/systems/__tests__/argsort-in-place.test.d.ts.map +1 -0
  616. package/dist/systems/__tests__/transparent-sort.bench.d.ts +2 -0
  617. package/dist/systems/__tests__/transparent-sort.bench.d.ts.map +1 -0
  618. package/dist/systems/sprite-animation-tick.d.ts +50 -0
  619. package/dist/systems/sprite-animation-tick.d.ts.map +1 -0
  620. package/dist/systems/tonemap.d.ts +27 -0
  621. package/dist/systems/tonemap.d.ts.map +1 -0
  622. package/dist/systems/transparent-sort.d.ts +51 -0
  623. package/dist/systems/transparent-sort.d.ts.map +1 -0
  624. package/dist/tilemap-register-validate.d.ts +21 -0
  625. package/dist/tilemap-register-validate.d.ts.map +1 -0
  626. package/package.json +100 -0
  627. package/src/__tests__/active-camera.unit.test.ts +193 -0
  628. package/src/__tests__/animation-graph-add.unit.test.ts +67 -0
  629. package/src/__tests__/animation-graph-asset-union.test-d.ts +83 -0
  630. package/src/__tests__/animation-graph-blend.unit.test.ts +66 -0
  631. package/src/__tests__/animation-graph-build.unit.test.ts +100 -0
  632. package/src/__tests__/animation-graph-clip-missing.unit.test.ts +62 -0
  633. package/src/__tests__/animation-graph-clip.unit.test.ts +77 -0
  634. package/src/__tests__/animation-graph-default-path.integration.test.ts +65 -0
  635. package/src/__tests__/animation-graph-describe.unit.test.ts +68 -0
  636. package/src/__tests__/animation-graph-errors.unit.test.ts +75 -0
  637. package/src/__tests__/animation-graph-nesting.unit.test.ts +84 -0
  638. package/src/__tests__/animation-graph-orthogonal-weight.unit.test.ts +98 -0
  639. package/src/__tests__/animation-graph-slot-fill.unit.test.ts +95 -0
  640. package/src/__tests__/animation-nslot.unit.test.ts +63 -0
  641. package/src/__tests__/animation-slot-length-guard.unit.test.ts +81 -0
  642. package/src/__tests__/append-injection.test.ts +105 -0
  643. package/src/__tests__/asi-world-baseline-export.unit.test.ts +173 -0
  644. package/src/__tests__/asi-world-ci-config.unit.test.ts +186 -0
  645. package/src/__tests__/asi-world-smoke.unit.test.ts +192 -0
  646. package/src/__tests__/asset-registry-scene.test-d.ts +49 -0
  647. package/src/__tests__/bind-group-cache-binding.test.ts +2513 -0
  648. package/src/__tests__/bind-group-cache-frame.test.ts +1511 -0
  649. package/src/__tests__/bind-group-cache-keying.test.ts +295 -0
  650. package/src/__tests__/block-upload-math.unit.test.ts +192 -0
  651. package/src/__tests__/builtin-shader-register-e2e.test.ts +151 -0
  652. package/src/__tests__/cache-false-eviction.test.ts +126 -0
  653. package/src/__tests__/cache-isolation-matrix.test.ts +182 -0
  654. package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +76 -0
  655. package/src/__tests__/clamp-to-last.e2e.browser.test.ts +183 -0
  656. package/src/__tests__/clamp-to-last.e2e.dawn.test.ts +325 -0
  657. package/src/__tests__/collect-scene-asset.test.ts +876 -0
  658. package/src/__tests__/collect-subtree.unit.test.ts +76 -0
  659. package/src/__tests__/collect-transient-children-absent.test.ts +154 -0
  660. package/src/__tests__/collect-transient-roundtrip.test.ts +245 -0
  661. package/src/__tests__/collect-transient-skip.test.ts +165 -0
  662. package/src/__tests__/components.test-d.ts +236 -0
  663. package/src/__tests__/components.unit.test.ts +2665 -0
  664. package/src/__tests__/composite-skybox-cross-world.browser.test.ts +378 -0
  665. package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -0
  666. package/src/__tests__/createRenderer-dispose.test.ts +416 -0
  667. package/src/__tests__/createRenderer-requiredFeatures.unit.test.ts +134 -0
  668. package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +59 -0
  669. package/src/__tests__/createRenderer.unit.test.ts +231 -0
  670. package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +393 -0
  671. package/src/__tests__/dawn/ibl-compose.dawn.test.ts +151 -0
  672. package/src/__tests__/dawn/ibl-modules-compose.dawn.test.ts +223 -0
  673. package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +241 -0
  674. package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +611 -0
  675. package/src/__tests__/dawn/instances-shadow.dawn.test.ts +443 -0
  676. package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +313 -0
  677. package/src/__tests__/dawn/material-alpha.dawn.test.ts +304 -0
  678. package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +64 -0
  679. package/src/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.ts +106 -0
  680. package/src/__tests__/dawn/mesh-update.dawn.test.ts +342 -0
  681. package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +117 -0
  682. package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +567 -0
  683. package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +251 -0
  684. package/src/__tests__/dawn/tonemap.dawn.test.ts +107 -0
  685. package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +291 -0
  686. package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +204 -0
  687. package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +122 -0
  688. package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +99 -0
  689. package/src/__tests__/demo-sortscope-migration.unit.test.ts +115 -0
  690. package/src/__tests__/derive-bgl-integration.test.ts +398 -0
  691. package/src/__tests__/derive-render-data-skin.unit.test.ts +90 -0
  692. package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +204 -0
  693. package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +297 -0
  694. package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +271 -0
  695. package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +321 -0
  696. package/src/__tests__/draw-published.ts +10 -0
  697. package/src/__tests__/environment-error-exhaustive.test-d.ts +28 -0
  698. package/src/__tests__/equirect-bc6h.integration.test.ts +35 -0
  699. package/src/__tests__/error-exhaustive.test.ts +220 -0
  700. package/src/__tests__/extract-frames-graceful-degradation.test.ts +298 -0
  701. package/src/__tests__/extract-frames-merge.test.ts +643 -0
  702. package/src/__tests__/extract-frames-reset.test.ts +158 -0
  703. package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +92 -0
  704. package/src/__tests__/fog-producer-manifest.ts +162 -0
  705. package/src/__tests__/fog-producer-pixel-probe.ts +263 -0
  706. package/src/__tests__/fog-producer-pixel.browser.test.ts +26 -0
  707. package/src/__tests__/fog-producer-pixel.dawn.test.ts +55 -0
  708. package/src/__tests__/fog-producer-real-fixture.ts +805 -0
  709. package/src/__tests__/fog-producer-vfx-effect.ts +272 -0
  710. package/src/__tests__/fog-scene-asset.integration.test.ts +123 -0
  711. package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +28 -0
  712. package/src/__tests__/fullscreen-post-bgl-depth.test.ts +131 -0
  713. package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +84 -0
  714. package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +320 -0
  715. package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +107 -0
  716. package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +292 -0
  717. package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +358 -0
  718. package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +254 -0
  719. package/src/__tests__/geometry.unit.test.ts +2265 -0
  720. package/src/__tests__/glyph-tilemap-worldid.test.ts +146 -0
  721. package/src/__tests__/gpu-resource-cow-survivor.test.ts +388 -0
  722. package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +207 -0
  723. package/src/__tests__/gpu-resource.test.ts +1206 -0
  724. package/src/__tests__/hdrp-bgl-slots.browser.test.ts +50 -0
  725. package/src/__tests__/hdrp-buffers.unit.test.ts +70 -0
  726. package/src/__tests__/hdrp-execute-filter.unit.test.ts +200 -0
  727. package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +64 -0
  728. package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +139 -0
  729. package/src/__tests__/hdrp-ssao-boundary.test.ts +237 -0
  730. package/src/__tests__/hdrp-ssao-falsification.test.ts +289 -0
  731. package/src/__tests__/hello-tilemap-smoke-upgrade.unit.test.ts +147 -0
  732. package/src/__tests__/helpers/mock-shader-registry.ts +139 -0
  733. package/src/__tests__/helpers/primitive-world.ts +91 -0
  734. package/src/__tests__/helpers/register-runtime-components.ts +69 -0
  735. package/src/__tests__/helpers/register-scene-components.ts +10 -0
  736. package/src/__tests__/helpers/render-asset-port.ts +65 -0
  737. package/src/__tests__/helpers/scene-asset-port.ts +23 -0
  738. package/src/__tests__/helpers/tilemap-assets.ts +29 -0
  739. package/src/__tests__/instances.test-d.ts +61 -0
  740. package/src/__tests__/light-attenuation-formula.test.ts +171 -0
  741. package/src/__tests__/light-casters-9-light.browser.test.ts +880 -0
  742. package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +163 -0
  743. package/src/__tests__/light-snapshot.test-d.ts +84 -0
  744. package/src/__tests__/lights-vec-negative.unit.test.ts +52 -0
  745. package/src/__tests__/lights.unit.test.ts +2936 -0
  746. package/src/__tests__/m3-vec-negative.unit.test.ts +45 -0
  747. package/src/__tests__/m5-browser-dawn-sweep.integration.test.ts +8 -0
  748. package/src/__tests__/material-derived-coordinates.integration.test.ts +100 -0
  749. package/src/__tests__/material-texture-uv-scale.unit.test.ts +49 -0
  750. package/src/__tests__/materials.unit.test.ts +271 -0
  751. package/src/__tests__/mesh-ssbo-grow.unit.test.ts +244 -0
  752. package/src/__tests__/mip-gate.unit.test.ts +79 -0
  753. package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +406 -0
  754. package/src/__tests__/multi-uv-8set.e2e.dawn.test.ts +296 -0
  755. package/src/__tests__/name.unit.test.ts +123 -0
  756. package/src/__tests__/node-shims.d.ts +33 -0
  757. package/src/__tests__/pass-selector.unit.test.ts +102 -0
  758. package/src/__tests__/pbr-pipeline.unit.test.ts +204 -0
  759. package/src/__tests__/pipeline-builder-msaa.unit.test.ts +224 -0
  760. package/src/__tests__/pipeline-cache-keying.unit.test.ts +316 -0
  761. package/src/__tests__/pipeline-layout-selection.test.ts +298 -0
  762. package/src/__tests__/pipeline-spec.test.ts +1061 -0
  763. package/src/__tests__/pipeline.unit.test.ts +6974 -0
  764. package/src/__tests__/point-light-shadow.browser.test.ts +278 -0
  765. package/src/__tests__/point-light-shadow.dawn.test.ts +822 -0
  766. package/src/__tests__/point-light-shadow.unit.test.ts +716 -0
  767. package/src/__tests__/post-process-error-codes.unit.test.ts +158 -0
  768. package/src/__tests__/post-process-params-component.unit.test.ts +153 -0
  769. package/src/__tests__/post-process-params-extract.unit.test.ts +100 -0
  770. package/src/__tests__/post-process-reads-narrowing.test-d.ts +52 -0
  771. package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +230 -0
  772. package/src/__tests__/postprocess-camera-consistency.test.ts +378 -0
  773. package/src/__tests__/profiler-assembly.integration.test.ts +74 -0
  774. package/src/__tests__/propagate-transforms.dawn.test.ts +253 -0
  775. package/src/__tests__/record-worldid-isolation.test.ts +247 -0
  776. package/src/__tests__/recover-error-exhaustive.test-d.ts +35 -0
  777. package/src/__tests__/render-error-exhaustive.test-d.ts +245 -0
  778. package/src/__tests__/render-feature-assembly.test-d.ts +28 -0
  779. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +124 -0
  780. package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +582 -0
  781. package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +602 -0
  782. package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +264 -0
  783. package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +361 -0
  784. package/src/__tests__/render-feature-recover.integration.test.ts +142 -0
  785. package/src/__tests__/render-feature-runtime-surface.test-d.ts +45 -0
  786. package/src/__tests__/render-feature-zero-feature.browser.test.ts +152 -0
  787. package/src/__tests__/render-pipeline-trivial.dawn.test.ts +525 -0
  788. package/src/__tests__/render-schema-consumer.integration.test.ts +25 -0
  789. package/src/__tests__/render-schema-owner-boundary.unit.test.ts +26 -0
  790. package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +172 -0
  791. package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +322 -0
  792. package/src/__tests__/render-system-extract.test.ts +1399 -0
  793. package/src/__tests__/render-system-fold-bucket.unit.test.ts +288 -0
  794. package/src/__tests__/render-system-fold-fallback.unit.test.ts +148 -0
  795. package/src/__tests__/render-system-fold-material.unit.test.ts +145 -0
  796. package/src/__tests__/render-system-fold-metrics.unit.test.ts +170 -0
  797. package/src/__tests__/render-system-fold-modegate.unit.test.ts +166 -0
  798. package/src/__tests__/render-system-fold-scene-instances.unit.test.ts +51 -0
  799. package/src/__tests__/render-system-fold.dawn.test.ts +306 -0
  800. package/src/__tests__/render-system-mega.test.ts +1578 -0
  801. package/src/__tests__/render-system-owner-split-contract.test.ts +200 -0
  802. package/src/__tests__/render-system-record-multi-material-textureview.test.ts +684 -0
  803. package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +464 -0
  804. package/src/__tests__/render-system-record.test.ts +1505 -0
  805. package/src/__tests__/render-system-record.unit.test.ts +270 -0
  806. package/src/__tests__/render-system-skin-bg.unit.test.ts +147 -0
  807. package/src/__tests__/renderer-consumer.test-d.ts +5 -0
  808. package/src/__tests__/renderer-health.unit.test.ts +935 -0
  809. package/src/__tests__/renderer-lifecycle.integration.test.ts +29 -0
  810. package/src/__tests__/renderer-recover.unit.test.ts +1075 -0
  811. package/src/__tests__/renderer-result.test-d.ts +26 -0
  812. package/src/__tests__/renderer-surface.unit.test.ts +416 -0
  813. package/src/__tests__/resolve-depth-only-view.test.ts +173 -0
  814. package/src/__tests__/rhi-null-command-flow.unit.test.ts +273 -0
  815. package/src/__tests__/rhi-null-noop-behavior.unit.test.ts +196 -0
  816. package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +182 -0
  817. package/src/__tests__/roots-to-scene-asset.test.ts +605 -0
  818. package/src/__tests__/runtime-authority-scan.unit.test.ts +19 -0
  819. package/src/__tests__/runtime-domain-residue.unit.test.ts +13 -0
  820. package/src/__tests__/scene-equirect-roundtrip.test.ts +33 -0
  821. package/src/__tests__/scene-instance-bridge.integration.test.ts +8 -0
  822. package/src/__tests__/scene-instance-component.test.ts +45 -0
  823. package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +66 -0
  824. package/src/__tests__/serialize-scene-asset.test.ts +336 -0
  825. package/src/__tests__/shadow-caster-empty-schema.test.ts +83 -0
  826. package/src/__tests__/shadow-csm-atlas.test.ts +178 -0
  827. package/src/__tests__/shadow-csm-blend.dawn.test.ts +230 -0
  828. package/src/__tests__/shadow-csm-cascade-loadop.test.ts +334 -0
  829. package/src/__tests__/shadow-csm-caster-membership.test.ts +232 -0
  830. package/src/__tests__/shadow-csm-component.test.ts +286 -0
  831. package/src/__tests__/shadow-csm-extract.test.ts +334 -0
  832. package/src/__tests__/shadow-csm-orthoz.test.ts +151 -0
  833. package/src/__tests__/shadow-csm-pssm.test.ts +142 -0
  834. package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +198 -0
  835. package/src/__tests__/shadow-csm-shader.dawn.test.ts +358 -0
  836. package/src/__tests__/shadow-csm-temporal.browser.test.ts +145 -0
  837. package/src/__tests__/shadow-csm-tile-consistency.test.ts +419 -0
  838. package/src/__tests__/shadow-csm-ubo.dawn.test.ts +293 -0
  839. package/src/__tests__/shadow-csm-ubo.test.ts +300 -0
  840. package/src/__tests__/shadow-csm-viewport.browser.test.ts +85 -0
  841. package/src/__tests__/shadow-csm-viewport.test.ts +74 -0
  842. package/src/__tests__/shadow-fields-observable.dawn.test.ts +615 -0
  843. package/src/__tests__/shadow-m1.dawn.test.ts +105 -0
  844. package/src/__tests__/shadow-m2.dawn.test.ts +394 -0
  845. package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +248 -0
  846. package/src/__tests__/shadow-m3-calibrate.ts +203 -0
  847. package/src/__tests__/shadow-m3.dawn.test.ts +288 -0
  848. package/src/__tests__/shadow-mesh-ssbo-order.test.ts +64 -0
  849. package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +264 -0
  850. package/src/__tests__/shadow-quality-metrics.dawn.test.ts +324 -0
  851. package/src/__tests__/skin-error-exhaustive.test-d.ts +74 -0
  852. package/src/__tests__/skin-errors.unit.test.ts +10 -0
  853. package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +23 -0
  854. package/src/__tests__/skin-parented-double-transform.test.ts +268 -0
  855. package/src/__tests__/skylight-lazy-projection.test.ts +359 -0
  856. package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +43 -0
  857. package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +470 -0
  858. package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +141 -0
  859. package/src/__tests__/sprite-lit-extract-branch.test.ts +117 -0
  860. package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +123 -0
  861. package/src/__tests__/sprite-param-values.test-d.ts +104 -0
  862. package/src/__tests__/ssao-bgl.test.ts +347 -0
  863. package/src/__tests__/ssao-buffers.test.ts +211 -0
  864. package/src/__tests__/ssao-data.test.ts +121 -0
  865. package/src/__tests__/ssao-errors.test.ts +162 -0
  866. package/src/__tests__/ssao-manifest.test.ts +109 -0
  867. package/src/__tests__/ssao-passes.test.ts +1229 -0
  868. package/src/__tests__/ssao-pipelines.test.ts +275 -0
  869. package/src/__tests__/ssao-uniform-layout.test.ts +178 -0
  870. package/src/__tests__/static-rig.integration.test.ts +9 -0
  871. package/src/__tests__/stencil-outline-pixel.dawn.test.ts +295 -0
  872. package/src/__tests__/swap-chain-format.unit.test.ts +117 -0
  873. package/src/__tests__/systems.unit.test.ts +9957 -0
  874. package/src/__tests__/temporal-off-path.unit.test.ts +69 -0
  875. package/src/__tests__/text.unit.test.ts +466 -0
  876. package/src/__tests__/tilemap-childed-despawn.test.ts +468 -0
  877. package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +314 -0
  878. package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +80 -0
  879. package/src/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.ts +424 -0
  880. package/src/__tests__/tilemap-chunk-extract.test.ts +236 -0
  881. package/src/__tests__/tilemap-chunk-extract.unit.test.ts +383 -0
  882. package/src/__tests__/tilemap-chunk-y-sort-bench.unit.test.ts +109 -0
  883. package/src/__tests__/tilemap-dirty-rebuild.test.ts +300 -0
  884. package/src/__tests__/tilemap-material-cache.test.ts +137 -0
  885. package/src/__tests__/tilemap-multi-atlas.test.ts +237 -0
  886. package/src/__tests__/tilemap-owner-boundary.unit.test.ts +63 -0
  887. package/src/__tests__/tilemap-region-pack.test.ts +153 -0
  888. package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +274 -0
  889. package/src/__tests__/tilemap-uv-inset.test.ts +204 -0
  890. package/src/__tests__/tilemap-validate.test.ts +201 -0
  891. package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +274 -0
  892. package/src/__tests__/transient-fields-collect.test.ts +203 -0
  893. package/src/__tests__/transitional-authoring.integration.test.ts +7 -0
  894. package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +227 -0
  895. package/src/__tests__/variant-selection.unit.test.ts +21 -0
  896. package/src/__tests__/vertex-attribute-layout.test.ts +324 -0
  897. package/src/__tests__/video-cache-regression.unit.test.ts +186 -0
  898. package/src/__tests__/video-extract-bindgroup.dawn.test.ts +450 -0
  899. package/src/__tests__/view-ubo-layout.browser.test.ts +183 -0
  900. package/src/__tests__/world-entity-key.test.ts +92 -0
  901. package/src/__tests__/world-scene-despawn.test.ts +132 -0
  902. package/src/__tests__/world-scene-instantiate.test.ts +228 -0
  903. package/src/__tests__/world-scene-nested.test.ts +230 -0
  904. package/src/__tests__/world-scene-override.test.ts +199 -0
  905. package/src/__tests__/zero-compression-zero-load.integration.test.ts +107 -0
  906. package/src/asset-contributions.ts +48 -0
  907. package/src/asset-kind.ts +7 -0
  908. package/src/collect-scene-asset.ts +689 -0
  909. package/src/components/__tests__/camera.test-d.ts +57 -0
  910. package/src/components/__tests__/camera.test.ts +95 -0
  911. package/src/components/__tests__/child-of.test.ts +35 -0
  912. package/src/components/__tests__/sprite-animation.test-d.ts +160 -0
  913. package/src/components/__tests__/sprite-instances.unit.test.ts +108 -0
  914. package/src/components/__tests__/sprite-region-override.test-d.ts +101 -0
  915. package/src/components/__tests__/tile-layer.test-d.ts +33 -0
  916. package/src/components/__tests__/tile-layer.unit.test.ts +125 -0
  917. package/src/components/__tests__/tilemap.test-d.ts +35 -0
  918. package/src/components/__tests__/transform-vec-schema.test.ts +121 -0
  919. package/src/create-renderer-env-classify.ts +110 -0
  920. package/src/createRenderer.ts +61 -0
  921. package/src/dev-import-transport.ts +97 -0
  922. package/src/errors/environment.ts +6 -0
  923. package/src/errors/sprite-animation.ts +5 -0
  924. package/src/index.ts +442 -0
  925. package/src/scene-asset-port.ts +32 -0
  926. package/src/scene-collect-errors.ts +30 -0
  927. package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +183 -0
  928. package/src/scene-utils/mount-override-fold.ts +217 -0
  929. package/src/shadow-m3-calibrate.ts +171 -0
  930. package/src/sprite-param-values.ts +61 -0
  931. package/src/systems/__tests__/_xorshift.ts +83 -0
  932. package/src/systems/__tests__/argsort-in-place.test.ts +155 -0
  933. package/src/systems/__tests__/transparent-sort.bench.ts +218 -0
  934. package/src/systems/sprite-animation-tick.ts +302 -0
  935. package/src/systems/tonemap.ts +68 -0
  936. package/src/systems/transparent-sort.ts +434 -0
  937. package/src/tilemap-register-validate.ts +100 -0
@@ -0,0 +1,935 @@
1
+ // @forgeax/engine-runtime — renderer health / recover unit + integration tests
2
+ //
3
+ // Covers:
4
+ // w1 — HealthReason narrowing + detail discriminated union test (AC-05)
5
+ // w2 — RecoverError union exhaustiveness test (AC-06)
6
+ // w3 — HealthListenerRegistry replay + unsubscribe + isolation test (AC-07/AC-08)
7
+ // w4 — HealthSnapshot shape + recoverable derivation + immutability test (AC-02)
8
+ // w8 — health() healthy-state baseline integration test
9
+ // w9 — recover() healthy-state returns recover-not-needed test (AC-04)
10
+ // w10 — recover() degraded-state placeholder + health unchanged test (AC-04b)
11
+ //
12
+ // w1-w4: unit tests (types + registry, GREEN after M1 w5-w7)
13
+ // w8-w10: integration tests (createRenderer + mock RHI, RED until w11-w13)
14
+
15
+ import type {
16
+ HealthChangeListener,
17
+ HealthReason,
18
+ HealthSnapshot,
19
+ } from '@forgeax/engine-render/internal';
20
+ import {
21
+ deriveRecoverable,
22
+ HealthListenerRegistry,
23
+ RecoverError,
24
+ type RecoverErrorCode,
25
+ } from '@forgeax/engine-render/internal';
26
+ import type { Result, RhiInstance } from '@forgeax/engine-rhi';
27
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
28
+
29
+ // ── w1: HealthReason narrowing + detail discriminated union (AC-05) ─────────
30
+
31
+ describe('HealthReason narrowing (AC-05)', () => {
32
+ it('switch(snap.reason) narrows detail per reason without as casts', () => {
33
+ // Consumer-side switch exercising all 3 HealthReason members.
34
+ // TS must narrow snap.detail in each case branch — zero `as` casts.
35
+ function consumeHealth(snap: HealthSnapshot): string {
36
+ switch (snap.reason) {
37
+ case 'alive':
38
+ // alive variant has no detail field — zero as casts
39
+ return 'alive';
40
+ case 'device-lost':
41
+ // detail narrows to HealthDetailDeviceLost; lostReason scoped to this variant
42
+ return `device-lost(lostReason=${snap.detail.lostReason}): ${snap.detail.message}`;
43
+ case 'internal-fault':
44
+ // detail narrows to HealthDetailInternalFault; message is the only field
45
+ return `internal-fault: ${snap.detail.message}`;
46
+ }
47
+ }
48
+ // Compile-time assertion: the function compiles with zero `as` casts
49
+ expect(typeof consumeHealth).toBe('function');
50
+ });
51
+
52
+ it('HealthReason has exactly 3 members — exhaustiveness without default', () => {
53
+ // If TS compiles this switch without default, the union is exactly 3 members.
54
+ function exhaustive(reason: HealthReason): string {
55
+ switch (reason) {
56
+ case 'alive':
57
+ return 'alive';
58
+ case 'device-lost':
59
+ return 'device-lost';
60
+ case 'internal-fault':
61
+ return 'internal-fault';
62
+ }
63
+ }
64
+ expect(typeof exhaustive).toBe('function');
65
+ });
66
+ });
67
+
68
+ // ── w2: RecoverError union exhaustiveness (AC-06) ──────────────────────────
69
+
70
+ describe('RecoverError closed union (AC-06)', () => {
71
+ it('switch(err.code) exhaustively matches all members without default', () => {
72
+ // Consumer-side switch matching every RecoverErrorCode member.
73
+ // TS must not emit non-exhaustive errors; no `default` branch.
74
+ // feat-20260622-s5 M3 / w19: union grew add-only to 4 members (adapter /
75
+ // device unavailable join the S3 not-needed / not-implemented(reserved)).
76
+ function handleRecover(err: RecoverError): string {
77
+ switch (err.code) {
78
+ case 'recover-not-needed':
79
+ return `not-needed: ${err.hint}`;
80
+ case 'recover-not-implemented':
81
+ return `not-implemented: ${err.hint}`;
82
+ case 'recover-adapter-unavailable':
83
+ return `adapter-unavailable: ${err.hint}`;
84
+ case 'recover-device-unavailable':
85
+ return `device-unavailable: ${err.hint}`;
86
+ }
87
+ }
88
+ expect(typeof handleRecover).toBe('function');
89
+ });
90
+
91
+ it('RecoverErrorCode has exactly 4 members', () => {
92
+ function exhaustive(code: RecoverErrorCode): string {
93
+ switch (code) {
94
+ case 'recover-not-needed':
95
+ return 'not-needed';
96
+ case 'recover-not-implemented':
97
+ return 'not-implemented';
98
+ case 'recover-adapter-unavailable':
99
+ return 'adapter-unavailable';
100
+ case 'recover-device-unavailable':
101
+ return 'device-unavailable';
102
+ }
103
+ }
104
+ expect(typeof exhaustive).toBe('function');
105
+ });
106
+
107
+ it('RecoverError carries .code, .expected, .hint fields', () => {
108
+ const err = new RecoverError('recover-not-needed');
109
+ expect(err.code).toBe('recover-not-needed');
110
+ expect(typeof err.expected).toBe('string');
111
+ expect(err.expected.length).toBeGreaterThan(0);
112
+ expect(typeof err.hint).toBe('string');
113
+ expect(err.hint.length).toBeGreaterThan(0);
114
+ });
115
+
116
+ it('recover-not-implemented code also carries valid .expected + .hint', () => {
117
+ const err = new RecoverError('recover-not-implemented');
118
+ expect(err.code).toBe('recover-not-implemented');
119
+ expect(typeof err.expected).toBe('string');
120
+ expect(err.expected.length).toBeGreaterThan(0);
121
+ expect(typeof err.hint).toBe('string');
122
+ expect(err.hint.length).toBeGreaterThan(0);
123
+ });
124
+ });
125
+
126
+ // ── w3: HealthListenerRegistry replay + unsubscribe + isolation (AC-07/AC-08)
127
+
128
+ describe('HealthListenerRegistry (AC-07/AC-08)', () => {
129
+ it('late-attach replay: fire then add calls listener immediately', () => {
130
+ const registry = new HealthListenerRegistry();
131
+ const snapshot: HealthSnapshot = {
132
+ reason: 'device-lost',
133
+ detail: { lostReason: 'destroyed', message: 'test device lost' },
134
+ recoverable: true,
135
+ };
136
+ registry.fire(snapshot);
137
+
138
+ const cb = vi.fn<HealthChangeListener>();
139
+ registry.add(cb);
140
+
141
+ expect(cb).toHaveBeenCalledTimes(1);
142
+ expect(cb).toHaveBeenCalledWith(snapshot);
143
+ });
144
+
145
+ it('unsubscribe: add returns unsubscribe, listener not called after', () => {
146
+ const registry = new HealthListenerRegistry();
147
+ const cb = vi.fn<HealthChangeListener>();
148
+ const unsubscribe = registry.add(cb);
149
+
150
+ // Unsubscribe
151
+ unsubscribe();
152
+
153
+ // Fire after unsubscribe — cb must not be called
154
+ const snapshot: HealthSnapshot = {
155
+ reason: 'alive',
156
+ recoverable: false,
157
+ };
158
+ registry.fire(snapshot);
159
+
160
+ expect(cb).not.toHaveBeenCalled();
161
+ });
162
+
163
+ it('listener-throw isolation: first throws, second still fires', () => {
164
+ const registry = new HealthListenerRegistry();
165
+
166
+ const cb1 = vi.fn<HealthChangeListener>(() => {
167
+ throw new Error('cb1 intentional throw');
168
+ });
169
+ const cb2 = vi.fn<HealthChangeListener>();
170
+
171
+ registry.add(cb1);
172
+ registry.add(cb2);
173
+
174
+ // Suppress console.error from the try/catch isolation
175
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
176
+
177
+ const snapshot: HealthSnapshot = {
178
+ reason: 'internal-fault',
179
+ detail: { message: 'simulated fault' },
180
+ recoverable: false,
181
+ };
182
+ registry.fire(snapshot);
183
+
184
+ expect(cb1).toHaveBeenCalledTimes(1);
185
+ expect(cb2).toHaveBeenCalledTimes(1);
186
+ expect(cb2).toHaveBeenCalledWith(snapshot);
187
+ // cb1's throw should be caught and surfaced via console.error
188
+ expect(consoleErrorSpy).toHaveBeenCalled();
189
+
190
+ consoleErrorSpy.mockRestore();
191
+ });
192
+
193
+ it('clear detaches all listeners but preserves fired/lastSnapshot for replay', () => {
194
+ const registry = new HealthListenerRegistry();
195
+
196
+ const snapshot: HealthSnapshot = {
197
+ reason: 'device-lost',
198
+ detail: { lostReason: 'unknown', message: 'test' },
199
+ recoverable: true,
200
+ };
201
+ registry.fire(snapshot);
202
+
203
+ registry.clear();
204
+
205
+ // Late-attach after clear: fired/lastSnapshot preserved, so replay still works
206
+ const cb = vi.fn<HealthChangeListener>();
207
+ registry.add(cb);
208
+
209
+ expect(cb).toHaveBeenCalledTimes(1);
210
+ expect(cb).toHaveBeenCalledWith(snapshot);
211
+ });
212
+
213
+ it('getLastSnapshot returns alive baseline when never fired', () => {
214
+ const registry = new HealthListenerRegistry();
215
+ const snapshot = registry.getLastSnapshot();
216
+
217
+ expect(snapshot.reason).toBe('alive');
218
+ expect(snapshot.recoverable).toBe(false);
219
+ });
220
+
221
+ it('getLastSnapshot returns last fired snapshot after fire', () => {
222
+ const registry = new HealthListenerRegistry();
223
+ const fired: HealthSnapshot = {
224
+ reason: 'device-lost',
225
+ detail: { lostReason: 'destroyed', message: 'lost' },
226
+ recoverable: true,
227
+ };
228
+ registry.fire(fired);
229
+
230
+ const snapshot = registry.getLastSnapshot();
231
+ expect(snapshot.reason).toBe('device-lost');
232
+ expect(snapshot.recoverable).toBe(true);
233
+ if (snapshot.reason === 'device-lost') {
234
+ expect(snapshot.detail).toEqual({ lostReason: 'destroyed', message: 'lost' });
235
+ }
236
+ });
237
+ });
238
+
239
+ // ── w4: HealthSnapshot shape + recoverable derivation + immutability (AC-02) ─
240
+
241
+ describe('HealthSnapshot shape + recoverable derivation (AC-02)', () => {
242
+ it('deriveRecoverable: alive -> false', () => {
243
+ expect(deriveRecoverable('alive')).toBe(false);
244
+ });
245
+
246
+ it('deriveRecoverable: device-lost -> true', () => {
247
+ expect(deriveRecoverable('device-lost')).toBe(true);
248
+ });
249
+
250
+ it('deriveRecoverable: internal-fault -> false', () => {
251
+ expect(deriveRecoverable('internal-fault')).toBe(false);
252
+ });
253
+
254
+ it('HealthSnapshot has exactly { reason, detail?, recoverable } fields', () => {
255
+ // Shape assertion: discriminated union — alive has no detail, degraded
256
+ // variants have required detail. TS would error on mismatched shapes.
257
+ const snapAlive: HealthSnapshot = { reason: 'alive', recoverable: false };
258
+ expect(snapAlive.reason).toBe('alive');
259
+ expect(snapAlive.recoverable).toBe(false);
260
+
261
+ const snapLost: HealthSnapshot = {
262
+ reason: 'device-lost',
263
+ detail: { lostReason: 'unknown', message: 'test' },
264
+ recoverable: true,
265
+ };
266
+ expect(snapLost.reason).toBe('device-lost');
267
+ expect(snapLost.recoverable).toBe(true);
268
+ expect(snapLost.detail).toEqual({ lostReason: 'unknown', message: 'test' });
269
+
270
+ const snapFault: HealthSnapshot = {
271
+ reason: 'internal-fault',
272
+ detail: { message: 'simulated' },
273
+ recoverable: false,
274
+ };
275
+ expect(snapFault.reason).toBe('internal-fault');
276
+ expect(snapFault.recoverable).toBe(false);
277
+ expect(snapFault.detail).toEqual({ message: 'simulated' });
278
+ });
279
+ });
280
+
281
+ // ──────────────────────────────────────────────────────────────────────────────
282
+ // M2 Integration tests (w8 / w9 / w10 — TDD RED)
283
+ //
284
+ // These tests require a Renderer constructed via createRenderer with a mock RHI
285
+ // backend. They are RED until w11 (+ interface) + w12 (+ registry wire) + w13
286
+ // (+ implementation) are complete.
287
+ // ──────────────────────────────────────────────────────────────────────────────
288
+
289
+ // ── Mock RHI setup (mirrors asset.unit.test.ts pattern) ──────────────────────
290
+
291
+ /**
292
+ * Module-level resolver hook so M3 integration tests (w14/w15) can
293
+ * control when device.lost resolves. Set by makeFakeRhiDevice on each call.
294
+ * @internal test-only hook, not part of any package surface.
295
+ */
296
+ let _testDeviceLostResolve: ((info: unknown) => void) | null = null;
297
+
298
+ function makeFakeRhiDevice(): Record<string, unknown> {
299
+ let resolveLost!: (info: unknown) => void;
300
+ const lost = new Promise<unknown>((res) => {
301
+ resolveLost = res;
302
+ });
303
+ _testDeviceLostResolve = resolveLost;
304
+ return {
305
+ __brand: 'RhiDevice',
306
+ lost,
307
+ features: new Set<string>(),
308
+ limits: {} as Record<string, number>,
309
+ // feat-20260707 M5 / w33: createRenderer projects RhiCaps.textureCompression*
310
+ // into TranscodeCaps at registry-build time; the fake device needs a caps
311
+ // object (the real RhiDevice always carries one).
312
+ caps: {
313
+ textureCompressionBc: false,
314
+ textureCompressionEtc2: false,
315
+ textureCompressionAstc: false,
316
+ },
317
+ queue: {
318
+ submit: () => undefined,
319
+ writeBuffer: () => undefined,
320
+ },
321
+ createBuffer: () => ({ ok: true, value: { __brand: 'Buffer' } }),
322
+ createTexture: () => ({ ok: true, value: { __brand: 'Texture' } }),
323
+ createBindGroupLayout: () => ({ ok: true, value: { __brand: 'BindGroupLayout' } }),
324
+ createBindGroup: () => ({ ok: true, value: { __brand: 'BindGroup' } }),
325
+ createPipelineLayout: () => ({ ok: true, value: { __brand: 'PipelineLayout' } }),
326
+ createRenderPipeline: () => ({ ok: true, value: { __brand: 'RenderPipeline' } }),
327
+ createSampler: () => ({ ok: true, value: { __brand: 'Sampler' } }),
328
+ createShaderModule: () => ({ ok: true, value: { __brand: 'ShaderModule' } }),
329
+ createTextureView: () => ({ ok: true, value: { __brand: 'TextureView' } }),
330
+ createCommandEncoder: () => ({
331
+ ok: true,
332
+ value: {
333
+ beginRenderPass: () => ({
334
+ setPipeline: () => undefined,
335
+ setBindGroup: () => undefined,
336
+ setVertexBuffer: () => undefined,
337
+ setIndexBuffer: () => undefined,
338
+ draw: () => undefined,
339
+ drawIndexed: () => undefined,
340
+ end: () => undefined,
341
+ }),
342
+ finish: () => ({ __brand: 'CommandBuffer' }),
343
+ },
344
+ }),
345
+ };
346
+ }
347
+
348
+ function makeExplicitRhi(): RhiInstance {
349
+ const adapter = {
350
+ features: new Set<string>(),
351
+ limits: {},
352
+ requestDevice: async () => ({ ok: true, value: makeFakeRhiDevice() }),
353
+ };
354
+ return {
355
+ requestAdapter: async () => ({ ok: true, value: adapter }),
356
+ acquireCanvasContext: () => ({
357
+ ok: true,
358
+ value: {
359
+ configure: () => ({ ok: true, value: undefined }),
360
+ unconfigure: () => ({ ok: true, value: undefined }),
361
+ getCurrentTexture: () => ({ ok: true, value: { __brand: 'TextureView' } }),
362
+ },
363
+ }),
364
+ createShaderModule: async () => ({ ok: true, value: { __brand: 'ShaderModule' } }),
365
+ } as unknown as RhiInstance;
366
+ }
367
+
368
+ function makeMockCanvas(): HTMLCanvasElement {
369
+ return {
370
+ width: 800,
371
+ height: 600,
372
+ getContext(kind: string): unknown {
373
+ if (kind === 'webgpu') {
374
+ return {
375
+ __mockTag: 'webgpu-canvas-context',
376
+ configure: () => undefined,
377
+ unconfigure: () => undefined,
378
+ getCurrentTexture: () => ({ createView: () => ({}) }),
379
+ };
380
+ }
381
+ if (kind === 'webgl2') {
382
+ return {
383
+ __mockTag: 'webgl2',
384
+ getExtension: () => null,
385
+ getParameter: () => 1,
386
+ isContextLost: () => false,
387
+ };
388
+ }
389
+ return null;
390
+ },
391
+ addEventListener: () => undefined,
392
+ removeEventListener: () => undefined,
393
+ } as Partial<HTMLCanvasElement> as HTMLCanvasElement;
394
+ }
395
+
396
+ vi.mock('@forgeax/engine-rhi-webgpu', async () => {
397
+ const actualRhi =
398
+ await vi.importActual<typeof import('@forgeax/engine-rhi')>('@forgeax/engine-rhi');
399
+ const fakeAdapter = {
400
+ features: new Set<string>(),
401
+ limits: {} as Readonly<Record<string, number>>,
402
+ async requestDevice() {
403
+ return actualRhi.ok(makeFakeRhiDevice());
404
+ },
405
+ };
406
+ return {
407
+ rhi: {
408
+ requestAdapter: async () => actualRhi.ok(fakeAdapter),
409
+ acquireCanvasContext: (_canvas: unknown) =>
410
+ actualRhi.ok({
411
+ configure: () => actualRhi.ok(undefined),
412
+ unconfigure: () => actualRhi.ok(undefined),
413
+ getCurrentTexture: () => actualRhi.ok({ __brand: 'TextureView' }),
414
+ }),
415
+ },
416
+ createShaderModule: async () => actualRhi.ok({ __brand: 'ShaderModule' } as unknown as object),
417
+ };
418
+ });
419
+
420
+ vi.mock('@forgeax/engine-rhi-wgpu', async () => {
421
+ const actualRhi =
422
+ await vi.importActual<typeof import('@forgeax/engine-rhi')>('@forgeax/engine-rhi');
423
+ const fakeAdapter = {
424
+ features: new Set<string>(),
425
+ limits: {} as Readonly<Record<string, number>>,
426
+ async requestDevice() {
427
+ return actualRhi.ok(makeFakeRhiDevice());
428
+ },
429
+ };
430
+ return {
431
+ rhi: {
432
+ requestAdapter: async () => actualRhi.ok(fakeAdapter),
433
+ acquireCanvasContext: (_canvas: unknown) =>
434
+ actualRhi.ok({
435
+ configure: () => actualRhi.ok(undefined),
436
+ unconfigure: () => actualRhi.ok(undefined),
437
+ getCurrentTexture: () => actualRhi.ok({ __brand: 'TextureView' }),
438
+ }),
439
+ },
440
+ ensureReady: async () => undefined,
441
+ };
442
+ });
443
+
444
+ let makeGPUSpy: ReturnType<typeof makeStubGPU>;
445
+ function makeStubGPU() {
446
+ return {
447
+ requestAdapter: async () => ({
448
+ features: new Set<string>(),
449
+ limits: {},
450
+ requestDevice: async () => makeFakeRhiDevice(),
451
+ }),
452
+ getPreferredCanvasFormat: () => 'bgra8unorm',
453
+ };
454
+ }
455
+
456
+ // Minimal shader manifest as data URL — provides a manifest that the
457
+ // ShaderRegistry can parse without HTTP requests, following the
458
+ // bind-group-cache-frame.test.ts pattern. Includes a pbr stub with the
459
+ // `f_schlick` content marker so `buildReadyWebGPU` finds the PBR entry.
460
+ const HEALTH_TEST_MANIFEST_URL = (() => {
461
+ const manifest = {
462
+ schemaVersion: '1.0.0',
463
+ entries: [
464
+ {
465
+ hash: 'pbr00000',
466
+ wgsl: '/* pbr stub - calls f_schlick( */',
467
+ glsl: '',
468
+ bindings: '',
469
+ },
470
+ ],
471
+ materialShaders: [],
472
+ };
473
+ return `data:application/json,${encodeURIComponent(JSON.stringify(manifest))}`;
474
+ })();
475
+
476
+ describe('Renderer health/recover integration (M2 RED)', () => {
477
+ beforeEach(() => {
478
+ makeGPUSpy = makeStubGPU();
479
+ vi.stubGlobal('navigator', { ...navigator, gpu: makeGPUSpy });
480
+ });
481
+
482
+ afterEach(() => {
483
+ vi.unstubAllGlobals();
484
+ });
485
+
486
+ // ── w8: health() healthy-state baseline ──────────────────────────────────
487
+
488
+ it('w8: health() returns alive baseline when registry has not been fired', async () => {
489
+ const canvas = makeMockCanvas();
490
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
491
+ const renderer = await createRenderer(
492
+ canvas,
493
+ { rhi: makeExplicitRhi() },
494
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
495
+ );
496
+
497
+ // TDD RED: renderer.health() does not exist on Renderer until w11.
498
+ // After w13, this should return { reason: 'alive', recoverable: false }.
499
+ const snapshot = (
500
+ (renderer as unknown as Record<string, unknown>).health as () => HealthSnapshot
501
+ )?.();
502
+ if (!snapshot) {
503
+ // RED guard: health() not yet implemented — test fails here until w13.
504
+ throw new Error('TDD RED: renderer.health() not implemented yet (expected after w11+w13)');
505
+ }
506
+ expect(snapshot.reason).toBe('alive');
507
+ expect(snapshot.recoverable).toBe(false);
508
+ });
509
+
510
+ // ── w9: recover() healthy-state returns recover-not-needed (AC-04) ────────
511
+ //
512
+ // feat-20260622-s5 M3 / w19 migration: recover() is now async (device rebuild
513
+ // is async). The alive-state guard returns recover-not-needed synchronously
514
+ // inside the Promise. The full rebuild success/failure-code matrix lives in
515
+ // renderer-recover.unit.test.ts (w10-w14); this stays a health-surface smoke.
516
+
517
+ it('w9: recover() on healthy renderer returns recover-not-needed error', async () => {
518
+ const canvas = makeMockCanvas();
519
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
520
+ const renderer = await createRenderer(
521
+ canvas,
522
+ { rhi: makeExplicitRhi() },
523
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
524
+ );
525
+
526
+ const recoverFn = (renderer as unknown as Record<string, unknown>).recover as
527
+ | (() => Promise<Result<void, RecoverError>>)
528
+ | undefined;
529
+ if (!recoverFn) {
530
+ throw new Error('renderer.recover() missing');
531
+ }
532
+ const result = await recoverFn();
533
+ expect(result.ok).toBe(false);
534
+ if (!result.ok) {
535
+ expect(result.error.code).toBe('recover-not-needed');
536
+ expect(typeof result.error.expected).toBe('string');
537
+ expect(result.error.expected.length).toBeGreaterThan(0);
538
+ expect(typeof result.error.hint).toBe('string');
539
+ expect(result.error.hint.length).toBeGreaterThan(0);
540
+ }
541
+ });
542
+
543
+ // ── w10: recover() on degraded state attempts a rebuild, never fakes alive ─
544
+ //
545
+ // feat-20260622-s5 M3 / w19 migration: the S3 placeholder behaviour
546
+ // (recover-not-implemented, health unchanged) is gone — recover() now runs a
547
+ // single idempotent rebuild. On this minimal single-entry HEALTH manifest the
548
+ // rebuild's engine-SSOT-triple check fails, so recover() resolves
549
+ // recover-device-unavailable and LEAVES health at device-lost (A-AC-07: never
550
+ // fakes the renderer back to alive on failure). The success path (full triple
551
+ // manifest -> ok + alive) is covered in renderer-recover.unit.test.ts (w10).
552
+
553
+ it('w10: recover() on degraded renderer attempts rebuild; failure keeps health device-lost', async () => {
554
+ const canvas = makeMockCanvas();
555
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
556
+ const renderer = await createRenderer(
557
+ canvas,
558
+ { rhi: makeExplicitRhi() },
559
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
560
+ );
561
+
562
+ const healthFn = (renderer as unknown as Record<string, unknown>).health as
563
+ | (() => HealthSnapshot)
564
+ | undefined;
565
+ if (!healthFn) {
566
+ throw new Error('renderer.health() missing');
567
+ }
568
+ const recoverFn = (renderer as unknown as Record<string, unknown>).recover as
569
+ | (() => Promise<Result<void, RecoverError>>)
570
+ | undefined;
571
+ if (!recoverFn) {
572
+ throw new Error('renderer.recover() missing');
573
+ }
574
+
575
+ // Drive into degraded state via device.lost (same mock path as w14).
576
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
577
+ _testDeviceLostResolve({
578
+ reason: 'unknown',
579
+ message: 'test device lost for w10 degraded-state',
580
+ });
581
+
582
+ await vi.waitFor(() => {
583
+ expect(healthFn().reason).toBe('device-lost');
584
+ });
585
+ expect(healthFn().reason).toBe('device-lost');
586
+
587
+ // recover() runs a single rebuild attempt. The reserved recover-not-implemented
588
+ // is never produced anymore; on this minimal manifest the rebuild fails with a
589
+ // device-unavailability code.
590
+ const result = await recoverFn();
591
+ expect(result.ok).toBe(false);
592
+ if (!result.ok) {
593
+ expect(result.error.code).not.toBe('recover-not-implemented');
594
+ expect(result.error.code).toBe('recover-device-unavailable');
595
+ }
596
+
597
+ // A-AC-07: failure never fakes the renderer back to alive.
598
+ const snapAfter = healthFn();
599
+ expect(snapAfter.reason).toBe('device-lost');
600
+ expect(snapAfter.recoverable).toBe(true);
601
+ });
602
+ });
603
+
604
+ // ──────────────────────────────────────────────────────────────────────────────
605
+ // M2 draw guard tests (w7 — TDD RED)
606
+ //
607
+ // These tests verify device-lost draw() silent return + disposed latch. They are
608
+ // RED until w9 adds the health-state guard in draw().
609
+ // ──────────────────────────────────────────────────────────────────────────────
610
+
611
+ describe('Renderer draw device-lost guard (w7 TDD RED)', () => {
612
+ beforeEach(() => {
613
+ makeGPUSpy = makeStubGPU();
614
+ vi.stubGlobal('navigator', { ...navigator, gpu: makeGPUSpy });
615
+ });
616
+
617
+ afterEach(() => {
618
+ vi.unstubAllGlobals();
619
+ _testDeviceLostResolve = null;
620
+ });
621
+
622
+ // ── w7(a): device-lost -> draw() returns err silently ──────────────────────
623
+
624
+ it('w7(a): device-lost state draw() returns Result.err without firing onError each frame', async () => {
625
+ const canvas = makeMockCanvas();
626
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
627
+ const renderer = await createRenderer(
628
+ canvas,
629
+ { rhi: makeExplicitRhi() },
630
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
631
+ );
632
+
633
+ const healthFn = (renderer as unknown as Record<string, unknown>).health as
634
+ | (() => HealthSnapshot)
635
+ | undefined;
636
+ if (!healthFn) {
637
+ throw new Error('TDD RED: renderer.health() not found');
638
+ }
639
+
640
+ // Subscribe to onError to verify no per-frame fire
641
+ const onErrorFn = (renderer as unknown as Record<string, unknown>).onError as
642
+ | ((cb: (err: { code: string }) => void) => () => void)
643
+ | undefined;
644
+ if (!onErrorFn) {
645
+ throw new Error('TDD RED: renderer.onError() not found');
646
+ }
647
+ const errorCb = vi.fn<(err: { code: string }) => void>();
648
+ onErrorFn(errorCb);
649
+
650
+ // Need a World with Camera to reach draw internals
651
+ const { World } = await import('@forgeax/engine-ecs');
652
+ const { Transform } = await import('@forgeax/engine-scene');
653
+ const { Camera } = await import('@forgeax/engine-render/internal');
654
+ const world = new World();
655
+ world.spawn(
656
+ {
657
+ component: Transform,
658
+ data: {
659
+ pos: [0, 0, 10],
660
+ quat: [0, 0, 0, 1],
661
+ scale: [1, 1, 1],
662
+ },
663
+ },
664
+ {
665
+ component: Camera,
666
+ data: {
667
+ fov: Math.PI / 4,
668
+ aspect: 1,
669
+ near: 0.1,
670
+ far: 100,
671
+ clearColor: [0, 0, 0, 1],
672
+ },
673
+ },
674
+ );
675
+
676
+ await renderer.ready;
677
+
678
+ // Baseline: health is alive
679
+ expect(healthFn().reason).toBe('alive');
680
+
681
+ // Trigger device-lost
682
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
683
+ _testDeviceLostResolve({
684
+ reason: 'unknown',
685
+ message: 'device lost for draw guard test',
686
+ });
687
+
688
+ await vi.waitFor(() => {
689
+ expect(healthFn().reason).toBe('device-lost');
690
+ });
691
+
692
+ // Reset error spy counter after lost event (the lost channel itself fires onError once)
693
+ errorCb.mockClear();
694
+
695
+ // Draw N=5 times in device-lost state
696
+ for (let i = 0; i < 5; i++) {
697
+ const result = renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
698
+ // TDD RED / AC-10: draw returns err silently (not ok for device-lost)
699
+ expect(result.ok).toBe(false);
700
+ }
701
+
702
+ // TDD RED / AC-10: onError was NOT fired during those 5 draws (silent return)
703
+ // Current behavior (w7 RED): draw fires onError each frame through the normal
704
+ // device-lost flow (dual-channel), or the disposed/rhi-not-available path fires.
705
+ // After w9 fix: zero onError fires for draw() during device-lost.
706
+ expect(errorCb).not.toHaveBeenCalled();
707
+ });
708
+
709
+ // ── w7(b): disposed latch — post-dispose lost callback is no-op ────────────
710
+
711
+ it('w7(b): disposed latch prevents reconstruction on device-lost event', async () => {
712
+ const canvas = makeMockCanvas();
713
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
714
+ const renderer = await createRenderer(
715
+ canvas,
716
+ { rhi: makeExplicitRhi() },
717
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
718
+ );
719
+
720
+ // TDD RED: dispose then trigger lost — should not try to reconstruct
721
+ const disposeFn = (renderer as unknown as Record<string, unknown>).dispose as
722
+ | (() => void)
723
+ | undefined;
724
+ if (!disposeFn) {
725
+ throw new Error('TDD RED: renderer.dispose() not found');
726
+ }
727
+
728
+ disposeFn();
729
+
730
+ // After dispose, trigger device.lost (should be no-op, no throw)
731
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
732
+ _testDeviceLostResolve({
733
+ reason: 'destroyed',
734
+ message: 'lost after dispose',
735
+ });
736
+
737
+ // Allow microtask flush — no assertion needed beyond "doesn't throw/crash"
738
+ await new Promise((r) => setTimeout(r, 50));
739
+
740
+ // TDD RED: disposed renderer.draw returns err
741
+ const { World } = await import('@forgeax/engine-ecs');
742
+ const world = new World();
743
+ const result = renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
744
+ expect(result.ok).toBe(false);
745
+ });
746
+ });
747
+
748
+ // ──────────────────────────────────────────────────────────────────────────────
749
+ // M3 Integration tests (w14 / w15 — TDD RED)
750
+ //
751
+ // These tests verify the device.lost health channel wire. They are RED until
752
+ // w16 adds the healthRegistry.fire() call in device.lost.then().
753
+ // ──────────────────────────────────────────────────────────────────────────────
754
+
755
+ describe('Renderer health device.lost integration (M3 RED)', () => {
756
+ beforeEach(() => {
757
+ makeGPUSpy = makeStubGPU();
758
+ vi.stubGlobal('navigator', { ...navigator, gpu: makeGPUSpy });
759
+ });
760
+
761
+ afterEach(() => {
762
+ vi.unstubAllGlobals();
763
+ _testDeviceLostResolve = null;
764
+ });
765
+
766
+ // ── w14: device.lost health update (AC-10) ─────────────────────────────────
767
+
768
+ it('w14: device.lost reason=unknown sets health().reason to device-lost with correct detail + recoverable', async () => {
769
+ const canvas = makeMockCanvas();
770
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
771
+ const renderer = await createRenderer(
772
+ canvas,
773
+ { rhi: makeExplicitRhi() },
774
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
775
+ );
776
+
777
+ // TDD RED: health() does not exist on Renderer until w11.
778
+ const healthFn = (renderer as unknown as Record<string, unknown>).health as
779
+ | (() => HealthSnapshot)
780
+ | undefined;
781
+ if (!healthFn) {
782
+ throw new Error('TDD RED: renderer.health() not implemented yet');
783
+ }
784
+
785
+ // Baseline: alive before device loss
786
+ expect(healthFn().reason).toBe('alive');
787
+
788
+ // Trigger device.lost via the module-level resolver hook. reason 'unknown'
789
+ // = genuine unrecoverable loss (driver crash / TDR) which DOES flip health
790
+ // to device-lost. (reason 'destroyed' = intentional teardown, gated -- see
791
+ // w14b below.)
792
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
793
+ _testDeviceLostResolve({
794
+ reason: 'unknown',
795
+ message: 'device lost (driver crash)',
796
+ });
797
+
798
+ // Allow the microtask queue to flush so device.lost.then() fires
799
+ await vi.waitFor(() => {
800
+ expect(healthFn().reason).toBe('device-lost');
801
+ });
802
+
803
+ const snap = healthFn();
804
+ expect(snap.reason).toBe('device-lost');
805
+ expect(snap.recoverable).toBe(true);
806
+
807
+ // TS discriminated union narrows snap: in 'device-lost' branch detail is
808
+ // HealthDetailDeviceLost with required lostReason (AC-05, no toHaveProperty bypass).
809
+ if (snap.reason === 'device-lost') {
810
+ expect(snap.detail.lostReason).toBe('unknown');
811
+ expect(snap.detail.message).toBe('device lost (driver crash)');
812
+ }
813
+ });
814
+
815
+ it('w14: device.lost with unknown reason sets lostReason to unknown', async () => {
816
+ const canvas = makeMockCanvas();
817
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
818
+ const renderer = await createRenderer(
819
+ canvas,
820
+ { rhi: makeExplicitRhi() },
821
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
822
+ );
823
+
824
+ const healthFn = (renderer as unknown as Record<string, unknown>).health as
825
+ | (() => HealthSnapshot)
826
+ | undefined;
827
+ if (!healthFn) {
828
+ throw new Error('TDD RED: renderer.health() not implemented yet');
829
+ }
830
+
831
+ // Device lost with reason: 'unknown'
832
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
833
+ _testDeviceLostResolve({
834
+ reason: 'unknown',
835
+ message: '',
836
+ });
837
+
838
+ await vi.waitFor(() => {
839
+ expect(healthFn().reason).toBe('device-lost');
840
+ });
841
+
842
+ const snap = healthFn();
843
+ if (snap.reason === 'device-lost') {
844
+ expect(snap.detail.lostReason).toBe('unknown');
845
+ }
846
+ });
847
+
848
+ // ── w15: onHealthChange callback triggered on device.lost (AC-10) ──────────
849
+
850
+ it('w15: onHealthChange callback called exactly once on device.lost', async () => {
851
+ const canvas = makeMockCanvas();
852
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
853
+ const renderer = await createRenderer(
854
+ canvas,
855
+ { rhi: makeExplicitRhi() },
856
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
857
+ );
858
+
859
+ const onHealthChangeFn = (renderer as unknown as Record<string, unknown>).onHealthChange as
860
+ | ((cb: HealthChangeListener) => () => void)
861
+ | undefined;
862
+ if (!onHealthChangeFn) {
863
+ throw new Error('TDD RED: renderer.onHealthChange() not implemented yet');
864
+ }
865
+
866
+ const cb = vi.fn<HealthChangeListener>();
867
+ onHealthChangeFn(cb);
868
+
869
+ // Before device loss, cb should not have been called
870
+ expect(cb).not.toHaveBeenCalled();
871
+
872
+ // Trigger device.lost
873
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
874
+ _testDeviceLostResolve({ reason: 'unknown', message: 'lost' });
875
+
876
+ // Wait for the health channel to fire
877
+ await vi.waitFor(() => {
878
+ expect(cb).toHaveBeenCalled();
879
+ });
880
+
881
+ // Called exactly once
882
+ expect(cb).toHaveBeenCalledTimes(1);
883
+
884
+ // Callback received the correct snapshot
885
+ const snap = cb.mock.calls[0]?.[0];
886
+ expect(snap).toBeDefined();
887
+ if (snap) {
888
+ expect(snap.reason).toBe('device-lost');
889
+ expect(snap.recoverable).toBe(true);
890
+ }
891
+ });
892
+
893
+ it('w15: late-attach replay after device.lost fires immediately', async () => {
894
+ const canvas = makeMockCanvas();
895
+ const { createRenderer } = await import('../../../render/src/renderer/renderer-factory');
896
+ const renderer = await createRenderer(
897
+ canvas,
898
+ { rhi: makeExplicitRhi() },
899
+ { shaderManifestUrl: HEALTH_TEST_MANIFEST_URL },
900
+ );
901
+
902
+ // Trigger device.lost BEFORE registering the callback
903
+ if (!_testDeviceLostResolve) throw new Error('device.lost resolver not set up');
904
+ _testDeviceLostResolve({ reason: 'unknown', message: 'late-attach test' });
905
+
906
+ // Flush the microtask so healthRegistry.fire() completes
907
+ const healthFn = (renderer as unknown as Record<string, unknown>).health as
908
+ | (() => HealthSnapshot)
909
+ | undefined;
910
+ if (!healthFn) {
911
+ throw new Error('TDD RED: renderer.health() not implemented yet');
912
+ }
913
+
914
+ await vi.waitFor(() => {
915
+ expect(healthFn().reason).toBe('device-lost');
916
+ });
917
+
918
+ // Now register callback — late-attach replay should fire immediately
919
+ const onHealthChangeFn = (renderer as unknown as Record<string, unknown>).onHealthChange as
920
+ | ((cb: HealthChangeListener) => () => void)
921
+ | undefined;
922
+ if (!onHealthChangeFn) {
923
+ throw new Error('TDD RED: renderer.onHealthChange() not implemented yet');
924
+ }
925
+
926
+ const cb = vi.fn<HealthChangeListener>();
927
+ onHealthChangeFn(cb);
928
+
929
+ // Called immediately via late-attach replay
930
+ expect(cb).toHaveBeenCalledTimes(1);
931
+ const snap = cb.mock.calls[0]?.[0];
932
+ expect(snap?.reason).toBe('device-lost');
933
+ expect(snap?.recoverable).toBe(true);
934
+ });
935
+ });