@forgeax/engine-runtime 0.0.0-dev.8d955ade1c79

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 (1017) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +165 -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-collect-roundtrip.test.d.ts +2 -0
  19. package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
  20. package/dist/__tests__/animation-graph-default-path.integration.test.d.ts +2 -0
  21. package/dist/__tests__/animation-graph-default-path.integration.test.d.ts.map +1 -0
  22. package/dist/__tests__/animation-graph-describe.unit.test.d.ts +2 -0
  23. package/dist/__tests__/animation-graph-describe.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/animation-graph-errors.unit.test.d.ts +2 -0
  25. package/dist/__tests__/animation-graph-errors.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/animation-graph-nesting.unit.test.d.ts +2 -0
  27. package/dist/__tests__/animation-graph-nesting.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts +2 -0
  29. package/dist/__tests__/animation-graph-orthogonal-weight.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
  31. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts +2 -0
  33. package/dist/__tests__/animation-graph-slot-fill.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/animation-nslot.unit.test.d.ts +2 -0
  35. package/dist/__tests__/animation-nslot.unit.test.d.ts.map +1 -0
  36. package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts +2 -0
  37. package/dist/__tests__/animation-slot-length-guard.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/append-injection.test.d.ts +2 -0
  39. package/dist/__tests__/append-injection.test.d.ts.map +1 -0
  40. package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts +2 -0
  41. package/dist/__tests__/asi-world-baseline-export.unit.test.d.ts.map +1 -0
  42. package/dist/__tests__/asi-world-ci-config.unit.test.d.ts +2 -0
  43. package/dist/__tests__/asi-world-ci-config.unit.test.d.ts.map +1 -0
  44. package/dist/__tests__/asi-world-smoke.unit.test.d.ts +2 -0
  45. package/dist/__tests__/asi-world-smoke.unit.test.d.ts.map +1 -0
  46. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
  47. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
  48. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
  49. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
  50. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
  51. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
  52. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
  53. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
  54. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
  55. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
  56. package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
  57. package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
  58. package/dist/__tests__/asset-registry-scene.test-d.d.ts +2 -0
  59. package/dist/__tests__/asset-registry-scene.test-d.d.ts.map +1 -0
  60. package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
  61. package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
  62. package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
  63. package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
  64. package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
  65. package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
  66. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
  67. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
  68. package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
  69. package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
  70. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
  71. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
  72. package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
  73. package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
  74. package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
  75. package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/asset.unit.test.d.ts +2 -0
  77. package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
  78. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
  79. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
  81. package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
  82. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
  83. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
  84. package/dist/__tests__/bind-group-cache-keying.test.d.ts +2 -0
  85. package/dist/__tests__/bind-group-cache-keying.test.d.ts.map +1 -0
  86. package/dist/__tests__/block-upload-math.unit.test.d.ts +2 -0
  87. package/dist/__tests__/block-upload-math.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
  89. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/builtin-shader-register-e2e.test.d.ts +2 -0
  91. package/dist/__tests__/builtin-shader-register-e2e.test.d.ts.map +1 -0
  92. package/dist/__tests__/cache-false-eviction.test.d.ts +2 -0
  93. package/dist/__tests__/cache-false-eviction.test.d.ts.map +1 -0
  94. package/dist/__tests__/cache-isolation-matrix.test.d.ts +2 -0
  95. package/dist/__tests__/cache-isolation-matrix.test.d.ts.map +1 -0
  96. package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts +2 -0
  97. package/dist/__tests__/camera-clear-snapshot-equivalence.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts +2 -0
  99. package/dist/__tests__/clamp-to-last.e2e.browser.test.d.ts.map +1 -0
  100. package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts +2 -0
  101. package/dist/__tests__/clamp-to-last.e2e.dawn.test.d.ts.map +1 -0
  102. package/dist/__tests__/collect-scene-asset.test.d.ts +2 -0
  103. package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -0
  104. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
  105. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
  106. package/dist/__tests__/collect-subtree.unit.test.d.ts +2 -0
  107. package/dist/__tests__/collect-subtree.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/collect-transient-children-absent.test.d.ts +2 -0
  109. package/dist/__tests__/collect-transient-children-absent.test.d.ts.map +1 -0
  110. package/dist/__tests__/collect-transient-roundtrip.test.d.ts +2 -0
  111. package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -0
  112. package/dist/__tests__/collect-transient-skip.test.d.ts +2 -0
  113. package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -0
  114. package/dist/__tests__/components.test-d.d.ts +2 -0
  115. package/dist/__tests__/components.test-d.d.ts.map +1 -0
  116. package/dist/__tests__/components.unit.test.d.ts +2 -0
  117. package/dist/__tests__/components.unit.test.d.ts.map +1 -0
  118. package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts +2 -0
  119. package/dist/__tests__/composite-skybox-cross-world.browser.test.d.ts.map +1 -0
  120. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
  121. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
  122. package/dist/__tests__/create-renderer-assembly.integration.test.d.ts +2 -0
  123. package/dist/__tests__/create-renderer-assembly.integration.test.d.ts.map +1 -0
  124. package/dist/__tests__/createRenderer-dispose.test.d.ts +2 -0
  125. package/dist/__tests__/createRenderer-dispose.test.d.ts.map +1 -0
  126. package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts +2 -0
  127. package/dist/__tests__/createRenderer-requiredFeatures.unit.test.d.ts.map +1 -0
  128. package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts +2 -0
  129. package/dist/__tests__/createRenderer.browser-no-webgpu.test.d.ts.map +1 -0
  130. package/dist/__tests__/createRenderer.unit.test.d.ts +2 -0
  131. package/dist/__tests__/createRenderer.unit.test.d.ts.map +1 -0
  132. package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts +2 -0
  133. package/dist/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.d.ts.map +1 -0
  134. package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts +2 -0
  135. package/dist/__tests__/dawn/ibl-compose.dawn.test.d.ts.map +1 -0
  136. package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts +2 -0
  137. package/dist/__tests__/dawn/ibl-modules-compose.dawn.test.d.ts.map +1 -0
  138. package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts +2 -0
  139. package/dist/__tests__/dawn/ibl-precompute-readback.dawn.test.d.ts.map +1 -0
  140. package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts +2 -0
  141. package/dist/__tests__/dawn/instances-per-instance-pbr.dawn.test.d.ts.map +1 -0
  142. package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts +2 -0
  143. package/dist/__tests__/dawn/instances-shadow.dawn.test.d.ts.map +1 -0
  144. package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts +2 -0
  145. package/dist/__tests__/dawn/instances-uniform-fallback.dawn.test.d.ts.map +1 -0
  146. package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts +2 -0
  147. package/dist/__tests__/dawn/material-alpha.dawn.test.d.ts.map +1 -0
  148. package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts +2 -0
  149. package/dist/__tests__/dawn/material-cooked-fixture.dawn.test.d.ts.map +1 -0
  150. package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts +2 -0
  151. package/dist/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.d.ts.map +1 -0
  152. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
  153. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
  154. package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts +2 -0
  155. package/dist/__tests__/dawn/mipmap-srgb-linear.dawn.test.d.ts.map +1 -0
  156. package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts +2 -0
  157. package/dist/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.d.ts.map +1 -0
  158. package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts +2 -0
  159. package/dist/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.d.ts.map +1 -0
  160. package/dist/__tests__/dawn/tonemap.dawn.test.d.ts +2 -0
  161. package/dist/__tests__/dawn/tonemap.dawn.test.d.ts.map +1 -0
  162. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
  163. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
  164. package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts +2 -0
  165. package/dist/__tests__/dawn/user-handle-mesh-render.dawn.test.d.ts.map +1 -0
  166. package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts +2 -0
  167. package/dist/__tests__/dawn/user-mesh-upload.dawn.test.d.ts.map +1 -0
  168. package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts +2 -0
  169. package/dist/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.d.ts.map +1 -0
  170. package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts +2 -0
  171. package/dist/__tests__/dawn/zero-manifest-ready.dawn.test.d.ts.map +1 -0
  172. package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts +2 -0
  173. package/dist/__tests__/demo-sortscope-migration.unit.test.d.ts.map +1 -0
  174. package/dist/__tests__/derive-bgl-integration.test.d.ts +2 -0
  175. package/dist/__tests__/derive-bgl-integration.test.d.ts.map +1 -0
  176. package/dist/__tests__/derive-render-data-skin.unit.test.d.ts +2 -0
  177. package/dist/__tests__/derive-render-data-skin.unit.test.d.ts.map +1 -0
  178. package/dist/__tests__/draw-published.d.ts +5 -0
  179. package/dist/__tests__/draw-published.d.ts.map +1 -0
  180. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
  181. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
  182. package/dist/__tests__/environment-error-exhaustive.test-d.d.ts +8 -0
  183. package/dist/__tests__/environment-error-exhaustive.test-d.d.ts.map +1 -0
  184. package/dist/__tests__/equirect-bc6h.integration.test.d.ts +2 -0
  185. package/dist/__tests__/equirect-bc6h.integration.test.d.ts.map +1 -0
  186. package/dist/__tests__/error-exhaustive.test.d.ts +2 -0
  187. package/dist/__tests__/error-exhaustive.test.d.ts.map +1 -0
  188. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  189. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  190. package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts +2 -0
  191. package/dist/__tests__/extract-frames-graceful-degradation.test.d.ts.map +1 -0
  192. package/dist/__tests__/extract-frames-merge.test.d.ts +2 -0
  193. package/dist/__tests__/extract-frames-merge.test.d.ts.map +1 -0
  194. package/dist/__tests__/extract-frames-reset.test.d.ts +2 -0
  195. package/dist/__tests__/extract-frames-reset.test.d.ts.map +1 -0
  196. package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts +2 -0
  197. package/dist/__tests__/extract-record-no-hardcoded-texture-fields.test.d.ts.map +1 -0
  198. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
  199. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
  200. package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
  201. package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
  202. package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
  203. package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
  204. package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts +2 -0
  205. package/dist/__tests__/frame-targets-shadow-regression.unit.test.d.ts.map +1 -0
  206. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
  207. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
  208. package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts +2 -0
  209. package/dist/__tests__/fullscreen-post-bgl-depth.test.d.ts.map +1 -0
  210. package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts +2 -0
  211. package/dist/__tests__/fullscreen-post-depth-params-arity.test.d.ts.map +1 -0
  212. package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts +2 -0
  213. package/dist/__tests__/fullscreen-post-process-pass.dawn.test.d.ts.map +1 -0
  214. package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts +2 -0
  215. package/dist/__tests__/fullscreen-post-process-pass.unit.test.d.ts.map +1 -0
  216. package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts +2 -0
  217. package/dist/__tests__/fxaa-pixel-diff.dawn.test.d.ts.map +1 -0
  218. package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts +2 -0
  219. package/dist/__tests__/fxaa-validation-and-resize.dawn.test.d.ts.map +1 -0
  220. package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts +2 -0
  221. package/dist/__tests__/fxaa-zero-overhead.dawn.test.d.ts.map +1 -0
  222. package/dist/__tests__/geometry.unit.test.d.ts +2 -0
  223. package/dist/__tests__/geometry.unit.test.d.ts.map +1 -0
  224. package/dist/__tests__/glyph-tilemap-worldid.test.d.ts +2 -0
  225. package/dist/__tests__/glyph-tilemap-worldid.test.d.ts.map +1 -0
  226. package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts +2 -0
  227. package/dist/__tests__/gpu-resource-cow-survivor.test.d.ts.map +1 -0
  228. package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
  229. package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
  230. package/dist/__tests__/handle-migration.test.d.ts +2 -0
  231. package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
  232. package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts +2 -0
  233. package/dist/__tests__/hello-tilemap-smoke-upgrade.unit.test.d.ts.map +1 -0
  234. package/dist/__tests__/helpers/mock-shader-registry.d.ts +11 -0
  235. package/dist/__tests__/helpers/mock-shader-registry.d.ts.map +1 -0
  236. package/dist/__tests__/helpers/register-runtime-components.d.ts +4 -0
  237. package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -0
  238. package/dist/__tests__/helpers/register-scene-components.d.ts +4 -0
  239. package/dist/__tests__/helpers/register-scene-components.d.ts.map +1 -0
  240. package/dist/__tests__/helpers/tilemap-assets.d.ts +6 -0
  241. package/dist/__tests__/helpers/tilemap-assets.d.ts.map +1 -0
  242. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
  243. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
  244. package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
  245. package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
  246. package/dist/__tests__/inspect-name.test.d.ts +2 -0
  247. package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
  248. package/dist/__tests__/instances.test-d.d.ts +2 -0
  249. package/dist/__tests__/instances.test-d.d.ts.map +1 -0
  250. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
  251. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
  252. package/dist/__tests__/light-attenuation-formula.test.d.ts +2 -0
  253. package/dist/__tests__/light-attenuation-formula.test.d.ts.map +1 -0
  254. package/dist/__tests__/light-casters-9-light.browser.test.d.ts +2 -0
  255. package/dist/__tests__/light-casters-9-light.browser.test.d.ts.map +1 -0
  256. package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts +2 -0
  257. package/dist/__tests__/light-gpu-byte-neutral.unit.test.d.ts.map +1 -0
  258. package/dist/__tests__/light-snapshot.test-d.d.ts +2 -0
  259. package/dist/__tests__/light-snapshot.test-d.d.ts.map +1 -0
  260. package/dist/__tests__/lights-vec-negative.unit.test.d.ts +2 -0
  261. package/dist/__tests__/lights-vec-negative.unit.test.d.ts.map +1 -0
  262. package/dist/__tests__/lights.unit.test.d.ts +2 -0
  263. package/dist/__tests__/lights.unit.test.d.ts.map +1 -0
  264. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
  265. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
  266. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
  267. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
  268. package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
  269. package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
  270. package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
  271. package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
  272. package/dist/__tests__/m3-vec-negative.unit.test.d.ts +2 -0
  273. package/dist/__tests__/m3-vec-negative.unit.test.d.ts.map +1 -0
  274. package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts +2 -0
  275. package/dist/__tests__/m5-browser-dawn-sweep.integration.test.d.ts.map +1 -0
  276. package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts +2 -0
  277. package/dist/__tests__/material-texture-uv-scale.unit.test.d.ts.map +1 -0
  278. package/dist/__tests__/materials.unit.test.d.ts +2 -0
  279. package/dist/__tests__/materials.unit.test.d.ts.map +1 -0
  280. package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
  281. package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
  282. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
  283. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
  284. package/dist/__tests__/mesh-bin.test.d.ts +2 -0
  285. package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
  286. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
  287. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
  288. package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts +2 -0
  289. package/dist/__tests__/mesh-ssbo-grow.unit.test.d.ts.map +1 -0
  290. package/dist/__tests__/mip-gate.unit.test.d.ts +2 -0
  291. package/dist/__tests__/mip-gate.unit.test.d.ts.map +1 -0
  292. package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts +2 -0
  293. package/dist/__tests__/msaa-sprite-pixel-diff.dawn.test.d.ts.map +1 -0
  294. package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts +2 -0
  295. package/dist/__tests__/multi-uv-8set.e2e.dawn.test.d.ts.map +1 -0
  296. package/dist/__tests__/name.unit.test.d.ts +2 -0
  297. package/dist/__tests__/name.unit.test.d.ts.map +1 -0
  298. package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
  299. package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
  300. package/dist/__tests__/package-promotion.test.d.ts +2 -0
  301. package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
  302. package/dist/__tests__/package-rename.test.d.ts +2 -0
  303. package/dist/__tests__/package-rename.test.d.ts.map +1 -0
  304. package/dist/__tests__/pass-selector.unit.test.d.ts +2 -0
  305. package/dist/__tests__/pass-selector.unit.test.d.ts.map +1 -0
  306. package/dist/__tests__/pbr-pipeline.unit.test.d.ts +2 -0
  307. package/dist/__tests__/pbr-pipeline.unit.test.d.ts.map +1 -0
  308. package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts +2 -0
  309. package/dist/__tests__/pipeline-builder-msaa.unit.test.d.ts.map +1 -0
  310. package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts +2 -0
  311. package/dist/__tests__/pipeline-cache-keying.unit.test.d.ts.map +1 -0
  312. package/dist/__tests__/pipeline-spec.test.d.ts +2 -0
  313. package/dist/__tests__/pipeline-spec.test.d.ts.map +1 -0
  314. package/dist/__tests__/pipeline.unit.test.d.ts +2 -0
  315. package/dist/__tests__/pipeline.unit.test.d.ts.map +1 -0
  316. package/dist/__tests__/point-light-shadow.browser.test.d.ts +2 -0
  317. package/dist/__tests__/point-light-shadow.browser.test.d.ts.map +1 -0
  318. package/dist/__tests__/point-light-shadow.dawn.test.d.ts +2 -0
  319. package/dist/__tests__/point-light-shadow.dawn.test.d.ts.map +1 -0
  320. package/dist/__tests__/point-light-shadow.unit.test.d.ts +2 -0
  321. package/dist/__tests__/point-light-shadow.unit.test.d.ts.map +1 -0
  322. package/dist/__tests__/post-process-error-codes.unit.test.d.ts +2 -0
  323. package/dist/__tests__/post-process-error-codes.unit.test.d.ts.map +1 -0
  324. package/dist/__tests__/post-process-params-component.unit.test.d.ts +2 -0
  325. package/dist/__tests__/post-process-params-component.unit.test.d.ts.map +1 -0
  326. package/dist/__tests__/post-process-params-extract.unit.test.d.ts +2 -0
  327. package/dist/__tests__/post-process-params-extract.unit.test.d.ts.map +1 -0
  328. package/dist/__tests__/postprocess-camera-consistency.test.d.ts +2 -0
  329. package/dist/__tests__/postprocess-camera-consistency.test.d.ts.map +1 -0
  330. package/dist/__tests__/profiler-assembly.integration.test.d.ts +2 -0
  331. package/dist/__tests__/profiler-assembly.integration.test.d.ts.map +1 -0
  332. package/dist/__tests__/propagate-transforms.dawn.test.d.ts +2 -0
  333. package/dist/__tests__/propagate-transforms.dawn.test.d.ts.map +1 -0
  334. package/dist/__tests__/record-worldid-isolation.test.d.ts +2 -0
  335. package/dist/__tests__/record-worldid-isolation.test.d.ts.map +1 -0
  336. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +11 -0
  337. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -0
  338. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +11 -0
  339. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -0
  340. package/dist/__tests__/render-feature-assembly.test-d.d.ts +2 -0
  341. package/dist/__tests__/render-feature-assembly.test-d.d.ts.map +1 -0
  342. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts +2 -0
  343. package/dist/__tests__/render-feature-prepared-graphics-docs.unit.test.d.ts.map +1 -0
  344. package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts +2 -0
  345. package/dist/__tests__/render-feature-prepared-graphics.browser.test.d.ts.map +1 -0
  346. package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts +2 -0
  347. package/dist/__tests__/render-feature-prepared-graphics.dawn.test.d.ts.map +1 -0
  348. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
  349. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
  350. package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts +2 -0
  351. package/dist/__tests__/render-feature-prepared-graphics.integration.test.d.ts.map +1 -0
  352. package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts +2 -0
  353. package/dist/__tests__/render-feature-prepared-graphics.regression.integration.test.d.ts.map +1 -0
  354. package/dist/__tests__/render-feature-recover.integration.test.d.ts +2 -0
  355. package/dist/__tests__/render-feature-recover.integration.test.d.ts.map +1 -0
  356. package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts +2 -0
  357. package/dist/__tests__/render-feature-runtime-surface.test-d.d.ts.map +1 -0
  358. package/dist/__tests__/render-schema-consumer.integration.test.d.ts +2 -0
  359. package/dist/__tests__/render-schema-consumer.integration.test.d.ts.map +1 -0
  360. package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts +2 -0
  361. package/dist/__tests__/render-schema-owner-boundary.unit.test.d.ts.map +1 -0
  362. package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts +2 -0
  363. package/dist/__tests__/render-system-cross-world-overlay-queue.test.d.ts.map +1 -0
  364. package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts +2 -0
  365. package/dist/__tests__/render-system-extract-dispatch-ordering.test.d.ts.map +1 -0
  366. package/dist/__tests__/render-system-extract.test.d.ts +2 -0
  367. package/dist/__tests__/render-system-extract.test.d.ts.map +1 -0
  368. package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
  369. package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
  370. package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts +2 -0
  371. package/dist/__tests__/render-system-fold-bucket.unit.test.d.ts.map +1 -0
  372. package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts +2 -0
  373. package/dist/__tests__/render-system-fold-fallback.unit.test.d.ts.map +1 -0
  374. package/dist/__tests__/render-system-fold-material.unit.test.d.ts +2 -0
  375. package/dist/__tests__/render-system-fold-material.unit.test.d.ts.map +1 -0
  376. package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts +2 -0
  377. package/dist/__tests__/render-system-fold-metrics.unit.test.d.ts.map +1 -0
  378. package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts +2 -0
  379. package/dist/__tests__/render-system-fold-modegate.unit.test.d.ts.map +1 -0
  380. package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts +2 -0
  381. package/dist/__tests__/render-system-fold-scene-instances.unit.test.d.ts.map +1 -0
  382. package/dist/__tests__/render-system-fold.dawn.test.d.ts +2 -0
  383. package/dist/__tests__/render-system-fold.dawn.test.d.ts.map +1 -0
  384. package/dist/__tests__/render-system-mega.test.d.ts +2 -0
  385. package/dist/__tests__/render-system-mega.test.d.ts.map +1 -0
  386. package/dist/__tests__/render-system-owner-split-contract.test.d.ts +2 -0
  387. package/dist/__tests__/render-system-owner-split-contract.test.d.ts.map +1 -0
  388. package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts +2 -0
  389. package/dist/__tests__/render-system-record-multi-material-textureview.test.d.ts.map +1 -0
  390. package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts +2 -0
  391. package/dist/__tests__/render-system-record-per-submesh-transparency.test.d.ts.map +1 -0
  392. package/dist/__tests__/render-system-record.test.d.ts +2 -0
  393. package/dist/__tests__/render-system-record.test.d.ts.map +1 -0
  394. package/dist/__tests__/render-system-record.unit.test.d.ts +2 -0
  395. package/dist/__tests__/render-system-record.unit.test.d.ts.map +1 -0
  396. package/dist/__tests__/render-system-skin-bg.unit.test.d.ts +2 -0
  397. package/dist/__tests__/render-system-skin-bg.unit.test.d.ts.map +1 -0
  398. package/dist/__tests__/renderer-consumer.test-d.d.ts +2 -0
  399. package/dist/__tests__/renderer-consumer.test-d.d.ts.map +1 -0
  400. package/dist/__tests__/renderer-health.unit.test.d.ts +2 -0
  401. package/dist/__tests__/renderer-health.unit.test.d.ts.map +1 -0
  402. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts +2 -0
  403. package/dist/__tests__/renderer-lifecycle.integration.test.d.ts.map +1 -0
  404. package/dist/__tests__/renderer-recover.unit.test.d.ts +2 -0
  405. package/dist/__tests__/renderer-recover.unit.test.d.ts.map +1 -0
  406. package/dist/__tests__/renderer-result.test-d.d.ts +2 -0
  407. package/dist/__tests__/renderer-result.test-d.d.ts.map +1 -0
  408. package/dist/__tests__/renderer-surface.unit.test.d.ts +2 -0
  409. package/dist/__tests__/renderer-surface.unit.test.d.ts.map +1 -0
  410. package/dist/__tests__/renderer-test-utils.d.ts +10 -0
  411. package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
  412. package/dist/__tests__/renderer.test-d.d.ts +2 -0
  413. package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
  414. package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
  415. package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
  416. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
  417. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
  418. package/dist/__tests__/resolve-depth-only-view.test.d.ts +2 -0
  419. package/dist/__tests__/resolve-depth-only-view.test.d.ts.map +1 -0
  420. package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
  421. package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
  422. package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
  423. package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
  424. package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
  425. package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
  426. package/dist/__tests__/resolveName.test.d.ts +2 -0
  427. package/dist/__tests__/resolveName.test.d.ts.map +1 -0
  428. package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts +2 -0
  429. package/dist/__tests__/rhi-null-command-flow.unit.test.d.ts.map +1 -0
  430. package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts +2 -0
  431. package/dist/__tests__/rhi-null-noop-behavior.unit.test.d.ts.map +1 -0
  432. package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts +2 -0
  433. package/dist/__tests__/rhi-null-renderer-lifecycle.unit.test.d.ts.map +1 -0
  434. package/dist/__tests__/roots-to-scene-asset.test.d.ts +2 -0
  435. package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -0
  436. package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
  437. package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
  438. package/dist/__tests__/runtime-authority-scan.unit.test.d.ts +2 -0
  439. package/dist/__tests__/runtime-authority-scan.unit.test.d.ts.map +1 -0
  440. package/dist/__tests__/runtime-domain-residue.unit.test.d.ts +2 -0
  441. package/dist/__tests__/runtime-domain-residue.unit.test.d.ts.map +1 -0
  442. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
  443. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
  444. package/dist/__tests__/scene-equirect-roundtrip.test.d.ts +2 -0
  445. package/dist/__tests__/scene-equirect-roundtrip.test.d.ts.map +1 -0
  446. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
  447. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
  448. package/dist/__tests__/scene-instance-bridge.integration.test.d.ts +2 -0
  449. package/dist/__tests__/scene-instance-bridge.integration.test.d.ts.map +1 -0
  450. package/dist/__tests__/scene-instance-component.test.d.ts +2 -0
  451. package/dist/__tests__/scene-instance-component.test.d.ts.map +1 -0
  452. package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts +2 -0
  453. package/dist/__tests__/scene-instantiate-cycle-runtime.test.d.ts.map +1 -0
  454. package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
  455. package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
  456. package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
  457. package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
  458. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
  459. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
  460. package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
  461. package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
  462. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
  463. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
  464. package/dist/__tests__/serialize-scene-asset.test.d.ts +2 -0
  465. package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -0
  466. package/dist/__tests__/shadow-caster-empty-schema.test.d.ts +2 -0
  467. package/dist/__tests__/shadow-caster-empty-schema.test.d.ts.map +1 -0
  468. package/dist/__tests__/shadow-csm-atlas.test.d.ts +2 -0
  469. package/dist/__tests__/shadow-csm-atlas.test.d.ts.map +1 -0
  470. package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts +2 -0
  471. package/dist/__tests__/shadow-csm-blend.dawn.test.d.ts.map +1 -0
  472. package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts +2 -0
  473. package/dist/__tests__/shadow-csm-cascade-loadop.test.d.ts.map +1 -0
  474. package/dist/__tests__/shadow-csm-component.test.d.ts +2 -0
  475. package/dist/__tests__/shadow-csm-component.test.d.ts.map +1 -0
  476. package/dist/__tests__/shadow-csm-extract.test.d.ts +2 -0
  477. package/dist/__tests__/shadow-csm-extract.test.d.ts.map +1 -0
  478. package/dist/__tests__/shadow-csm-orthoz.test.d.ts +2 -0
  479. package/dist/__tests__/shadow-csm-orthoz.test.d.ts.map +1 -0
  480. package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts +2 -0
  481. package/dist/__tests__/shadow-csm-runtime-vary.dawn.test.d.ts.map +1 -0
  482. package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts +2 -0
  483. package/dist/__tests__/shadow-csm-shader.dawn.test.d.ts.map +1 -0
  484. package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts +2 -0
  485. package/dist/__tests__/shadow-csm-tile-consistency.test.d.ts.map +1 -0
  486. package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts +2 -0
  487. package/dist/__tests__/shadow-csm-ubo.dawn.test.d.ts.map +1 -0
  488. package/dist/__tests__/shadow-csm-ubo.test.d.ts +2 -0
  489. package/dist/__tests__/shadow-csm-ubo.test.d.ts.map +1 -0
  490. package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts +2 -0
  491. package/dist/__tests__/shadow-csm-viewport.browser.test.d.ts.map +1 -0
  492. package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts +2 -0
  493. package/dist/__tests__/shadow-fields-observable.dawn.test.d.ts.map +1 -0
  494. package/dist/__tests__/shadow-m1.dawn.test.d.ts +2 -0
  495. package/dist/__tests__/shadow-m1.dawn.test.d.ts.map +1 -0
  496. package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts +2 -0
  497. package/dist/__tests__/shadow-mesh-ssbo-order.test.d.ts.map +1 -0
  498. package/dist/__tests__/skin-error-exhaustive.test-d.d.ts +11 -0
  499. package/dist/__tests__/skin-error-exhaustive.test-d.d.ts.map +1 -0
  500. package/dist/__tests__/skin-errors.unit.test.d.ts +2 -0
  501. package/dist/__tests__/skin-errors.unit.test.d.ts.map +1 -0
  502. package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts +2 -0
  503. package/dist/__tests__/skin-extract-getarrayview-count.unit.test.d.ts.map +1 -0
  504. package/dist/__tests__/skin-parented-double-transform.test.d.ts +14 -0
  505. package/dist/__tests__/skin-parented-double-transform.test.d.ts.map +1 -0
  506. package/dist/__tests__/skylight-lazy-projection.test.d.ts +2 -0
  507. package/dist/__tests__/skylight-lazy-projection.test.d.ts.map +1 -0
  508. package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts +2 -0
  509. package/dist/__tests__/sparse-tag-scene-roundtrip.test.d.ts.map +1 -0
  510. package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts +2 -0
  511. package/dist/__tests__/sprite-cullmode-flip.dawn.test.d.ts.map +1 -0
  512. package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts +2 -0
  513. package/dist/__tests__/sprite-lit-bgl-byte-identical.test.d.ts.map +1 -0
  514. package/dist/__tests__/sprite-lit-extract-branch.test.d.ts +2 -0
  515. package/dist/__tests__/sprite-lit-extract-branch.test.d.ts.map +1 -0
  516. package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts +2 -0
  517. package/dist/__tests__/sprite-lit-pipeline-cache-key.test.d.ts.map +1 -0
  518. package/dist/__tests__/sprite-param-values.test-d.d.ts +2 -0
  519. package/dist/__tests__/sprite-param-values.test-d.d.ts.map +1 -0
  520. package/dist/__tests__/ssao-bgl.test.d.ts +2 -0
  521. package/dist/__tests__/ssao-bgl.test.d.ts.map +1 -0
  522. package/dist/__tests__/ssao-buffers.test.d.ts +2 -0
  523. package/dist/__tests__/ssao-buffers.test.d.ts.map +1 -0
  524. package/dist/__tests__/ssao-data.test.d.ts +2 -0
  525. package/dist/__tests__/ssao-data.test.d.ts.map +1 -0
  526. package/dist/__tests__/ssao-errors.test.d.ts +2 -0
  527. package/dist/__tests__/ssao-errors.test.d.ts.map +1 -0
  528. package/dist/__tests__/ssao-manifest.test.d.ts +2 -0
  529. package/dist/__tests__/ssao-manifest.test.d.ts.map +1 -0
  530. package/dist/__tests__/ssao-passes.test.d.ts +2 -0
  531. package/dist/__tests__/ssao-passes.test.d.ts.map +1 -0
  532. package/dist/__tests__/ssao-pipelines.test.d.ts +2 -0
  533. package/dist/__tests__/ssao-pipelines.test.d.ts.map +1 -0
  534. package/dist/__tests__/ssao-uniform-layout.test.d.ts +2 -0
  535. package/dist/__tests__/ssao-uniform-layout.test.d.ts.map +1 -0
  536. package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
  537. package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
  538. package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts +2 -0
  539. package/dist/__tests__/stencil-outline-pixel.dawn.test.d.ts.map +1 -0
  540. package/dist/__tests__/swap-chain-format.unit.test.d.ts +2 -0
  541. package/dist/__tests__/swap-chain-format.unit.test.d.ts.map +1 -0
  542. package/dist/__tests__/systems.unit.test.d.ts +2 -0
  543. package/dist/__tests__/systems.unit.test.d.ts.map +1 -0
  544. package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
  545. package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
  546. package/dist/__tests__/text.unit.test.d.ts +2 -0
  547. package/dist/__tests__/text.unit.test.d.ts.map +1 -0
  548. package/dist/__tests__/tilemap-childed-despawn.test.d.ts +2 -0
  549. package/dist/__tests__/tilemap-childed-despawn.test.d.ts.map +1 -0
  550. package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts +2 -0
  551. package/dist/__tests__/tilemap-chunk-extract.overhang-bounds.test.d.ts.map +1 -0
  552. package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts +2 -0
  553. package/dist/__tests__/tilemap-chunk-extract.propagate-order.test.d.ts.map +1 -0
  554. package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts +2 -0
  555. package/dist/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.d.ts.map +1 -0
  556. package/dist/__tests__/tilemap-chunk-extract.test.d.ts +2 -0
  557. package/dist/__tests__/tilemap-chunk-extract.test.d.ts.map +1 -0
  558. package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts +2 -0
  559. package/dist/__tests__/tilemap-chunk-extract.unit.test.d.ts.map +1 -0
  560. package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts +2 -0
  561. package/dist/__tests__/tilemap-chunk-y-sort-bench.unit.test.d.ts.map +1 -0
  562. package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts +2 -0
  563. package/dist/__tests__/tilemap-dirty-rebuild.test.d.ts.map +1 -0
  564. package/dist/__tests__/tilemap-material-cache.test.d.ts +2 -0
  565. package/dist/__tests__/tilemap-material-cache.test.d.ts.map +1 -0
  566. package/dist/__tests__/tilemap-multi-atlas.test.d.ts +2 -0
  567. package/dist/__tests__/tilemap-multi-atlas.test.d.ts.map +1 -0
  568. package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts +2 -0
  569. package/dist/__tests__/tilemap-owner-boundary.unit.test.d.ts.map +1 -0
  570. package/dist/__tests__/tilemap-region-pack.test.d.ts +2 -0
  571. package/dist/__tests__/tilemap-region-pack.test.d.ts.map +1 -0
  572. package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts +2 -0
  573. package/dist/__tests__/tilemap-spawn-flip-pivot.test.d.ts.map +1 -0
  574. package/dist/__tests__/tilemap-uv-inset.test.d.ts +2 -0
  575. package/dist/__tests__/tilemap-uv-inset.test.d.ts.map +1 -0
  576. package/dist/__tests__/tilemap-validate.test.d.ts +2 -0
  577. package/dist/__tests__/tilemap-validate.test.d.ts.map +1 -0
  578. package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
  579. package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
  580. package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
  581. package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
  582. package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts +2 -0
  583. package/dist/__tests__/transform-hierarchy-pixel-diff.dawn.test.d.ts.map +1 -0
  584. package/dist/__tests__/transient-fields-collect.test.d.ts +2 -0
  585. package/dist/__tests__/transient-fields-collect.test.d.ts.map +1 -0
  586. package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
  587. package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
  588. package/dist/__tests__/transitional-authoring.integration.test.d.ts +2 -0
  589. package/dist/__tests__/transitional-authoring.integration.test.d.ts.map +1 -0
  590. package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts +2 -0
  591. package/dist/__tests__/transparent-sort-tilemap-sprite-interleave.test.d.ts.map +1 -0
  592. package/dist/__tests__/variant-selection.unit.test.d.ts +2 -0
  593. package/dist/__tests__/variant-selection.unit.test.d.ts.map +1 -0
  594. package/dist/__tests__/vertex-attribute-layout.test.d.ts +2 -0
  595. package/dist/__tests__/vertex-attribute-layout.test.d.ts.map +1 -0
  596. package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts +2 -0
  597. package/dist/__tests__/video-extract-bindgroup.dawn.test.d.ts.map +1 -0
  598. package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
  599. package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
  600. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
  601. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
  602. package/dist/__tests__/view-ubo-layout.browser.test.d.ts +2 -0
  603. package/dist/__tests__/view-ubo-layout.browser.test.d.ts.map +1 -0
  604. package/dist/__tests__/world-entity-key.test.d.ts +2 -0
  605. package/dist/__tests__/world-entity-key.test.d.ts.map +1 -0
  606. package/dist/__tests__/world-scene-despawn.test.d.ts +2 -0
  607. package/dist/__tests__/world-scene-despawn.test.d.ts.map +1 -0
  608. package/dist/__tests__/world-scene-instantiate.test.d.ts +2 -0
  609. package/dist/__tests__/world-scene-instantiate.test.d.ts.map +1 -0
  610. package/dist/__tests__/world-scene-nested.test.d.ts +2 -0
  611. package/dist/__tests__/world-scene-nested.test.d.ts.map +1 -0
  612. package/dist/__tests__/world-scene-override.test.d.ts +2 -0
  613. package/dist/__tests__/world-scene-override.test.d.ts.map +1 -0
  614. package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts +2 -0
  615. package/dist/__tests__/zero-compression-zero-load.integration.test.d.ts.map +1 -0
  616. package/dist/asset-contributions.d.ts +3 -0
  617. package/dist/asset-contributions.d.ts.map +1 -0
  618. package/dist/backend-selection.d.ts +13 -0
  619. package/dist/backend-selection.d.ts.map +1 -0
  620. package/dist/collect-scene-asset.d.ts +19 -0
  621. package/dist/collect-scene-asset.d.ts.map +1 -0
  622. package/dist/components/__tests__/camera.test-d.d.ts +2 -0
  623. package/dist/components/__tests__/camera.test-d.d.ts.map +1 -0
  624. package/dist/components/__tests__/camera.test.d.ts +2 -0
  625. package/dist/components/__tests__/camera.test.d.ts.map +1 -0
  626. package/dist/components/__tests__/child-of.test.d.ts +2 -0
  627. package/dist/components/__tests__/child-of.test.d.ts.map +1 -0
  628. package/dist/components/__tests__/sprite-animation.test-d.d.ts +2 -0
  629. package/dist/components/__tests__/sprite-animation.test-d.d.ts.map +1 -0
  630. package/dist/components/__tests__/sprite-instances.unit.test.d.ts +2 -0
  631. package/dist/components/__tests__/sprite-instances.unit.test.d.ts.map +1 -0
  632. package/dist/components/__tests__/sprite-region-override.test-d.d.ts +2 -0
  633. package/dist/components/__tests__/sprite-region-override.test-d.d.ts.map +1 -0
  634. package/dist/components/__tests__/tile-layer.test-d.d.ts +2 -0
  635. package/dist/components/__tests__/tile-layer.test-d.d.ts.map +1 -0
  636. package/dist/components/__tests__/tile-layer.unit.test.d.ts +2 -0
  637. package/dist/components/__tests__/tile-layer.unit.test.d.ts.map +1 -0
  638. package/dist/components/__tests__/tilemap.test-d.d.ts +2 -0
  639. package/dist/components/__tests__/tilemap.test-d.d.ts.map +1 -0
  640. package/dist/components/__tests__/transform-vec-schema.test.d.ts +2 -0
  641. package/dist/components/__tests__/transform-vec-schema.test.d.ts.map +1 -0
  642. package/dist/create-renderer-env-classify.d.ts +21 -0
  643. package/dist/create-renderer-env-classify.d.ts.map +1 -0
  644. package/dist/createRenderer.d.ts +15 -0
  645. package/dist/createRenderer.d.ts.map +1 -0
  646. package/dist/dev-import-transport.d.ts +24 -0
  647. package/dist/dev-import-transport.d.ts.map +1 -0
  648. package/dist/errors/environment.d.ts +2 -0
  649. package/dist/errors/environment.d.ts.map +1 -0
  650. package/dist/index.d.ts +218 -0
  651. package/dist/index.d.ts.map +1 -0
  652. package/dist/index.mjs +813 -0
  653. package/dist/index.mjs.map +1 -0
  654. package/dist/renderer-host.d.ts +9 -0
  655. package/dist/renderer-host.d.ts.map +1 -0
  656. package/dist/renderer-host.mjs +62 -0
  657. package/dist/renderer-host.mjs.map +1 -0
  658. package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts +2 -0
  659. package/dist/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.d.ts.map +1 -0
  660. package/dist/scene-instances/index.d.ts +2 -0
  661. package/dist/scene-instances/index.d.ts.map +1 -0
  662. package/dist/scene-utils/mount-override-fold.d.ts +15 -0
  663. package/dist/scene-utils/mount-override-fold.d.ts.map +1 -0
  664. package/dist/sprite-param-values.d.ts +62 -0
  665. package/dist/sprite-param-values.d.ts.map +1 -0
  666. package/dist/systems/__tests__/_xorshift.d.ts +28 -0
  667. package/dist/systems/__tests__/_xorshift.d.ts.map +1 -0
  668. package/dist/systems/__tests__/argsort-in-place.test.d.ts +2 -0
  669. package/dist/systems/__tests__/argsort-in-place.test.d.ts.map +1 -0
  670. package/dist/systems/__tests__/transparent-sort.bench.d.ts +2 -0
  671. package/dist/systems/__tests__/transparent-sort.bench.d.ts.map +1 -0
  672. package/dist/systems/sprite-animation-tick.d.ts +50 -0
  673. package/dist/systems/sprite-animation-tick.d.ts.map +1 -0
  674. package/dist/systems/tonemap.d.ts +27 -0
  675. package/dist/systems/tonemap.d.ts.map +1 -0
  676. package/dist/systems/transparent-sort.d.ts +50 -0
  677. package/dist/systems/transparent-sort.d.ts.map +1 -0
  678. package/dist/tilemap-register-validate.d.ts +21 -0
  679. package/dist/tilemap-register-validate.d.ts.map +1 -0
  680. package/package.json +101 -0
  681. package/src/__tests__/active-camera.unit.test.ts +203 -0
  682. package/src/__tests__/animation-graph-add.unit.test.ts +67 -0
  683. package/src/__tests__/animation-graph-asset-union.test-d.ts +83 -0
  684. package/src/__tests__/animation-graph-blend.unit.test.ts +66 -0
  685. package/src/__tests__/animation-graph-build.unit.test.ts +100 -0
  686. package/src/__tests__/animation-graph-clip-missing.unit.test.ts +62 -0
  687. package/src/__tests__/animation-graph-clip.unit.test.ts +77 -0
  688. package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
  689. package/src/__tests__/animation-graph-default-path.integration.test.ts +65 -0
  690. package/src/__tests__/animation-graph-describe.unit.test.ts +68 -0
  691. package/src/__tests__/animation-graph-errors.unit.test.ts +75 -0
  692. package/src/__tests__/animation-graph-nesting.unit.test.ts +84 -0
  693. package/src/__tests__/animation-graph-orthogonal-weight.unit.test.ts +98 -0
  694. package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
  695. package/src/__tests__/animation-graph-slot-fill.unit.test.ts +95 -0
  696. package/src/__tests__/animation-nslot.unit.test.ts +63 -0
  697. package/src/__tests__/animation-slot-length-guard.unit.test.ts +81 -0
  698. package/src/__tests__/append-injection.test.ts +105 -0
  699. package/src/__tests__/asi-world-baseline-export.unit.test.ts +173 -0
  700. package/src/__tests__/asi-world-ci-config.unit.test.ts +186 -0
  701. package/src/__tests__/asi-world-smoke.unit.test.ts +192 -0
  702. package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
  703. package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
  704. package/src/__tests__/asset-registry-guid-reverse.test.ts +608 -0
  705. package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
  706. package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
  707. package/src/__tests__/asset-registry-mounts.test.ts +806 -0
  708. package/src/__tests__/asset-registry-scene.test-d.ts +49 -0
  709. package/src/__tests__/asset-registry.browser.test.ts +81 -0
  710. package/src/__tests__/asset-registry.dawn.test.ts +94 -0
  711. package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
  712. package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
  713. package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
  714. package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
  715. package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
  716. package/src/__tests__/asset-registry.unit.test.ts +1030 -0
  717. package/src/__tests__/asset.unit.test.ts +7107 -0
  718. package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
  719. package/src/__tests__/backend-selection.integration.test.ts +11 -0
  720. package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
  721. package/src/__tests__/bind-group-cache-keying.test.ts +295 -0
  722. package/src/__tests__/block-upload-math.unit.test.ts +192 -0
  723. package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
  724. package/src/__tests__/builtin-shader-register-e2e.test.ts +151 -0
  725. package/src/__tests__/cache-false-eviction.test.ts +127 -0
  726. package/src/__tests__/cache-isolation-matrix.test.ts +183 -0
  727. package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +75 -0
  728. package/src/__tests__/clamp-to-last.e2e.browser.test.ts +193 -0
  729. package/src/__tests__/clamp-to-last.e2e.dawn.test.ts +325 -0
  730. package/src/__tests__/collect-scene-asset.test.ts +873 -0
  731. package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
  732. package/src/__tests__/collect-subtree.unit.test.ts +75 -0
  733. package/src/__tests__/collect-transient-children-absent.test.ts +168 -0
  734. package/src/__tests__/collect-transient-roundtrip.test.ts +269 -0
  735. package/src/__tests__/collect-transient-skip.test.ts +176 -0
  736. package/src/__tests__/components.test-d.ts +231 -0
  737. package/src/__tests__/components.unit.test.ts +2666 -0
  738. package/src/__tests__/composite-skybox-cross-world.browser.test.ts +410 -0
  739. package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
  740. package/src/__tests__/create-renderer-assembly.integration.test.ts +55 -0
  741. package/src/__tests__/createRenderer-dispose.test.ts +49 -0
  742. package/src/__tests__/createRenderer-requiredFeatures.unit.test.ts +134 -0
  743. package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +54 -0
  744. package/src/__tests__/createRenderer.unit.test.ts +231 -0
  745. package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +357 -0
  746. package/src/__tests__/dawn/ibl-compose.dawn.test.ts +151 -0
  747. package/src/__tests__/dawn/ibl-modules-compose.dawn.test.ts +223 -0
  748. package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +250 -0
  749. package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +631 -0
  750. package/src/__tests__/dawn/instances-shadow.dawn.test.ts +454 -0
  751. package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +312 -0
  752. package/src/__tests__/dawn/material-alpha.dawn.test.ts +296 -0
  753. package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +79 -0
  754. package/src/__tests__/dawn/mesh-ssbo-normal-matrix.dawn.test.ts +106 -0
  755. package/src/__tests__/dawn/mesh-update-dawn.test.ts +250 -0
  756. package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +124 -0
  757. package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +555 -0
  758. package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +235 -0
  759. package/src/__tests__/dawn/tonemap.dawn.test.ts +107 -0
  760. package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
  761. package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +289 -0
  762. package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +209 -0
  763. package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +119 -0
  764. package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +98 -0
  765. package/src/__tests__/demo-sortscope-migration.unit.test.ts +115 -0
  766. package/src/__tests__/derive-bgl-integration.test.ts +388 -0
  767. package/src/__tests__/derive-render-data-skin.unit.test.ts +90 -0
  768. package/src/__tests__/draw-published.ts +17 -0
  769. package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
  770. package/src/__tests__/environment-error-exhaustive.test-d.ts +28 -0
  771. package/src/__tests__/equirect-bc6h.integration.test.ts +158 -0
  772. package/src/__tests__/error-exhaustive.test.ts +220 -0
  773. package/src/__tests__/errors.unit.test.ts +1227 -0
  774. package/src/__tests__/extract-frames-graceful-degradation.test.ts +294 -0
  775. package/src/__tests__/extract-frames-merge.test.ts +656 -0
  776. package/src/__tests__/extract-frames-reset.test.ts +158 -0
  777. package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +81 -0
  778. package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
  779. package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
  780. package/src/__tests__/four-path-compression.integration.test.ts +395 -0
  781. package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +28 -0
  782. package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
  783. package/src/__tests__/fullscreen-post-bgl-depth.test.ts +133 -0
  784. package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +84 -0
  785. package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +336 -0
  786. package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +109 -0
  787. package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +303 -0
  788. package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +369 -0
  789. package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +258 -0
  790. package/src/__tests__/geometry.unit.test.ts +2631 -0
  791. package/src/__tests__/glyph-tilemap-worldid.test.ts +146 -0
  792. package/src/__tests__/gpu-resource-cow-survivor.test.ts +390 -0
  793. package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
  794. package/src/__tests__/handle-migration.test.ts +136 -0
  795. package/src/__tests__/hello-tilemap-smoke-upgrade.unit.test.ts +147 -0
  796. package/src/__tests__/helpers/mock-shader-registry.ts +139 -0
  797. package/src/__tests__/helpers/register-runtime-components.ts +71 -0
  798. package/src/__tests__/helpers/register-scene-components.ts +10 -0
  799. package/src/__tests__/helpers/tilemap-assets.ts +29 -0
  800. package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
  801. package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
  802. package/src/__tests__/inspect-name.test.ts +139 -0
  803. package/src/__tests__/instances.test-d.ts +61 -0
  804. package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
  805. package/src/__tests__/light-attenuation-formula.test.ts +171 -0
  806. package/src/__tests__/light-casters-9-light.browser.test.ts +877 -0
  807. package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +160 -0
  808. package/src/__tests__/light-snapshot.test-d.ts +84 -0
  809. package/src/__tests__/lights-vec-negative.unit.test.ts +52 -0
  810. package/src/__tests__/lights.unit.test.ts +2456 -0
  811. package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
  812. package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
  813. package/src/__tests__/loader-extract-graceful.test.ts +146 -0
  814. package/src/__tests__/loader-name-survival.test.ts +213 -0
  815. package/src/__tests__/m3-vec-negative.unit.test.ts +46 -0
  816. package/src/__tests__/m5-browser-dawn-sweep.integration.test.ts +8 -0
  817. package/src/__tests__/material-texture-uv-scale.unit.test.ts +119 -0
  818. package/src/__tests__/materials.unit.test.ts +254 -0
  819. package/src/__tests__/mesh-bin-contract.test.ts +28 -0
  820. package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
  821. package/src/__tests__/mesh-bin.test.ts +38 -0
  822. package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
  823. package/src/__tests__/mesh-ssbo-grow.unit.test.ts +244 -0
  824. package/src/__tests__/mip-gate.unit.test.ts +79 -0
  825. package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +367 -0
  826. package/src/__tests__/multi-uv-8set.e2e.dawn.test.ts +296 -0
  827. package/src/__tests__/name.unit.test.ts +123 -0
  828. package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
  829. package/src/__tests__/node-shims.d.ts +31 -0
  830. package/src/__tests__/package-promotion.test.ts +88 -0
  831. package/src/__tests__/package-rename.test.ts +103 -0
  832. package/src/__tests__/pass-selector.unit.test.ts +102 -0
  833. package/src/__tests__/pbr-pipeline.unit.test.ts +200 -0
  834. package/src/__tests__/pipeline-builder-msaa.unit.test.ts +221 -0
  835. package/src/__tests__/pipeline-cache-keying.unit.test.ts +313 -0
  836. package/src/__tests__/pipeline-spec.test.ts +900 -0
  837. package/src/__tests__/pipeline.unit.test.ts +5435 -0
  838. package/src/__tests__/point-light-shadow.browser.test.ts +278 -0
  839. package/src/__tests__/point-light-shadow.dawn.test.ts +813 -0
  840. package/src/__tests__/point-light-shadow.unit.test.ts +675 -0
  841. package/src/__tests__/post-process-error-codes.unit.test.ts +161 -0
  842. package/src/__tests__/post-process-params-component.unit.test.ts +153 -0
  843. package/src/__tests__/post-process-params-extract.unit.test.ts +97 -0
  844. package/src/__tests__/postprocess-camera-consistency.test.ts +375 -0
  845. package/src/__tests__/profiler-assembly.integration.test.ts +74 -0
  846. package/src/__tests__/propagate-transforms.dawn.test.ts +254 -0
  847. package/src/__tests__/record-worldid-isolation.test.ts +225 -0
  848. package/src/__tests__/recover-error-exhaustive.test-d.ts +35 -0
  849. package/src/__tests__/render-error-exhaustive.test-d.ts +291 -0
  850. package/src/__tests__/render-feature-assembly.test-d.ts +39 -0
  851. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +126 -0
  852. package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +88 -0
  853. package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +115 -0
  854. package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
  855. package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +56 -0
  856. package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +104 -0
  857. package/src/__tests__/render-feature-recover.integration.test.ts +102 -0
  858. package/src/__tests__/render-feature-runtime-surface.test-d.ts +42 -0
  859. package/src/__tests__/render-schema-consumer.integration.test.ts +32 -0
  860. package/src/__tests__/render-schema-owner-boundary.unit.test.ts +22 -0
  861. package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +172 -0
  862. package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +307 -0
  863. package/src/__tests__/render-system-extract.test.ts +1384 -0
  864. package/src/__tests__/render-system-extract.unit.test.ts +360 -0
  865. package/src/__tests__/render-system-fold-bucket.unit.test.ts +286 -0
  866. package/src/__tests__/render-system-fold-fallback.unit.test.ts +151 -0
  867. package/src/__tests__/render-system-fold-material.unit.test.ts +143 -0
  868. package/src/__tests__/render-system-fold-metrics.unit.test.ts +170 -0
  869. package/src/__tests__/render-system-fold-modegate.unit.test.ts +166 -0
  870. package/src/__tests__/render-system-fold-scene-instances.unit.test.ts +51 -0
  871. package/src/__tests__/render-system-fold.dawn.test.ts +308 -0
  872. package/src/__tests__/render-system-mega.test.ts +1680 -0
  873. package/src/__tests__/render-system-owner-split-contract.test.ts +178 -0
  874. package/src/__tests__/render-system-record-multi-material-textureview.test.ts +698 -0
  875. package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +458 -0
  876. package/src/__tests__/render-system-record.test.ts +1668 -0
  877. package/src/__tests__/render-system-record.unit.test.ts +269 -0
  878. package/src/__tests__/render-system-skin-bg.unit.test.ts +143 -0
  879. package/src/__tests__/renderer-consumer.test-d.ts +18 -0
  880. package/src/__tests__/renderer-health.unit.test.ts +45 -0
  881. package/src/__tests__/renderer-lifecycle.integration.test.ts +42 -0
  882. package/src/__tests__/renderer-recover.unit.test.ts +55 -0
  883. package/src/__tests__/renderer-result.test-d.ts +36 -0
  884. package/src/__tests__/renderer-surface.unit.test.ts +414 -0
  885. package/src/__tests__/renderer-test-utils.ts +56 -0
  886. package/src/__tests__/renderer.test-d.ts +61 -0
  887. package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
  888. package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
  889. package/src/__tests__/resolve-depth-only-view.test.ts +173 -0
  890. package/src/__tests__/resolveName-fallback.test.ts +64 -0
  891. package/src/__tests__/resolveName-null-package.test.ts +38 -0
  892. package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
  893. package/src/__tests__/resolveName.test.ts +64 -0
  894. package/src/__tests__/rhi-null-command-flow.unit.test.ts +69 -0
  895. package/src/__tests__/rhi-null-noop-behavior.unit.test.ts +196 -0
  896. package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +54 -0
  897. package/src/__tests__/roots-to-scene-asset.test.ts +711 -0
  898. package/src/__tests__/roundtrip-primitive.test.ts +351 -0
  899. package/src/__tests__/runtime-authority-scan.unit.test.ts +19 -0
  900. package/src/__tests__/runtime-domain-residue.unit.test.ts +13 -0
  901. package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
  902. package/src/__tests__/scene-equirect-roundtrip.test.ts +120 -0
  903. package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
  904. package/src/__tests__/scene-instance-bridge.integration.test.ts +8 -0
  905. package/src/__tests__/scene-instance-component.test.ts +45 -0
  906. package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +66 -0
  907. package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
  908. package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
  909. package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
  910. package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
  911. package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
  912. package/src/__tests__/serialize-scene-asset.test.ts +533 -0
  913. package/src/__tests__/shadow-caster-empty-schema.test.ts +83 -0
  914. package/src/__tests__/shadow-csm-atlas.test.ts +178 -0
  915. package/src/__tests__/shadow-csm-blend.dawn.test.ts +230 -0
  916. package/src/__tests__/shadow-csm-cascade-loadop.test.ts +354 -0
  917. package/src/__tests__/shadow-csm-component.test.ts +284 -0
  918. package/src/__tests__/shadow-csm-extract.test.ts +236 -0
  919. package/src/__tests__/shadow-csm-orthoz.test.ts +137 -0
  920. package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +203 -0
  921. package/src/__tests__/shadow-csm-shader.dawn.test.ts +358 -0
  922. package/src/__tests__/shadow-csm-tile-consistency.test.ts +425 -0
  923. package/src/__tests__/shadow-csm-ubo.dawn.test.ts +252 -0
  924. package/src/__tests__/shadow-csm-ubo.test.ts +278 -0
  925. package/src/__tests__/shadow-csm-viewport.browser.test.ts +85 -0
  926. package/src/__tests__/shadow-fields-observable.dawn.test.ts +626 -0
  927. package/src/__tests__/shadow-m1.dawn.test.ts +104 -0
  928. package/src/__tests__/shadow-mesh-ssbo-order.test.ts +48 -0
  929. package/src/__tests__/skin-error-exhaustive.test-d.ts +74 -0
  930. package/src/__tests__/skin-errors.unit.test.ts +10 -0
  931. package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +25 -0
  932. package/src/__tests__/skin-parented-double-transform.test.ts +268 -0
  933. package/src/__tests__/skylight-lazy-projection.test.ts +380 -0
  934. package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +43 -0
  935. package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +453 -0
  936. package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +142 -0
  937. package/src/__tests__/sprite-lit-extract-branch.test.ts +117 -0
  938. package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +123 -0
  939. package/src/__tests__/sprite-param-values.test-d.ts +104 -0
  940. package/src/__tests__/ssao-bgl.test.ts +354 -0
  941. package/src/__tests__/ssao-buffers.test.ts +211 -0
  942. package/src/__tests__/ssao-data.test.ts +121 -0
  943. package/src/__tests__/ssao-errors.test.ts +162 -0
  944. package/src/__tests__/ssao-manifest.test.ts +109 -0
  945. package/src/__tests__/ssao-passes.test.ts +905 -0
  946. package/src/__tests__/ssao-pipelines.test.ts +275 -0
  947. package/src/__tests__/ssao-uniform-layout.test.ts +180 -0
  948. package/src/__tests__/static-rig.integration.test.ts +9 -0
  949. package/src/__tests__/stencil-outline-pixel.dawn.test.ts +303 -0
  950. package/src/__tests__/swap-chain-format.unit.test.ts +115 -0
  951. package/src/__tests__/systems.unit.test.ts +9167 -0
  952. package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
  953. package/src/__tests__/text.unit.test.ts +489 -0
  954. package/src/__tests__/tilemap-childed-despawn.test.ts +462 -0
  955. package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +310 -0
  956. package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +81 -0
  957. package/src/__tests__/tilemap-chunk-extract.terrain-rewrite.unit.test.ts +424 -0
  958. package/src/__tests__/tilemap-chunk-extract.test.ts +232 -0
  959. package/src/__tests__/tilemap-chunk-extract.unit.test.ts +383 -0
  960. package/src/__tests__/tilemap-chunk-y-sort-bench.unit.test.ts +109 -0
  961. package/src/__tests__/tilemap-dirty-rebuild.test.ts +296 -0
  962. package/src/__tests__/tilemap-material-cache.test.ts +132 -0
  963. package/src/__tests__/tilemap-multi-atlas.test.ts +217 -0
  964. package/src/__tests__/tilemap-owner-boundary.unit.test.ts +66 -0
  965. package/src/__tests__/tilemap-region-pack.test.ts +149 -0
  966. package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +270 -0
  967. package/src/__tests__/tilemap-uv-inset.test.ts +201 -0
  968. package/src/__tests__/tilemap-validate.test.ts +201 -0
  969. package/src/__tests__/tileset-asset-validate.test.ts +638 -0
  970. package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
  971. package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +282 -0
  972. package/src/__tests__/transient-fields-collect.test.ts +210 -0
  973. package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
  974. package/src/__tests__/transitional-authoring.integration.test.ts +7 -0
  975. package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +227 -0
  976. package/src/__tests__/variant-selection.unit.test.ts +21 -0
  977. package/src/__tests__/vertex-attribute-layout.test.ts +324 -0
  978. package/src/__tests__/video-extract-bindgroup.dawn.test.ts +403 -0
  979. package/src/__tests__/video-loader-consumption.test.ts +86 -0
  980. package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
  981. package/src/__tests__/view-ubo-layout.browser.test.ts +161 -0
  982. package/src/__tests__/world-entity-key.test.ts +92 -0
  983. package/src/__tests__/world-scene-despawn.test.ts +132 -0
  984. package/src/__tests__/world-scene-instantiate.test.ts +194 -0
  985. package/src/__tests__/world-scene-nested.test.ts +230 -0
  986. package/src/__tests__/world-scene-override.test.ts +199 -0
  987. package/src/__tests__/zero-compression-zero-load.integration.test.ts +107 -0
  988. package/src/asset-contributions.ts +48 -0
  989. package/src/backend-selection.ts +69 -0
  990. package/src/collect-scene-asset.ts +701 -0
  991. package/src/components/__tests__/camera.test-d.ts +57 -0
  992. package/src/components/__tests__/camera.test.ts +95 -0
  993. package/src/components/__tests__/child-of.test.ts +35 -0
  994. package/src/components/__tests__/sprite-animation.test-d.ts +160 -0
  995. package/src/components/__tests__/sprite-instances.unit.test.ts +108 -0
  996. package/src/components/__tests__/sprite-region-override.test-d.ts +101 -0
  997. package/src/components/__tests__/tile-layer.test-d.ts +33 -0
  998. package/src/components/__tests__/tile-layer.unit.test.ts +125 -0
  999. package/src/components/__tests__/tilemap.test-d.ts +35 -0
  1000. package/src/components/__tests__/transform-vec-schema.test.ts +121 -0
  1001. package/src/create-renderer-env-classify.ts +110 -0
  1002. package/src/createRenderer.ts +49 -0
  1003. package/src/dev-import-transport.ts +97 -0
  1004. package/src/errors/environment.ts +6 -0
  1005. package/src/index.ts +380 -0
  1006. package/src/renderer-host.ts +33 -0
  1007. package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +183 -0
  1008. package/src/scene-instances/index.ts +4 -0
  1009. package/src/scene-utils/mount-override-fold.ts +213 -0
  1010. package/src/sprite-param-values.ts +61 -0
  1011. package/src/systems/__tests__/_xorshift.ts +83 -0
  1012. package/src/systems/__tests__/argsort-in-place.test.ts +155 -0
  1013. package/src/systems/__tests__/transparent-sort.bench.ts +218 -0
  1014. package/src/systems/sprite-animation-tick.ts +302 -0
  1015. package/src/systems/tonemap.ts +68 -0
  1016. package/src/systems/transparent-sort.ts +434 -0
  1017. package/src/tilemap-register-validate.ts +100 -0
@@ -0,0 +1,1384 @@
1
+ // Consolidated by feat-20260608-ci-time-cut M5 w13/w14: merges
2
+ // - render-system-extract.test.ts
3
+ // - render-system-extract-material-inheritance.test.ts
4
+ // - render-system-extract-sprite-slices.test.ts
5
+ // - render-system-clear-camera.test.ts
6
+ // Each original file body sits in its own block-scope so helper names
7
+ // cannot collide; describe() inside still registers globally with vitest.
8
+
9
+ import { AssetRegistry, HANDLE_CUBE, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
10
+ import { World } from '@forgeax/engine-ecs';
11
+ import { mat4, vec3 } from '@forgeax/engine-math';
12
+ import { AssetGuid } from '@forgeax/engine-pack/guid';
13
+ import {
14
+ Camera,
15
+ DirectionalLight,
16
+ MeshFilter,
17
+ MeshRenderer,
18
+ PointLight,
19
+ SpotLight,
20
+ } from '@forgeax/engine-render';
21
+ import { ChildOf, propagateTransforms, Transform } from '@forgeax/engine-scene';
22
+ import { ShaderRegistry, type ShaderRegistryDevice } from '@forgeax/engine-shader';
23
+ import type {
24
+ Handle,
25
+ MaterialAsset,
26
+ MaterialPass,
27
+ MeshAsset,
28
+ TextureAsset,
29
+ } from '@forgeax/engine-types';
30
+ import { srgbChannelToLinear } from '@forgeax/engine-types';
31
+ import { describe, expect, it, vi } from 'vitest';
32
+ import {
33
+ extractFrame,
34
+ extractFrames,
35
+ prepareExtractContext,
36
+ } from '../../../render/src/render-system-extract';
37
+ import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
38
+
39
+ // ─── from render-system-extract.test.ts ───
40
+ {
41
+ // w9 -- render-system-extract consumer migration unit tests (M3, AC-07 / AC-15).
42
+ //
43
+ // Post-migration extract reads the single resolved `Transform.world` mat4
44
+ // (written by propagateTransforms) for every world-space consumer; the legacy
45
+ // GlobalTransform-column-switch + per-snapshot `mat4.compose` are gone.
46
+ //
47
+ // Five consumer classes covered:
48
+ // 1. mesh-walk -> RenderableSnapshot.transform.world is the 16-float
49
+ // column-major world mat4 (parent x child), copied straight from the
50
+ // Transform.world view; no per-snapshot compose.
51
+ // 2. frustum cull -> the cull AABB follows the world mat4 (a child placed
52
+ // off-screen by its parent is culled; in-screen is kept) -- same-source
53
+ // with the rendered world (AC-05 carried forward).
54
+ // 3. camera view -> CameraSnapshot.position is the world-space translation
55
+ // (mat4.getTranslation of Transform.world); a child camera reflects
56
+ // parent x child.
57
+ // 4. light position -> point / spot light position is the world-space
58
+ // translation extracted from Transform.world (mat4.getTranslation).
59
+ // 5. AC-15 zero-materialization -> the mesh-walk reads world through the
60
+ // column-level array view; it does NOT call `world.get` per renderable
61
+ // to materialize a `{}` whole-component object.
62
+ //
63
+ // extractFrame + propagateTransforms are pure CPU functions; no GPU is touched.
64
+
65
+ function identity() {
66
+ return {
67
+ pos: [0, 0, 0],
68
+ quat: [0, 0, 0, 1],
69
+ scale: [1, 1, 1],
70
+ };
71
+ }
72
+
73
+ const cameraData = {
74
+ fov: 1.0,
75
+ aspect: 1.0,
76
+ near: 0.1,
77
+ far: 100.0,
78
+ projection: 0,
79
+ left: -1,
80
+ right: 1,
81
+ bottom: -1,
82
+ top: 1,
83
+ };
84
+
85
+ function perspectiveCameraData() {
86
+ return {
87
+ fov: Math.PI / 4,
88
+ aspect: 1,
89
+ near: 0.1,
90
+ far: 100,
91
+ projection: 0,
92
+ left: -1,
93
+ right: 1,
94
+ bottom: -1,
95
+ top: 1,
96
+ };
97
+ }
98
+
99
+ function spawnCamera(world: World): void {
100
+ world
101
+ .spawn({ component: Transform, data: identity() }, { component: Camera, data: cameraData })
102
+ .unwrap();
103
+ }
104
+
105
+ function registerMesh(world: World): Handle<'MeshAsset', 'shared'> {
106
+ return registerMeshWithAabb(world, new Float32Array([-1, -1, -1, 1, 1, 1]));
107
+ }
108
+
109
+ function registerMeshWithAabb(
110
+ world: World,
111
+ aabb: Float32Array | undefined,
112
+ ): Handle<'MeshAsset', 'shared'> {
113
+ const positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
114
+ const mesh: MeshAsset = {
115
+ kind: 'mesh',
116
+ vertices: new Float32Array([
117
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
118
+ 1, 0, 0, 0, 0,
119
+ ]),
120
+ indices: new Uint16Array([0, 1, 2]),
121
+ attributes: { position: positions },
122
+ submeshes: [
123
+ {
124
+ indexOffset: 0,
125
+ indexCount: 3,
126
+ vertexCount: 36,
127
+ topology: 'triangle-list',
128
+ materialSlot: 0,
129
+ },
130
+ ],
131
+ ...(aabb !== undefined ? { aabb } : {}),
132
+
133
+ materialSlots: [{ slotName: 'Default' }],
134
+ };
135
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', mesh);
136
+ }
137
+
138
+ function registerMaterial(world: World): Handle<'MaterialAsset', 'shared'> {
139
+ return world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
140
+ kind: 'material',
141
+ passes: [
142
+ {
143
+ name: 'Forward',
144
+ program: { module: 'forgeax::default-unlit' },
145
+ renderState: { tags: { LightMode: 'Forward' }, queue: 2000 },
146
+ },
147
+ ],
148
+ values: { baseColor: [1, 1, 1] },
149
+ });
150
+ }
151
+
152
+ describe('render-system-extract consumer migration (w9, AC-07 / AC-15)', () => {
153
+ it('reuses one frame-local material snapshot for repeated shared handles', () => {
154
+ const world = new World();
155
+ spawnCamera(world);
156
+ const assets = new AssetRegistry(makeMockShaderRegistry());
157
+ const mesh = registerMesh(world);
158
+ const material = registerMaterial(world);
159
+
160
+ for (let index = 0; index < 64; index++) {
161
+ world
162
+ .spawn(
163
+ {
164
+ component: Transform,
165
+ data: { ...identity(), pos: [0, 0, -index - 2] },
166
+ },
167
+ { component: MeshFilter, data: { assetHandle: mesh } },
168
+ { component: MeshRenderer, data: { materials: [material] } },
169
+ )
170
+ .unwrap();
171
+ }
172
+
173
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
174
+ expect(frame.renderables).toHaveLength(64);
175
+ const first = frame.renderables[0]?.material;
176
+ expect(first).toBeDefined();
177
+ expect(new Set(frame.renderables.map((renderable) => renderable.material)).size).toBe(1);
178
+ for (const renderable of frame.renderables) expect(renderable.material).toBe(first);
179
+ });
180
+
181
+ it('mesh-walk: RenderableSnapshot.transform.world is the resolved world mat4 (parent x child), zero per-snapshot compose', () => {
182
+ const world = new World();
183
+ world
184
+ .spawn(
185
+ { component: Transform, data: { ...identity(), pos: [12, 3, 5] } },
186
+ { component: Camera, data: cameraData },
187
+ )
188
+ .unwrap();
189
+ const parent = world
190
+ .spawn({ component: Transform, data: { ...identity(), pos: [10, 0, 0] } })
191
+ .unwrap();
192
+ world
193
+ .spawn(
194
+ { component: Transform, data: { ...identity(), pos: [2, 3, 0] } },
195
+ { component: ChildOf, data: { parent } },
196
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
197
+ { component: MeshRenderer, data: {} },
198
+ )
199
+ .unwrap();
200
+
201
+ expect(propagateTransforms(world).ok).toBe(true);
202
+ const frame = extractFrame(world, prepareExtractContext(world));
203
+ expect(frame.renderables.length).toBe(1);
204
+
205
+ const w = frame.renderables[0]?.transform.world;
206
+ expect(w).toBeInstanceOf(Float32Array);
207
+ expect(w?.length).toBe(16);
208
+ // world translation column (col3 = m[12,13,14]) = parent (10,0,0) + child local (2,3,0).
209
+ expect(w?.[12]).toBeCloseTo(12, 5);
210
+ expect(w?.[13]).toBeCloseTo(3, 5);
211
+ expect(w?.[14]).toBeCloseTo(0, 5);
212
+ // The snapshot world must equal the entity's Transform.world column byte-for-byte.
213
+ });
214
+
215
+ it('mesh-walk: flat root world mat4 equals compose(local)', () => {
216
+ const world = new World();
217
+ world
218
+ .spawn(
219
+ { component: Transform, data: { ...identity(), pos: [5, 6, 12] } },
220
+ { component: Camera, data: cameraData },
221
+ )
222
+ .unwrap();
223
+ world
224
+ .spawn(
225
+ { component: Transform, data: { ...identity(), pos: [5, 6, 7], scale: [2, 1, 1] } },
226
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
227
+ { component: MeshRenderer, data: {} },
228
+ )
229
+ .unwrap();
230
+
231
+ expect(propagateTransforms(world).ok).toBe(true);
232
+ const frame = extractFrame(world, prepareExtractContext(world));
233
+ expect(frame.renderables.length).toBe(1);
234
+ const w = frame.renderables[0]?.transform.world as Float32Array;
235
+ const expected = mat4.create();
236
+ mat4.compose(expected, vec3.create(5, 6, 7), [0, 0, 0, 1], vec3.create(2, 1, 1));
237
+ for (let i = 0; i < 16; i++) {
238
+ expect(w[i]).toBeCloseTo((expected as unknown as number[])[i] as number, 5);
239
+ }
240
+ });
241
+
242
+ it('camera view: child camera position reflects world translation (parent x child)', () => {
243
+ const world = new World();
244
+ const rig = world
245
+ .spawn({ component: Transform, data: { ...identity(), pos: [0, 5, 0] } })
246
+ .unwrap();
247
+ world
248
+ .spawn(
249
+ { component: Transform, data: { ...identity(), pos: [1, 0, 2] } },
250
+ { component: ChildOf, data: { parent: rig } },
251
+ { component: Camera, data: cameraData },
252
+ )
253
+ .unwrap();
254
+
255
+ expect(propagateTransforms(world).ok).toBe(true);
256
+ const frame = extractFrame(world, prepareExtractContext(world));
257
+ expect(frame.cameras.length).toBe(1);
258
+ const pos = frame.cameras[0]?.position;
259
+ // rig (0,5,0) x camera local (1,0,2) -> world (1,5,2).
260
+ expect(pos?.[0]).toBeCloseTo(1, 5);
261
+ expect(pos?.[1]).toBeCloseTo(5, 5);
262
+ expect(pos?.[2]).toBeCloseTo(2, 5);
263
+ });
264
+
265
+ it('light position: child point + spot light position reflects world translation', () => {
266
+ const world = new World();
267
+ const rig = world
268
+ .spawn({ component: Transform, data: { ...identity(), pos: [0, 0, 7] } })
269
+ .unwrap();
270
+ world
271
+ .spawn(
272
+ { component: Transform, data: { ...identity(), pos: [3, 0, 0] } },
273
+ { component: ChildOf, data: { parent: rig } },
274
+ { component: PointLight, data: { intensity: 1 } },
275
+ )
276
+ .unwrap();
277
+ const spotRig = world
278
+ .spawn({ component: Transform, data: { ...identity(), pos: [0, 4, 0] } })
279
+ .unwrap();
280
+ world
281
+ .spawn(
282
+ { component: Transform, data: identity() },
283
+ { component: ChildOf, data: { parent: spotRig } },
284
+ {
285
+ component: SpotLight,
286
+ data: { direction: [0, -1, 0], intensity: 1 },
287
+ },
288
+ )
289
+ .unwrap();
290
+
291
+ expect(propagateTransforms(world).ok).toBe(true);
292
+ const frame = extractFrame(world, prepareExtractContext(world));
293
+ expect(frame.lights.point.length).toBe(1);
294
+ expect(frame.lights.point[0]?.position?.[0]).toBeCloseTo(3, 5);
295
+ expect(frame.lights.point[0]?.position?.[2]).toBeCloseTo(7, 5);
296
+ expect(frame.lights.spot.length).toBe(1);
297
+ expect(frame.lights.spot[0]?.position?.[1]).toBeCloseTo(4, 5);
298
+ // D-6 carried forward: spot direction stays from the SpotLight component.
299
+ expect(frame.lights.spot[0]?.direction?.[1]).toBeCloseTo(-1, 5);
300
+ });
301
+
302
+ it('directional light snapshot is unchanged regardless of hierarchy (no Transform dependency)', () => {
303
+ const world = new World();
304
+ world
305
+ .spawn({
306
+ component: DirectionalLight,
307
+ data: {
308
+ direction: [0, -1, 0],
309
+ color: [1, 1, 1],
310
+ intensity: 1,
311
+ },
312
+ })
313
+ .unwrap();
314
+ expect(propagateTransforms(world).ok).toBe(true);
315
+ const frame = extractFrame(world, prepareExtractContext(world));
316
+ expect(frame.lights.directional).toBeDefined();
317
+ expect(frame.lights.directional?.direction?.[1]).toBeCloseTo(-1, 5);
318
+ });
319
+
320
+ it('AC-05: cull AABB follows the world mat4 (parent off-screen -> child culled; in-screen -> kept)', () => {
321
+ {
322
+ const world = new World();
323
+ const mesh = registerMesh(world);
324
+ const mat = registerMaterial(world);
325
+ world
326
+ .spawn(
327
+ { component: Transform, data: { ...identity(), pos: [0, 0, 5] } },
328
+ { component: Camera, data: perspectiveCameraData() },
329
+ )
330
+ .unwrap();
331
+ const parent = world
332
+ .spawn({ component: Transform, data: { ...identity(), pos: [0, 0, 100] } })
333
+ .unwrap();
334
+ world
335
+ .spawn(
336
+ { component: Transform, data: identity() },
337
+ { component: ChildOf, data: { parent } },
338
+ { component: MeshFilter, data: { assetHandle: mesh } },
339
+ { component: MeshRenderer, data: { materials: [mat] } },
340
+ )
341
+ .unwrap();
342
+ expect(propagateTransforms(world).ok).toBe(true);
343
+ const frame = extractFrame(world, prepareExtractContext(world));
344
+ expect(frame.renderables).toHaveLength(0);
345
+ }
346
+ {
347
+ const world = new World();
348
+ const mesh = registerMesh(world);
349
+ const mat = registerMaterial(world);
350
+ world
351
+ .spawn(
352
+ { component: Transform, data: { ...identity(), pos: [0, 0, 5] } },
353
+ { component: Camera, data: perspectiveCameraData() },
354
+ )
355
+ .unwrap();
356
+ const parent = world.spawn({ component: Transform, data: identity() }).unwrap();
357
+ world
358
+ .spawn(
359
+ { component: Transform, data: identity() },
360
+ { component: ChildOf, data: { parent } },
361
+ { component: MeshFilter, data: { assetHandle: mesh } },
362
+ { component: MeshRenderer, data: { materials: [mat] } },
363
+ )
364
+ .unwrap();
365
+ expect(propagateTransforms(world).ok).toBe(true);
366
+ const frame = extractFrame(world, prepareExtractContext(world));
367
+ expect(frame.renderables).toHaveLength(1);
368
+ }
369
+ });
370
+
371
+ it('AC-02: builtin MeshAsset AABB enters the same frustum path as imported meshes', () => {
372
+ const world = new World();
373
+ spawnCamera(world);
374
+ world
375
+ .spawn(
376
+ { component: Transform, data: { ...identity(), pos: [0, 0, 200] } },
377
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
378
+ { component: MeshRenderer, data: {} },
379
+ )
380
+ .unwrap();
381
+
382
+ expect(propagateTransforms(world).ok).toBe(true);
383
+ const frame = extractFrame(world, prepareExtractContext(world));
384
+
385
+ expect(frame.renderables).toHaveLength(0);
386
+ expect(frame.frustumStats).toEqual({ culled: 1, total: 1 });
387
+ });
388
+
389
+ it('cross-world extract keeps frustum culling against the surfaced camera-owner camera', () => {
390
+ const cameraWorld = new World();
391
+ cameraWorld
392
+ .spawn(
393
+ { component: Transform, data: identity() },
394
+ { component: Camera, data: perspectiveCameraData() },
395
+ )
396
+ .unwrap();
397
+
398
+ const sceneWorld = new World();
399
+ sceneWorld
400
+ .spawn(
401
+ { component: Transform, data: { ...identity(), pos: [0, 0, 0] } },
402
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
403
+ { component: MeshRenderer, data: {} },
404
+ )
405
+ .unwrap();
406
+ sceneWorld
407
+ .spawn(
408
+ { component: Transform, data: { ...identity(), pos: [0, 0, 200] } },
409
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
410
+ { component: MeshRenderer, data: {} },
411
+ )
412
+ .unwrap();
413
+
414
+ propagateTransforms(cameraWorld).unwrap();
415
+ propagateTransforms(sceneWorld).unwrap();
416
+
417
+ const frame = extractFrames([cameraWorld, sceneWorld], { cameraOwner: 0, resourceOwner: 1 });
418
+
419
+ expect(frame.renderables).toHaveLength(1);
420
+ expect(frame.frustumStats).toEqual({ culled: 1, total: 2 });
421
+ });
422
+
423
+ it('AC-02: malformed MeshAsset AABBs stay conservative and out of cull statistics', () => {
424
+ const malformedAabbs: Array<Float32Array | undefined> = [
425
+ undefined,
426
+ new Float32Array([
427
+ Number.POSITIVE_INFINITY,
428
+ Number.POSITIVE_INFINITY,
429
+ Number.POSITIVE_INFINITY,
430
+ Number.NEGATIVE_INFINITY,
431
+ Number.NEGATIVE_INFINITY,
432
+ Number.NEGATIVE_INFINITY,
433
+ ]),
434
+ new Float32Array([1, 0, 0, 0, 1, 1]),
435
+ new Float32Array([0, 1, 0, 1, 0, 1]),
436
+ new Float32Array([0, 0, 1, 1, 1, 0]),
437
+ new Float32Array([Number.NaN, 0, 0, 1, 1, 1]),
438
+ new Float32Array([0, 0, 0, Number.POSITIVE_INFINITY, 1, 1]),
439
+ new Float32Array([0, 0, 0, 1]),
440
+ ];
441
+
442
+ for (const [index, aabb] of malformedAabbs.entries()) {
443
+ const world = new World();
444
+ spawnCamera(world);
445
+ const mesh = registerMeshWithAabb(world, aabb);
446
+ const material = registerMaterial(world);
447
+ world
448
+ .spawn(
449
+ { component: Transform, data: { ...identity(), pos: [0, 0, 200] } },
450
+ { component: MeshFilter, data: { assetHandle: mesh } },
451
+ { component: MeshRenderer, data: { materials: [material] } },
452
+ )
453
+ .unwrap();
454
+
455
+ expect(propagateTransforms(world).ok).toBe(true);
456
+ const frame = extractFrame(world, prepareExtractContext(world));
457
+
458
+ // Invalid/missing bounds must never cause a false negative visibility
459
+ // result. They are a producer-contract failure, not a valid cull
460
+ // candidate, so they stay out of frustumStats.
461
+ expect(frame.renderables, `malformed AABB case ${index}`).toHaveLength(1);
462
+ expect(frame.frustumStats, `malformed AABB case ${index}`).toEqual({ culled: 0, total: 0 });
463
+ }
464
+ });
465
+
466
+ it('AC-15: mesh-walk reads world via the column array view, not a per-renderable world.get materialization', () => {
467
+ const world = new World();
468
+ spawnCamera(world);
469
+ world
470
+ .spawn(
471
+ { component: Transform, data: { ...identity(), pos: [1, 2, 3] } },
472
+ { component: MeshFilter, data: { assetHandle: HANDLE_CUBE } },
473
+ { component: MeshRenderer, data: {} },
474
+ )
475
+ .unwrap();
476
+ expect(propagateTransforms(world).ok).toBe(true);
477
+
478
+ const getSpy = vi.spyOn(world, 'get');
479
+ extractFrame(world, prepareExtractContext(world));
480
+ // The mesh-walk must NOT call world.get(entity, Transform) to read the
481
+ // resolved world mat4 -- it goes through the zero-materialization column
482
+ // array view (_getArrayView). Any Transform materialization here would
483
+ // re-introduce the per-frame `{}` allocation AC-15 forbids.
484
+ const transformGets = getSpy.mock.calls.filter((c) => {
485
+ const comp = c[1] as { name?: string } | undefined;
486
+ return comp?.name === 'Transform';
487
+ });
488
+ expect(transformGets.length).toBe(0);
489
+ getSpy.mockRestore();
490
+ });
491
+ });
492
+ }
493
+
494
+ // ─── from render-system-extract-material-inheritance.test.ts ───
495
+ {
496
+ // render-system-extract-material-inheritance.test.ts — M3 / w10 (TDD red)
497
+ //
498
+ // feat-20260529-material-parent-inheritance-read-through-drop-reso
499
+ //
500
+ // Integration tests for material parent-chain inheritance through the
501
+ // extract stage. These tests intentionally FAIL (red) because w11 has not
502
+ // yet wired extract:976 to consume passesOf/paramValueOf — extract still
503
+ // reads asset.passes directly without walking the parent chain.
504
+ //
505
+ // Coverage:
506
+ // (a) inherit-passes: child with no passes, parent ref — snapshot passes
507
+ // come from parent (AC-05 core signal)
508
+ // (b) shoot-76-equivalent: 1 parent + 76 children — extract produces
509
+ // materials with inherited passes (AC-06: non-empty hull.passes)
510
+ // (c) values-merge: child key overrides parent, parent-only key
511
+ // retained (AC-06 shallow-merge)
512
+ // (d) no-parent-regression: material with no parent — extract still works
513
+ //
514
+ // Anchors: requirements AC-05 (extract inheritance core signal) /
515
+ // AC-06 (76 materials equivalent reproduction); plan-strategy D-6
516
+ // (extract:976-999 transformation scope); research Finding 2 (L976 is the
517
+ // sole direct-read point + dataflow).
518
+
519
+ // ── Fixture constants ────────────────────────────────────────────────────────
520
+
521
+ const FORWARD_PBR_PASS: MaterialPass = {
522
+ name: 'Forward',
523
+ program: { module: 'forgeax::default-standard-pbr' },
524
+ };
525
+
526
+ const FORWARD_UNLIT_PASS: MaterialPass = {
527
+ name: 'Forward',
528
+ program: { module: 'forgeax::default-unlit' },
529
+ };
530
+
531
+ // ── Helpers ──────────────────────────────────────────────────────────────────
532
+
533
+ function makeWorldWithComponents(): World {
534
+ const world = new World();
535
+ return world;
536
+ }
537
+
538
+ function registerTestMesh(world: World): Handle<'MeshAsset', 'shared'> {
539
+ const positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
540
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', {
541
+ kind: 'mesh',
542
+ vertices: new Float32Array([
543
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
544
+ 1, 0, 0, 0, 0,
545
+ ]),
546
+ indices: new Uint16Array([0, 1, 2]),
547
+ attributes: { position: positions },
548
+ aabb: new Float32Array([0, 0, 0, 1, 1, 1]),
549
+ submeshes: [
550
+ {
551
+ indexOffset: 0,
552
+ indexCount: 3,
553
+ vertexCount: 36,
554
+ topology: 'triangle-list',
555
+ materialSlot: 0,
556
+ },
557
+ ],
558
+
559
+ materialSlots: [{ slotName: 'Default' }],
560
+ });
561
+ }
562
+
563
+ // D-19: a material's parent is an embedded AssetGuid resolved through the
564
+ // registry catalogue (registry.lookup), while the material itself is
565
+ // resolved from a column handle via world.sharedRefs. So a parent material is
566
+ // catalogued by GUID (lookupable during the walk) and the child references
567
+ // that GUID; the returned handle is what MeshRenderer.materials carries.
568
+ function registerMaterial(
569
+ world: World,
570
+ assets: AssetRegistry,
571
+ passes: MaterialPass[] | undefined,
572
+ parentGuid?: AssetGuid,
573
+ values?: Readonly<Record<string, unknown>>,
574
+ ): { handle: Handle<'MaterialAsset', 'shared'>; guid: AssetGuid } {
575
+ const asset: MaterialAsset = {
576
+ kind: 'material',
577
+ passes,
578
+ values: values ?? {},
579
+ } as unknown as MaterialAsset;
580
+ if (parentGuid !== undefined) {
581
+ (asset as { parent: AssetGuid }).parent = parentGuid;
582
+ }
583
+ const guid = AssetGuid.random();
584
+ assets.catalog(guid, asset);
585
+ const handle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', asset);
586
+ return { handle, guid };
587
+ }
588
+
589
+ function transformData(
590
+ x: number,
591
+ y: number,
592
+ z: number,
593
+ ): {
594
+ pos: number[];
595
+ quat: number[];
596
+ scale: number[];
597
+ } {
598
+ return {
599
+ pos: [x, y, z],
600
+ quat: [0, 0, 0, 1],
601
+ scale: [1, 1, 1],
602
+ };
603
+ }
604
+
605
+ function spawnRenderable(
606
+ world: World,
607
+ meshHandle: Handle<'MeshAsset', 'shared'>,
608
+ matHandle: Handle<'MaterialAsset', 'shared'>,
609
+ x = 0,
610
+ y = 0,
611
+ z = 0,
612
+ ): void {
613
+ world
614
+ .spawn(
615
+ { component: Transform, data: transformData(x, y, z) },
616
+ { component: MeshFilter, data: { assetHandle: meshHandle } },
617
+ { component: MeshRenderer, data: { materials: [matHandle] } },
618
+ )
619
+ .unwrap();
620
+ }
621
+
622
+ function spawnCamera(world: World): void {
623
+ world
624
+ .spawn(
625
+ {
626
+ component: Transform,
627
+ data: transformData(0, 0, 5),
628
+ },
629
+ {
630
+ component: Camera,
631
+ data: {
632
+ fov: Math.PI / 4,
633
+ aspect: 1,
634
+ near: 0.1,
635
+ far: 100,
636
+ projection: 0,
637
+ left: -1,
638
+ right: 1,
639
+ bottom: -1,
640
+ top: 1,
641
+ },
642
+ },
643
+ )
644
+ .unwrap();
645
+ }
646
+
647
+ // ── Tests ────────────────────────────────────────────────────────────────────
648
+
649
+ describe('render-system-extract material inheritance (M3 w10, TDD red)', () => {
650
+ // ── (a) AC-05: inherit passes from parent ─────────────────────────────
651
+
652
+ it('AC-05 core signal: child no-passes inherits passes from parent via extract', () => {
653
+ const world = makeWorldWithComponents();
654
+ spawnCamera(world);
655
+ const assets = new AssetRegistry(makeMockShaderRegistry());
656
+ const mesh = registerTestMesh(world);
657
+
658
+ const parentMat = registerMaterial(world, assets, [FORWARD_PBR_PASS]);
659
+ const childMat = registerMaterial(world, assets, undefined, parentMat.guid);
660
+
661
+ spawnRenderable(world, mesh, childMat.handle);
662
+
663
+ propagateTransforms(world);
664
+
665
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
666
+ expect(frame.renderables.length).toBe(1);
667
+
668
+ // AC-05: the child's snapshot should inherit passes from the parent,
669
+ // yielding a non-undefined materialShaderId derived from the first pass.
670
+ // RED: with direct asset.passes read, child with undefined passes
671
+ // yields passes=[] -> materialShaderId=undefined.
672
+ const snap = frame.renderables[0]?.material;
673
+ expect(snap).toBeDefined();
674
+ expect(snap?.materialShaderId).toBe('forgeax::default-standard-pbr');
675
+ });
676
+
677
+ // ── (b) AC-06: shoot-76 equivalent (1 parent + 76 children) ─────────
678
+
679
+ it('AC-06 shoot-76 equivalent: N children inherit from 1 parent', () => {
680
+ const world = makeWorldWithComponents();
681
+ spawnCamera(world);
682
+ const assets = new AssetRegistry(makeMockShaderRegistry());
683
+ const mesh = registerTestMesh(world);
684
+
685
+ const parentMat = registerMaterial(world, assets, [FORWARD_PBR_PASS]);
686
+
687
+ const childCount = 76;
688
+ for (let i = 0; i < childCount; i++) {
689
+ const childMat = registerMaterial(world, assets, undefined, parentMat.guid);
690
+ // Spread across Z axis (0 to -60) so all entities stay within
691
+ // the perspective camera frustum (far=100, fov=PI/4 at (0,0,5)).
692
+ spawnRenderable(world, mesh, childMat.handle, 0, 0, -i * 0.8);
693
+ }
694
+
695
+ propagateTransforms(world);
696
+
697
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
698
+
699
+ // AC-06: all 76 entities should produce renderables with non-empty
700
+ // inherited passes.
701
+ expect(frame.renderables.length).toBe(childCount);
702
+
703
+ for (let i = 0; i < childCount; i++) {
704
+ const snap = frame.renderables[i]?.material;
705
+ // RED: each child's snapshot currently has undefined materialShaderId
706
+ // because asset.passes is undefined (direct read, no parent walk).
707
+ expect(snap?.materialShaderId).toBe('forgeax::default-standard-pbr');
708
+ }
709
+ });
710
+
711
+ // ── (c) AC-06: values shallow-merge ───────────────────────────
712
+
713
+ it('AC-06 values shallow-merge: child overrides parent, parent-only key retained', () => {
714
+ const world = makeWorldWithComponents();
715
+ spawnCamera(world);
716
+ const assets = new AssetRegistry(makeMockShaderRegistry());
717
+ const mesh = registerTestMesh(world);
718
+
719
+ const parentMat = registerMaterial(world, assets, [FORWARD_PBR_PASS], undefined, {
720
+ metallic: 0.3,
721
+ roughness: 0.7,
722
+ });
723
+ const childMat = registerMaterial(world, assets, undefined, parentMat.guid, {
724
+ metallic: 0.9,
725
+ });
726
+
727
+ spawnRenderable(world, mesh, childMat.handle);
728
+
729
+ propagateTransforms(world);
730
+
731
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
732
+ expect(frame.renderables.length).toBe(1);
733
+
734
+ // RED: child's metallic should be 0.9 (child overrides), roughness
735
+ // should be 0.7 (inherited from parent). With direct asset read,
736
+ // roughness comes from child's own values which is { metallic: 0.9 }
737
+ // — roughness defaults to 0.5, not inherited from parent.
738
+ const snap = frame.renderables[0]?.material;
739
+ expect(snap).toBeDefined();
740
+ expect(snap?.metallic).toBe(0.9);
741
+ expect(snap?.roughness).toBe(0.7);
742
+ });
743
+
744
+ // ── (d) regression: no-parent path still works ─────────────────────
745
+
746
+ it('no-parent regression: material without parent still extracts correctly', () => {
747
+ const world = makeWorldWithComponents();
748
+ spawnCamera(world);
749
+ const assets = new AssetRegistry(makeMockShaderRegistry());
750
+ const mesh = registerTestMesh(world);
751
+
752
+ const mat = registerMaterial(world, assets, [FORWARD_UNLIT_PASS], undefined, {
753
+ baseColor: [0.2, 0.3, 0.4],
754
+ });
755
+
756
+ spawnRenderable(world, mesh, mat.handle);
757
+
758
+ propagateTransforms(world);
759
+
760
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
761
+ expect(frame.renderables.length).toBe(1);
762
+
763
+ const snap = frame.renderables[0]?.material;
764
+ expect(snap).toBeDefined();
765
+ expect(snap?.materialShaderId).toBe('forgeax::default-unlit');
766
+ expect(snap?.baseColor[0]).toBeCloseTo(srgbChannelToLinear(0.2));
767
+ expect(snap?.baseColor[1]).toBeCloseTo(srgbChannelToLinear(0.3));
768
+ expect(snap?.baseColor[2]).toBeCloseTo(srgbChannelToLinear(0.4));
769
+ });
770
+ });
771
+ }
772
+
773
+ // --- from render-system-extract-sprite-slices.test.ts ---
774
+ {
775
+ // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w9 (TDD red).
776
+ //
777
+ // Sprite extract now walks the same generic else-branch every other
778
+ // paramSchema-driven material consumes: extract produces a MaterialSnapshot
779
+ // carrying `materialShaderId === 'forgeax::sprite'` + `paramSnapshot` keyed
780
+ // on the WGSL Material UBO struct field names (colorTint / region /
781
+ // pivotAndSize / slicesAndMode). `shadingModel` is undefined on the sprite
782
+ // path -- the 'sprite' union member is removed (AC-01 w15 closes the type
783
+ // layer; this test asserts the production behaviour change at w12).
784
+ //
785
+ // Three sentinel states match the post-ablation slicesAndMode encoding:
786
+ // - undefined slices: paramSnapshot.slicesAndMode === [0, 0, 0, 0]
787
+ // - stretch [.25,.25,.25,.25] sliceMode=0 -> [.25, .25, .25, .25]
788
+ // - tile [.25,.25,.25,.25] sliceMode=1 -> [.25, .25, .25, -.25]
789
+ // (extract pre-folds sliceMode=1 by negating slicesAndMode.w; the
790
+ // shader recovers magnitude via abs() and dispatches on sign.)
791
+ //
792
+ // RED before w12 -- the legacy isSprite branch still emits
793
+ // shadingModel='sprite' + spriteFields. Goes green after w12.
794
+
795
+ function makeShaderRegistryWithSprite(): ShaderRegistry {
796
+ const mockDevice: ShaderRegistryDevice = {
797
+ createShaderModule() {
798
+ return {
799
+ ok: true,
800
+ value: undefined,
801
+ unwrap: () => undefined,
802
+ unwrapOr: (d: unknown) => d,
803
+ } as unknown as ReturnType<ShaderRegistryDevice['createShaderModule']>;
804
+ },
805
+ };
806
+ const sr = new ShaderRegistry({ device: mockDevice, manifestUrl: undefined });
807
+ // Sprite paramSchema mirrors sprite.material.json post-w11. The four
808
+ // UBO entries (colorTint / region / pivotAndSize / slicesAndMode) are
809
+ // the WGSL Material struct field names; user-facing inputs
810
+ // (region/pivot/slices/sliceMode/flipX/flipY) are folded into these
811
+ // entries by the sprite extract branch (D-8 flip + sliceMode fold).
812
+ // The texture entry uses the post-w11 baseColorTexture name (D-4).
813
+ sr.installMaterialArtifact('forgeax::sprite', {
814
+ source: 'fn main() {}',
815
+ paramSchema: [
816
+ { name: 'colorTint', type: 'vec4', default: [1.0, 1.0, 1.0, 1.0] },
817
+ { name: 'region', type: 'vec4', default: [0.0, 0.0, 1.0, 1.0] },
818
+ { name: 'pivotAndSize', type: 'vec4', default: [0.5, 0.5, 1.0, 1.0] },
819
+ { name: 'slicesAndMode', type: 'vec4', default: [0.0, 0.0, 0.0, 0.0] },
820
+ { name: 'baseColorTexture', type: 'texture2d' },
821
+ ],
822
+ });
823
+ return sr;
824
+ }
825
+
826
+ const SPRITE_PASS: MaterialPass = {
827
+ name: 'Sprite',
828
+ program: { module: 'forgeax::sprite' },
829
+ renderState: { queue: 3000 },
830
+ };
831
+
832
+ function identity() {
833
+ return {
834
+ pos: [0, 0, 0],
835
+ quat: [0, 0, 0, 1],
836
+ scale: [1, 1, 1],
837
+ };
838
+ }
839
+
840
+ function registerSpriteMesh(world: World): Handle<'MeshAsset', 'shared'> {
841
+ const positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
842
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', {
843
+ kind: 'mesh',
844
+ vertices: new Float32Array([
845
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
846
+ 1, 0, 0, 0, 0,
847
+ ]),
848
+ indices: new Uint16Array([0, 1, 2]),
849
+ attributes: { position: positions },
850
+ aabb: new Float32Array([0, 0, 0, 1, 1, 1]),
851
+ submeshes: [
852
+ {
853
+ indexOffset: 0,
854
+ indexCount: 3,
855
+ vertexCount: 36,
856
+ topology: 'triangle-list',
857
+ materialSlot: 0,
858
+ },
859
+ ],
860
+
861
+ materialSlots: [{ slotName: 'Default' }],
862
+ });
863
+ }
864
+
865
+ function spawnSpriteScene(values: Record<string, unknown>): {
866
+ world: World;
867
+ assets: AssetRegistry;
868
+ } {
869
+ const world = new World();
870
+ const assets = new AssetRegistry(makeShaderRegistryWithSprite());
871
+ const mesh = registerSpriteMesh(world);
872
+ const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
873
+ kind: 'material',
874
+ passes: [SPRITE_PASS],
875
+ values,
876
+ } as MaterialAsset);
877
+ // Spawn a camera so extract has a viewport.
878
+ world
879
+ .spawn(
880
+ { component: Transform, data: { ...identity(), pos: [0, 0, 5] } },
881
+ {
882
+ component: Camera,
883
+ data: {
884
+ fov: Math.PI / 4,
885
+ aspect: 1,
886
+ near: 0.1,
887
+ far: 100,
888
+ projection: 0,
889
+ left: -1,
890
+ right: 1,
891
+ bottom: -1,
892
+ top: 1,
893
+ },
894
+ },
895
+ )
896
+ .unwrap();
897
+ // Spawn sprite entity.
898
+ world
899
+ .spawn(
900
+ { component: Transform, data: identity() },
901
+ { component: MeshFilter, data: { assetHandle: mesh } },
902
+ { component: MeshRenderer, data: { materials: [matHandle] } },
903
+ )
904
+ .unwrap();
905
+ propagateTransforms(world);
906
+ return { world, assets };
907
+ }
908
+
909
+ describe('render-system-extract sprite paramSnapshot slicesAndMode (M3 / w9)', () => {
910
+ it('(1) no slicesAndMode in values -> paramSnapshot.slicesAndMode absent', () => {
911
+ const { world, assets } = spawnSpriteScene({});
912
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
913
+ // Renderable filter: post-ablation sprite carries forgeax::sprite
914
+ // shaderId, NOT shadingModel='sprite' (the union member is gone in
915
+ // AC-01).
916
+ const renderable = frame.renderables.find(
917
+ (r) => r.material.materialShaderId === 'forgeax::sprite',
918
+ );
919
+ expect(renderable).toBeDefined();
920
+ const snap = renderable?.material.paramSnapshot;
921
+ expect(snap).toBeDefined();
922
+ // w0a SSOT-collapse fix: extract stage now explicitly seeds the
923
+ // slicesAndMode slot with [0,0,0,0] when absent from values so
924
+ // the record-stage UBO writer overrides the PBR baseline (which would
925
+ // otherwise leave occlusionStrength=1 at offset 48 -> trips
926
+ // useSlices=true in sprite.wgsl -> degenerate quad).
927
+ expect(snap?.slicesAndMode).toEqual([0, 0, 0, 0]);
928
+ });
929
+
930
+ it('(2) stretch slicesAndMode [0.25,0.25,0.25,0.25] -> paramSnapshot.slicesAndMode verbatim', () => {
931
+ const { world, assets } = spawnSpriteScene({
932
+ slicesAndMode: [0.25, 0.25, 0.25, 0.25],
933
+ });
934
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
935
+ const renderable = frame.renderables.find(
936
+ (r) => r.material.materialShaderId === 'forgeax::sprite',
937
+ );
938
+ expect(renderable).toBeDefined();
939
+ const snap = renderable?.material.paramSnapshot;
940
+ expect(snap?.slicesAndMode).toEqual([0.25, 0.25, 0.25, 0.25]);
941
+ });
942
+
943
+ it('(3) tile slicesAndMode [.25,.25,.25,-.25] -> .w negative sentinel verbatim', () => {
944
+ // Post-fix-up F-1: callers encode tile mode at the call site by
945
+ // supplying a negative `.w`; the extract path no longer folds a
946
+ // separate `sliceMode` scalar (the shim layer is gone).
947
+ const { world, assets } = spawnSpriteScene({
948
+ slicesAndMode: [0.25, 0.25, 0.25, -0.25],
949
+ });
950
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
951
+ const renderable = frame.renderables.find(
952
+ (r) => r.material.materialShaderId === 'forgeax::sprite',
953
+ );
954
+ expect(renderable).toBeDefined();
955
+ const snap = renderable?.material.paramSnapshot;
956
+ const slicesAndMode = snap?.slicesAndMode as readonly number[] | undefined;
957
+ expect(slicesAndMode?.[0]).toBe(0.25);
958
+ expect(slicesAndMode?.[1]).toBe(0.25);
959
+ expect(slicesAndMode?.[2]).toBe(0.25);
960
+ // Sentinel encoding: D-3 .w negative on tile mode (shader abs() recovers).
961
+ expect(slicesAndMode?.[3]).toBe(-0.25);
962
+ });
963
+
964
+ it('(4) default identity region fold; pivotAndSize absent when not supplied', () => {
965
+ const { world, assets } = spawnSpriteScene({});
966
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
967
+ const renderable = frame.renderables.find(
968
+ (r) => r.material.materialShaderId === 'forgeax::sprite',
969
+ );
970
+ const snap = renderable?.material.paramSnapshot;
971
+ // The sprite block still writes paramSnap.region unconditionally because
972
+ // SpriteRegionOverride + flipX/flipY fold (plan D-8) need a base to
973
+ // operate on; the [0,0,1,1] identity is that base.
974
+ expect(snap?.region).toEqual([0, 0, 1, 1]);
975
+ // Post-fix-up F-1: no legacy `pivot` -> `pivotAndSize` fold; absence on
976
+ // input means absence on snapshot (UBO writer fills std140 zero).
977
+ expect(snap?.pivotAndSize).toBeUndefined();
978
+ });
979
+
980
+ it('(5) flipX=1 folds into paramSnapshot.region: region.x += region.z; region.z = -region.z (D-8)', () => {
981
+ const { world, assets } = spawnSpriteScene({ flipX: 1 });
982
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
983
+ const renderable = frame.renderables.find(
984
+ (r) => r.material.materialShaderId === 'forgeax::sprite',
985
+ );
986
+ const snap = renderable?.material.paramSnapshot;
987
+ // Identity region [0,0,1,1] with flipX -> [1, 0, -1, 1].
988
+ const region = snap?.region as readonly number[] | undefined;
989
+ expect(region?.[0]).toBe(1);
990
+ expect(region?.[1]).toBe(0);
991
+ expect(region?.[2]).toBe(-1);
992
+ expect(region?.[3]).toBe(1);
993
+ });
994
+ });
995
+ }
996
+
997
+ // ─── from render-system-clear-camera.test.ts ───
998
+ {
999
+ // @forgeax/engine-runtime/__tests__/render-system-clear-camera.test.ts -
1000
+ // feat-20260608-create-app-param-surface-trim / M1 / TASK-002.
1001
+ //
1002
+ // Asserts the clear-color flow from a Camera entity's SoA column into
1003
+ // the per-frame CameraSnapshot the record stage reads. The extract stage
1004
+ // is the boundary between the ECS column-views and the record stage's
1005
+ // GPU recording calls; once clearColor is on the snapshot, the record
1006
+ // stage can drop `internals.clearColor ?? [0.06, 0.06, 0.08, 1.0]` and
1007
+ // read directly from `cameras[0]` (first-archetype-hit per
1008
+ // requirements §OOS-2).
1009
+ //
1010
+ // feat-20260709 M3 / D-3: clear-color is one inline `array<f32,4>` column
1011
+ // (collapsed from the feat-20260608 clearR/G/B/A quartet) read on the hot
1012
+ // path as a stride-4 subscript, mirroring the light direction/color SoA
1013
+ // idiom.
1014
+ //
1015
+ // AC-03 asserts the boundary: if the snapshot does not surface clearColor,
1016
+ // the record stage cannot read it without re-walking the ECS, defeating the
1017
+ // SoA pipeline.
1018
+
1019
+ function identityTransform() {
1020
+ return {
1021
+ pos: [0, 0, 0],
1022
+ quat: [0, 0, 0, 1],
1023
+ scale: [1, 1, 1],
1024
+ };
1025
+ }
1026
+
1027
+ function spawnCamera(
1028
+ world: World,
1029
+ cam: { clearColor: readonly [number, number, number, number] },
1030
+ ) {
1031
+ world
1032
+ .spawn(
1033
+ { component: Transform, data: identityTransform() },
1034
+ {
1035
+ component: Camera,
1036
+ data: {
1037
+ fov: Math.PI / 4,
1038
+ aspect: 1,
1039
+ near: 0.1,
1040
+ far: 100,
1041
+ clearColor: cam.clearColor,
1042
+ },
1043
+ },
1044
+ )
1045
+ .unwrap();
1046
+ }
1047
+
1048
+ describe('render-system-extract clear-color SoA flow (TASK-002)', () => {
1049
+ it('CameraSnapshot surfaces clearColor read straight from the Camera SoA column', () => {
1050
+ const world = new World();
1051
+ spawnCamera(world, { clearColor: [0.25, 0.5, 0.75, 1.0] });
1052
+ propagateTransforms(world);
1053
+ const frame = extractFrame(world, prepareExtractContext(world));
1054
+ expect(frame.cameras.length).toBe(1);
1055
+ const cam = frame.cameras[0];
1056
+ expect(cam).toBeDefined();
1057
+ if (!cam) return;
1058
+ expect(cam.clearColor[0]).toBeCloseTo(0.25, 6);
1059
+ expect(cam.clearColor[1]).toBeCloseTo(0.5, 6);
1060
+ expect(cam.clearColor[2]).toBeCloseTo(0.75, 6);
1061
+ expect(cam.clearColor[3]).toBeCloseTo(1.0, 6);
1062
+ });
1063
+
1064
+ it('first-archetype-hit semantics: when N>1 cameras carry distinct clear, snapshot[0] is the first one', () => {
1065
+ const world = new World();
1066
+ spawnCamera(world, { clearColor: [0.1, 0.2, 0.3, 1.0] });
1067
+ spawnCamera(world, { clearColor: [0.9, 0.8, 0.7, 1.0] });
1068
+ propagateTransforms(world);
1069
+ const frame = extractFrame(world, prepareExtractContext(world));
1070
+ expect(frame.cameras.length).toBeGreaterThanOrEqual(1);
1071
+ const cam0 = frame.cameras[0];
1072
+ expect(cam0).toBeDefined();
1073
+ if (!cam0) return;
1074
+ // The record stage uses cameras[0] (first-archetype-hit) per OOS-2;
1075
+ // assert the snapshot ordering preserves the spawn order so the
1076
+ // record stage's cameras[0] read is deterministic.
1077
+ expect(cam0.clearColor[0]).toBeCloseTo(0.1, 6);
1078
+ expect(cam0.clearColor[1]).toBeCloseTo(0.2, 6);
1079
+ expect(cam0.clearColor[2]).toBeCloseTo(0.3, 6);
1080
+ });
1081
+
1082
+ it('Camera spawned without explicit clearColor defaults to transparent black [0,0,0,0]', () => {
1083
+ const world = new World();
1084
+ world
1085
+ .spawn(
1086
+ { component: Transform, data: identityTransform() },
1087
+ {
1088
+ component: Camera,
1089
+ data: { fov: Math.PI / 4, aspect: 1, near: 0.1, far: 100 },
1090
+ },
1091
+ )
1092
+ .unwrap();
1093
+ propagateTransforms(world);
1094
+ const frame = extractFrame(world, prepareExtractContext(world));
1095
+ const cam = frame.cameras[0];
1096
+ expect(cam).toBeDefined();
1097
+ if (!cam) return;
1098
+ expect(Array.from(cam.clearColor)).toEqual([0, 0, 0, 0]);
1099
+ });
1100
+ });
1101
+ }
1102
+
1103
+ // ─── M2 / w3: extract MaterialSnapshot carries a 4th texture (heightTexture) ───
1104
+ //
1105
+ // feat-20260621-learn-render-5-5-parallax-mapping-demo-aligned-wit M2 / w3
1106
+ //
1107
+ // A custom parallax shader declares heightTexture (the 4th user-region texture).
1108
+ // The extract stage must iterate derive(paramSchema).textureFieldNames so the
1109
+ // heightTexture handle flows into the MaterialSnapshot. Today extract hardcodes
1110
+ // the 3 standard texture fields, so the 4th texture's handle is silently
1111
+ // dropped — this test is RED until w7 wires the iteration. Post-w7 the snapshot
1112
+ // carries the handle under MaterialSnapshot.textureHandles (a field-name keyed
1113
+ // map that holds every declared user-region texture handle).
1114
+ {
1115
+ function makeShaderRegistryWithParallax(): ShaderRegistry {
1116
+ const mockDevice: ShaderRegistryDevice = {
1117
+ createShaderModule() {
1118
+ return {
1119
+ ok: true,
1120
+ value: undefined,
1121
+ unwrap: () => undefined,
1122
+ unwrapOr: (d: unknown) => d,
1123
+ } as unknown as ReturnType<ShaderRegistryDevice['createShaderModule']>;
1124
+ },
1125
+ };
1126
+ const sr = new ShaderRegistry({ device: mockDevice, manifestUrl: undefined });
1127
+ sr.installMaterialArtifact('learn-render::5-5-parallax', {
1128
+ source: 'fn main() {}',
1129
+ paramSchema: [
1130
+ { name: 'baseColor', type: 'color', default: [1.0, 1.0, 1.0, 1.0] },
1131
+ { name: 'metallic', type: 'f32', default: 0.0 },
1132
+ { name: 'roughness', type: 'f32', default: 0.5 },
1133
+ { name: 'heightScale', type: 'f32', default: 0.1 },
1134
+ { name: 'algoMode', type: 'f32', default: 0.0 },
1135
+ { name: 'baseColorTexture', type: 'texture2d' },
1136
+ { name: 'metallicRoughnessTexture', type: 'texture2d' },
1137
+ { name: 'normalTexture', type: 'texture2d' },
1138
+ { name: 'heightTexture', type: 'texture2d' },
1139
+ ],
1140
+ });
1141
+ return sr;
1142
+ }
1143
+
1144
+ function makeShaderRegistryWithEmptyBuiltinPbrSchema(): ShaderRegistry {
1145
+ const sr = makeShaderRegistryWithParallax();
1146
+ sr.installMaterialArtifact('forgeax::default-standard-pbr', {
1147
+ source: 'fn main() {}',
1148
+ paramSchema: [],
1149
+ });
1150
+ return sr;
1151
+ }
1152
+
1153
+ const PARALLAX_PASS: MaterialPass = {
1154
+ name: 'Forward',
1155
+ program: { module: 'learn-render::5-5-parallax' },
1156
+ };
1157
+
1158
+ function identityTx() {
1159
+ return {
1160
+ pos: [0, 0, 0],
1161
+ quat: [0, 0, 0, 1],
1162
+ scale: [1, 1, 1],
1163
+ };
1164
+ }
1165
+
1166
+ function registerQuadMesh(world: World): Handle<'MeshAsset', 'shared'> {
1167
+ const positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
1168
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', {
1169
+ kind: 'mesh',
1170
+ vertices: new Float32Array([
1171
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
1172
+ 1, 0, 0, 0, 0,
1173
+ ]),
1174
+ indices: new Uint16Array([0, 1, 2]),
1175
+ attributes: { position: positions },
1176
+ aabb: new Float32Array([0, 0, 0, 1, 1, 1]),
1177
+ submeshes: [
1178
+ {
1179
+ indexOffset: 0,
1180
+ indexCount: 3,
1181
+ vertexCount: 36,
1182
+ topology: 'triangle-list',
1183
+ materialSlot: 0,
1184
+ },
1185
+ ],
1186
+
1187
+ materialSlots: [{ slotName: 'Default' }],
1188
+ });
1189
+ }
1190
+
1191
+ function makeTextureHandle(world: World): Handle<'TextureAsset', 'shared'> {
1192
+ return world.allocSharedRef<'TextureAsset', import('@forgeax/engine-types').TextureAsset>(
1193
+ 'TextureAsset',
1194
+ {
1195
+ kind: 'texture',
1196
+ width: 1,
1197
+ height: 1,
1198
+ format: 'rgba8unorm',
1199
+ data: new Uint8Array([255, 255, 255, 255]),
1200
+ colorSpace: 'linear',
1201
+ mipmap: false,
1202
+ },
1203
+ );
1204
+ }
1205
+
1206
+ describe('render-system-extract heightTexture (4th texture) snapshot pass-through (M2 w3)', () => {
1207
+ it('resolves a binary AssetGuid texture reference through the material owner path', () => {
1208
+ const world = new World();
1209
+ const assets = new AssetRegistry(makeShaderRegistryWithParallax());
1210
+ const mesh = registerQuadMesh(world);
1211
+ const textureGuid = AssetGuid.random();
1212
+ assets.catalog(textureGuid, {
1213
+ kind: 'texture',
1214
+ width: 1,
1215
+ height: 1,
1216
+ format: 'rgba8unorm',
1217
+ data: new Uint8Array([255, 255, 255, 255]),
1218
+ colorSpace: 'linear',
1219
+ mipmap: false,
1220
+ } satisfies TextureAsset);
1221
+ const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
1222
+ kind: 'material',
1223
+ passes: [PARALLAX_PASS],
1224
+ values: { baseColorTexture: { texture: textureGuid } },
1225
+ });
1226
+
1227
+ world
1228
+ .spawn(
1229
+ { component: Transform, data: identityTx() },
1230
+ { component: MeshFilter, data: { assetHandle: mesh } },
1231
+ { component: MeshRenderer, data: { materials: [matHandle] } },
1232
+ )
1233
+ .unwrap();
1234
+ propagateTransforms(world);
1235
+
1236
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
1237
+ const textureHandle = frame.renderables[0]?.material.textureHandles?.get('baseColorTexture');
1238
+ expect(textureHandle).toBeDefined();
1239
+ expect(resolveAssetHandle<TextureAsset>(world, textureHandle as never).unwrap().kind).toBe(
1240
+ 'texture',
1241
+ );
1242
+ });
1243
+
1244
+ it('MaterialSnapshot.textureHandles carries heightTexture handle (non-undefined, matches input)', () => {
1245
+ const world = new World();
1246
+ const assets = new AssetRegistry(makeShaderRegistryWithParallax());
1247
+ const mesh = registerQuadMesh(world);
1248
+
1249
+ const baseColorHandle = makeTextureHandle(world);
1250
+ const normalHandle = makeTextureHandle(world);
1251
+ const heightHandle = makeTextureHandle(world);
1252
+
1253
+ const matHandle = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
1254
+ kind: 'material',
1255
+ passes: [PARALLAX_PASS],
1256
+ values: {
1257
+ baseColor: [1, 1, 1, 1],
1258
+ heightScale: 0.1,
1259
+ algoMode: 0,
1260
+ baseColorTexture: baseColorHandle,
1261
+ normalTexture: normalHandle,
1262
+ heightTexture: heightHandle,
1263
+ },
1264
+ } as MaterialAsset);
1265
+
1266
+ world
1267
+ .spawn(
1268
+ { component: Transform, data: { ...identityTx(), pos: [0, 0, 5] } },
1269
+ {
1270
+ component: Camera,
1271
+ data: {
1272
+ fov: Math.PI / 4,
1273
+ aspect: 1,
1274
+ near: 0.1,
1275
+ far: 100,
1276
+ projection: 0,
1277
+ left: -1,
1278
+ right: 1,
1279
+ bottom: -1,
1280
+ top: 1,
1281
+ },
1282
+ },
1283
+ )
1284
+ .unwrap();
1285
+ world
1286
+ .spawn(
1287
+ { component: Transform, data: identityTx() },
1288
+ { component: MeshFilter, data: { assetHandle: mesh } },
1289
+ { component: MeshRenderer, data: { materials: [matHandle] } },
1290
+ )
1291
+ .unwrap();
1292
+ propagateTransforms(world);
1293
+
1294
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
1295
+ const renderable = frame.renderables.find(
1296
+ (r) => r.material.materialShaderId === 'learn-render::5-5-parallax',
1297
+ );
1298
+ expect(renderable).toBeDefined();
1299
+ // The 4th texture handle must survive extract under the field-name keyed
1300
+ // map MaterialSnapshot.textureHandles (added + populated by w7). Read via
1301
+ // a structural cast so this test compiles in the red phase before the
1302
+ // field lands; the runtime assertion stays RED until w7 wires extract.
1303
+ const snap = renderable?.material as
1304
+ | {
1305
+ readonly textureHandles?: ReadonlyMap<string, Handle<'TextureAsset', 'shared'>>;
1306
+ readonly materialShaderId?: string;
1307
+ }
1308
+ | undefined;
1309
+ const heightFromSnap = snap?.textureHandles?.get('heightTexture');
1310
+ expect(heightFromSnap).toBeDefined();
1311
+ expect(heightFromSnap).toBe(heightHandle);
1312
+ // The standard fields also land in the same map (single SSOT path).
1313
+ expect(snap?.textureHandles?.get('baseColorTexture')).toBe(baseColorHandle);
1314
+ expect(snap?.textureHandles?.get('normalTexture')).toBe(normalHandle);
1315
+ });
1316
+
1317
+ it('keeps built-in PBR texture handles when its manifest schema is empty', () => {
1318
+ const world = new World();
1319
+ const assets = new AssetRegistry(makeShaderRegistryWithEmptyBuiltinPbrSchema());
1320
+ const mesh = registerQuadMesh(world);
1321
+ const baseColorHandle = makeTextureHandle(world);
1322
+ const metallicRoughnessHandle = makeTextureHandle(world);
1323
+ const samplerHandle = world.allocSharedRef('SamplerAsset', {
1324
+ kind: 'sampler',
1325
+ magFilter: 'nearest',
1326
+ minFilter: 'nearest',
1327
+ });
1328
+ const material = world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
1329
+ kind: 'material',
1330
+ passes: [
1331
+ {
1332
+ name: 'Forward',
1333
+ program: { module: 'forgeax::default-standard-pbr' },
1334
+ renderState: { tags: { LightMode: 'Forward' } },
1335
+ },
1336
+ ],
1337
+ values: {
1338
+ baseColor: [1, 1, 1, 1],
1339
+ baseColorTexture: {
1340
+ texture: baseColorHandle,
1341
+ sampler: samplerHandle,
1342
+ } as unknown as number,
1343
+ metallicRoughnessTexture: metallicRoughnessHandle,
1344
+ },
1345
+ });
1346
+
1347
+ world
1348
+ .spawn(
1349
+ { component: Transform, data: { ...identityTx(), pos: [0, 0, 5] } },
1350
+ {
1351
+ component: Camera,
1352
+ data: {
1353
+ fov: Math.PI / 4,
1354
+ aspect: 1,
1355
+ near: 0.1,
1356
+ far: 100,
1357
+ projection: 0,
1358
+ left: -1,
1359
+ right: 1,
1360
+ bottom: -1,
1361
+ top: 1,
1362
+ },
1363
+ },
1364
+ )
1365
+ .unwrap();
1366
+ world
1367
+ .spawn(
1368
+ { component: Transform, data: identityTx() },
1369
+ { component: MeshFilter, data: { assetHandle: mesh } },
1370
+ { component: MeshRenderer, data: { materials: [material] } },
1371
+ )
1372
+ .unwrap();
1373
+ propagateTransforms(world);
1374
+
1375
+ const snapshot = extractFrame(world, prepareExtractContext(world, { assets })).renderables[0]
1376
+ ?.material;
1377
+ expect(snapshot?.textureHandles?.get('baseColorTexture')).toBe(baseColorHandle);
1378
+ expect(snapshot?.textureHandles?.get('metallicRoughnessTexture')).toBe(
1379
+ metallicRoughnessHandle,
1380
+ );
1381
+ expect(snapshot?.samplerHandles?.get('baseColorTexture')).toBe(samplerHandle);
1382
+ });
1383
+ });
1384
+ }