@forgeax/engine-runtime 0.1.3 → 0.1.6

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 (606) hide show
  1. package/README.md +49 -83
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts +2 -0
  4. package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
  5. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
  6. package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
  8. package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
  9. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
  10. package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
  11. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
  12. package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
  13. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
  14. package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
  15. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
  16. package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
  17. package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
  18. package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
  19. package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
  20. package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
  21. package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
  22. package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
  23. package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
  24. package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
  25. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
  26. package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
  27. package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
  28. package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
  29. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
  30. package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
  31. package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
  32. package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
  33. package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
  34. package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/asset.unit.test.d.ts +2 -0
  36. package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
  37. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
  38. package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
  39. package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
  40. package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
  41. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
  42. package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
  43. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
  44. package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
  45. package/dist/__tests__/collect-scene-asset.test.d.ts +1 -2
  46. package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -1
  47. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
  48. package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
  49. package/dist/__tests__/collect-transient-roundtrip.test.d.ts +1 -1
  50. package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -1
  51. package/dist/__tests__/collect-transient-skip.test.d.ts +1 -2
  52. package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -1
  53. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
  54. package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
  55. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
  56. package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
  57. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
  58. package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
  59. package/dist/__tests__/draw-published.d.ts +2 -2
  60. package/dist/__tests__/draw-published.d.ts.map +1 -1
  61. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
  62. package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
  63. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  64. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  65. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
  66. package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
  67. package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
  68. package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
  69. package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
  70. package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
  71. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
  72. package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
  73. package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
  74. package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
  75. package/dist/__tests__/handle-migration.test.d.ts +2 -0
  76. package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
  77. package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -1
  78. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
  79. package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
  80. package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
  81. package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
  82. package/dist/__tests__/inspect-name.test.d.ts +2 -0
  83. package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
  84. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
  85. package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
  86. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
  87. package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
  88. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
  89. package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
  91. package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
  92. package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
  93. package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
  94. package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
  95. package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
  96. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
  97. package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/mesh-bin.test.d.ts +2 -0
  99. package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
  100. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
  101. package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
  102. package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
  103. package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
  104. package/dist/__tests__/package-promotion.test.d.ts +2 -0
  105. package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
  106. package/dist/__tests__/package-rename.test.d.ts +2 -0
  107. package/dist/__tests__/package-rename.test.d.ts.map +1 -0
  108. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +1 -1
  109. package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -1
  110. package/dist/__tests__/render-error-exhaustive.test-d.d.ts +1 -1
  111. package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
  112. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
  113. package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
  114. package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
  115. package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/renderer-test-utils.d.ts +10 -0
  117. package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
  118. package/dist/__tests__/renderer.test-d.d.ts +2 -0
  119. package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
  120. package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
  121. package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
  122. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
  123. package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
  125. package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
  126. package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
  127. package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
  128. package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
  129. package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
  130. package/dist/__tests__/resolveName.test.d.ts +2 -0
  131. package/dist/__tests__/resolveName.test.d.ts.map +1 -0
  132. package/dist/__tests__/roots-to-scene-asset.test.d.ts +1 -1
  133. package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -1
  134. package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
  135. package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
  136. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
  137. package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
  138. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
  139. package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
  140. package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
  141. package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
  142. package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
  143. package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
  144. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
  145. package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
  146. package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
  147. package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
  148. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
  149. package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
  150. package/dist/__tests__/serialize-scene-asset.test.d.ts +1 -1
  151. package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -1
  152. package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
  153. package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
  154. package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
  155. package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
  156. package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
  157. package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
  158. package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
  159. package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
  160. package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
  161. package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
  162. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
  163. package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
  164. package/dist/backend-selection.d.ts +13 -0
  165. package/dist/backend-selection.d.ts.map +1 -0
  166. package/dist/collect-scene-asset.d.ts +3 -3
  167. package/dist/collect-scene-asset.d.ts.map +1 -1
  168. package/dist/createRenderer.d.ts +14 -2
  169. package/dist/createRenderer.d.ts.map +1 -1
  170. package/dist/errors/environment.d.ts +1 -1
  171. package/dist/errors/environment.d.ts.map +1 -1
  172. package/dist/index.d.ts +19 -81
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.mjs +105 -108
  175. package/dist/index.mjs.map +1 -1
  176. package/dist/renderer-host.d.ts +9 -0
  177. package/dist/renderer-host.d.ts.map +1 -0
  178. package/dist/renderer-host.mjs +62 -0
  179. package/dist/renderer-host.mjs.map +1 -0
  180. package/dist/scene-instances/index.d.ts +2 -0
  181. package/dist/scene-instances/index.d.ts.map +1 -0
  182. package/dist/scene-utils/mount-override-fold.d.ts +1 -2
  183. package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
  184. package/dist/systems/sprite-animation-tick.d.ts +1 -1
  185. package/dist/systems/sprite-animation-tick.d.ts.map +1 -1
  186. package/dist/systems/transparent-sort.d.ts +1 -2
  187. package/dist/systems/transparent-sort.d.ts.map +1 -1
  188. package/dist/tilemap-register-validate.d.ts.map +1 -1
  189. package/package.json +34 -33
  190. package/src/__tests__/active-camera.unit.test.ts +19 -9
  191. package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
  192. package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
  193. package/src/__tests__/append-injection.test.ts +1 -1
  194. package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
  195. package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
  196. package/src/__tests__/asset-registry-guid-reverse.test.ts +575 -0
  197. package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
  198. package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
  199. package/src/__tests__/asset-registry-mounts.test.ts +806 -0
  200. package/src/__tests__/asset-registry.browser.test.ts +81 -0
  201. package/src/__tests__/asset-registry.dawn.test.ts +94 -0
  202. package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
  203. package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
  204. package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
  205. package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
  206. package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
  207. package/src/__tests__/asset-registry.unit.test.ts +1030 -0
  208. package/src/__tests__/asset.unit.test.ts +7107 -0
  209. package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
  210. package/src/__tests__/backend-selection.integration.test.ts +11 -0
  211. package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
  212. package/src/__tests__/bind-group-cache-keying.test.ts +4 -4
  213. package/src/__tests__/block-upload-math.unit.test.ts +2 -2
  214. package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
  215. package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
  216. package/src/__tests__/cache-false-eviction.test.ts +2 -1
  217. package/src/__tests__/cache-isolation-matrix.test.ts +2 -1
  218. package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +5 -6
  219. package/src/__tests__/clamp-to-last.e2e.browser.test.ts +29 -19
  220. package/src/__tests__/collect-scene-asset.test.ts +49 -52
  221. package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
  222. package/src/__tests__/collect-subtree.unit.test.ts +1 -2
  223. package/src/__tests__/collect-transient-children-absent.test.ts +24 -10
  224. package/src/__tests__/collect-transient-roundtrip.test.ts +44 -20
  225. package/src/__tests__/collect-transient-skip.test.ts +24 -13
  226. package/src/__tests__/components.test-d.ts +1 -6
  227. package/src/__tests__/components.unit.test.ts +20 -19
  228. package/src/__tests__/composite-skybox-cross-world.browser.test.ts +59 -27
  229. package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
  230. package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -29
  231. package/src/__tests__/createRenderer-dispose.test.ts +35 -402
  232. package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +25 -30
  233. package/src/__tests__/createRenderer.unit.test.ts +1 -1
  234. package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +27 -63
  235. package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +56 -47
  236. package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +49 -29
  237. package/src/__tests__/dawn/instances-shadow.dawn.test.ts +26 -15
  238. package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +13 -14
  239. package/src/__tests__/dawn/material-alpha.dawn.test.ts +23 -31
  240. package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +0 -18
  241. package/src/__tests__/dawn/{mesh-update.dawn.test.ts → mesh-update-dawn.test.ts} +42 -134
  242. package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +14 -7
  243. package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +16 -28
  244. package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +23 -39
  245. package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
  246. package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +12 -14
  247. package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +27 -22
  248. package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +25 -28
  249. package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +10 -11
  250. package/src/__tests__/demo-sortscope-migration.unit.test.ts +5 -5
  251. package/src/__tests__/derive-bgl-integration.test.ts +34 -44
  252. package/src/__tests__/derive-render-data-skin.unit.test.ts +1 -1
  253. package/src/__tests__/draw-published.ts +11 -4
  254. package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
  255. package/src/__tests__/equirect-bc6h.integration.test.ts +144 -21
  256. package/src/__tests__/errors.unit.test.ts +1203 -0
  257. package/src/__tests__/extract-frames-graceful-degradation.test.ts +3 -7
  258. package/src/__tests__/extract-frames-merge.test.ts +35 -22
  259. package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +5 -16
  260. package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
  261. package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
  262. package/src/__tests__/four-path-compression.integration.test.ts +395 -0
  263. package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +1 -1
  264. package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
  265. package/src/__tests__/fullscreen-post-bgl-depth.test.ts +4 -2
  266. package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +3 -3
  267. package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +39 -23
  268. package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +4 -2
  269. package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +28 -17
  270. package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +29 -18
  271. package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +16 -12
  272. package/src/__tests__/geometry.unit.test.ts +525 -159
  273. package/src/__tests__/glyph-tilemap-worldid.test.ts +1 -1
  274. package/src/__tests__/gpu-resource-cow-survivor.test.ts +6 -4
  275. package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
  276. package/src/__tests__/handle-migration.test.ts +136 -0
  277. package/src/__tests__/helpers/register-runtime-components.ts +4 -2
  278. package/src/__tests__/helpers/register-scene-components.ts +1 -1
  279. package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
  280. package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
  281. package/src/__tests__/inspect-name.test.ts +139 -0
  282. package/src/__tests__/instances.test-d.ts +1 -1
  283. package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
  284. package/src/__tests__/light-casters-9-light.browser.test.ts +73 -76
  285. package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +7 -10
  286. package/src/__tests__/light-snapshot.test-d.ts +2 -2
  287. package/src/__tests__/lights-vec-negative.unit.test.ts +1 -1
  288. package/src/__tests__/lights.unit.test.ts +16 -500
  289. package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
  290. package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
  291. package/src/__tests__/loader-extract-graceful.test.ts +146 -0
  292. package/src/__tests__/loader-name-survival.test.ts +213 -0
  293. package/src/__tests__/m3-vec-negative.unit.test.ts +3 -2
  294. package/src/__tests__/material-texture-uv-scale.unit.test.ts +101 -31
  295. package/src/__tests__/materials.unit.test.ts +10 -27
  296. package/src/__tests__/mesh-bin-contract.test.ts +28 -0
  297. package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
  298. package/src/__tests__/mesh-bin.test.ts +38 -0
  299. package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
  300. package/src/__tests__/mesh-ssbo-grow.unit.test.ts +3 -3
  301. package/src/__tests__/mip-gate.unit.test.ts +1 -1
  302. package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +29 -68
  303. package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
  304. package/src/__tests__/node-shims.d.ts +4 -6
  305. package/src/__tests__/package-promotion.test.ts +88 -0
  306. package/src/__tests__/package-rename.test.ts +103 -0
  307. package/src/__tests__/pass-selector.unit.test.ts +2 -2
  308. package/src/__tests__/pbr-pipeline.unit.test.ts +14 -21
  309. package/src/__tests__/pipeline-builder-msaa.unit.test.ts +6 -9
  310. package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -9
  311. package/src/__tests__/pipeline-spec.test.ts +16 -177
  312. package/src/__tests__/pipeline.unit.test.ts +154 -1693
  313. package/src/__tests__/point-light-shadow.dawn.test.ts +33 -42
  314. package/src/__tests__/point-light-shadow.unit.test.ts +19 -60
  315. package/src/__tests__/post-process-error-codes.unit.test.ts +4 -1
  316. package/src/__tests__/post-process-params-component.unit.test.ts +1 -1
  317. package/src/__tests__/post-process-params-extract.unit.test.ts +2 -5
  318. package/src/__tests__/postprocess-camera-consistency.test.ts +4 -7
  319. package/src/__tests__/profiler-assembly.integration.test.ts +1 -1
  320. package/src/__tests__/propagate-transforms.dawn.test.ts +12 -11
  321. package/src/__tests__/record-worldid-isolation.test.ts +7 -29
  322. package/src/__tests__/recover-error-exhaustive.test-d.ts +1 -1
  323. package/src/__tests__/render-error-exhaustive.test-d.ts +81 -71
  324. package/src/__tests__/render-feature-assembly.test-d.ts +20 -9
  325. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +8 -6
  326. package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +60 -558
  327. package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +57 -544
  328. package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
  329. package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +40 -248
  330. package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +83 -340
  331. package/src/__tests__/render-feature-recover.integration.test.ts +9 -49
  332. package/src/__tests__/render-feature-runtime-surface.test-d.ts +17 -20
  333. package/src/__tests__/render-schema-consumer.integration.test.ts +20 -13
  334. package/src/__tests__/render-schema-owner-boundary.unit.test.ts +2 -6
  335. package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +5 -5
  336. package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +16 -31
  337. package/src/__tests__/render-system-extract.test.ts +36 -51
  338. package/src/__tests__/render-system-extract.unit.test.ts +360 -0
  339. package/src/__tests__/render-system-fold-bucket.unit.test.ts +3 -5
  340. package/src/__tests__/render-system-fold-fallback.unit.test.ts +6 -3
  341. package/src/__tests__/render-system-fold-material.unit.test.ts +3 -5
  342. package/src/__tests__/render-system-fold-metrics.unit.test.ts +5 -5
  343. package/src/__tests__/render-system-fold-modegate.unit.test.ts +6 -6
  344. package/src/__tests__/render-system-fold.dawn.test.ts +7 -5
  345. package/src/__tests__/render-system-mega.test.ts +292 -190
  346. package/src/__tests__/render-system-owner-split-contract.test.ts +10 -32
  347. package/src/__tests__/render-system-record-multi-material-textureview.test.ts +59 -45
  348. package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +23 -29
  349. package/src/__tests__/render-system-record.test.ts +398 -235
  350. package/src/__tests__/render-system-record.unit.test.ts +25 -26
  351. package/src/__tests__/render-system-skin-bg.unit.test.ts +8 -12
  352. package/src/__tests__/renderer-consumer.test-d.ts +16 -3
  353. package/src/__tests__/renderer-health.unit.test.ts +26 -916
  354. package/src/__tests__/renderer-lifecycle.integration.test.ts +19 -6
  355. package/src/__tests__/renderer-recover.unit.test.ts +49 -1069
  356. package/src/__tests__/renderer-result.test-d.ts +19 -9
  357. package/src/__tests__/renderer-surface.unit.test.ts +3 -5
  358. package/src/__tests__/renderer-test-utils.ts +56 -0
  359. package/src/__tests__/renderer.test-d.ts +59 -0
  360. package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
  361. package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
  362. package/src/__tests__/resolve-depth-only-view.test.ts +1 -1
  363. package/src/__tests__/resolveName-fallback.test.ts +64 -0
  364. package/src/__tests__/resolveName-null-package.test.ts +38 -0
  365. package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
  366. package/src/__tests__/resolveName.test.ts +64 -0
  367. package/src/__tests__/rhi-null-command-flow.unit.test.ts +43 -261
  368. package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +41 -169
  369. package/src/__tests__/roots-to-scene-asset.test.ts +199 -93
  370. package/src/__tests__/roundtrip-primitive.test.ts +351 -0
  371. package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
  372. package/src/__tests__/scene-equirect-roundtrip.test.ts +103 -16
  373. package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
  374. package/src/__tests__/scene-instance-bridge.integration.test.ts +1 -1
  375. package/src/__tests__/scene-instance-component.test.ts +1 -1
  376. package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
  377. package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
  378. package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
  379. package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
  380. package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
  381. package/src/__tests__/serialize-scene-asset.test.ts +219 -22
  382. package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -3
  383. package/src/__tests__/shadow-csm-cascade-loadop.test.ts +37 -17
  384. package/src/__tests__/shadow-csm-component.test.ts +3 -5
  385. package/src/__tests__/shadow-csm-extract.test.ts +2 -100
  386. package/src/__tests__/shadow-csm-orthoz.test.ts +2 -16
  387. package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +19 -14
  388. package/src/__tests__/shadow-csm-tile-consistency.test.ts +32 -26
  389. package/src/__tests__/shadow-csm-ubo.dawn.test.ts +8 -49
  390. package/src/__tests__/shadow-csm-ubo.test.ts +3 -25
  391. package/src/__tests__/shadow-csm-viewport.browser.test.ts +1 -1
  392. package/src/__tests__/shadow-fields-observable.dawn.test.ts +67 -56
  393. package/src/__tests__/shadow-m1.dawn.test.ts +8 -9
  394. package/src/__tests__/shadow-mesh-ssbo-order.test.ts +11 -27
  395. package/src/__tests__/skin-errors.unit.test.ts +1 -1
  396. package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +7 -5
  397. package/src/__tests__/skylight-lazy-projection.test.ts +36 -15
  398. package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +5 -5
  399. package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +47 -64
  400. package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +12 -11
  401. package/src/__tests__/sprite-lit-extract-branch.test.ts +1 -1
  402. package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
  403. package/src/__tests__/ssao-bgl.test.ts +16 -9
  404. package/src/__tests__/ssao-buffers.test.ts +2 -2
  405. package/src/__tests__/ssao-data.test.ts +2 -2
  406. package/src/__tests__/ssao-errors.test.ts +1 -1
  407. package/src/__tests__/ssao-passes.test.ts +64 -392
  408. package/src/__tests__/ssao-pipelines.test.ts +1 -1
  409. package/src/__tests__/ssao-uniform-layout.test.ts +8 -6
  410. package/src/__tests__/stencil-outline-pixel.dawn.test.ts +25 -17
  411. package/src/__tests__/swap-chain-format.unit.test.ts +5 -7
  412. package/src/__tests__/systems.unit.test.ts +536 -1326
  413. package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
  414. package/src/__tests__/text.unit.test.ts +56 -33
  415. package/src/__tests__/tilemap-childed-despawn.test.ts +8 -14
  416. package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +8 -12
  417. package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +2 -1
  418. package/src/__tests__/tilemap-chunk-extract.test.ts +13 -17
  419. package/src/__tests__/tilemap-dirty-rebuild.test.ts +7 -11
  420. package/src/__tests__/tilemap-material-cache.test.ts +8 -13
  421. package/src/__tests__/tilemap-multi-atlas.test.ts +12 -32
  422. package/src/__tests__/tilemap-owner-boundary.unit.test.ts +5 -2
  423. package/src/__tests__/tilemap-region-pack.test.ts +8 -12
  424. package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +8 -12
  425. package/src/__tests__/tilemap-uv-inset.test.ts +11 -14
  426. package/src/__tests__/tilemap-validate.test.ts +1 -1
  427. package/src/__tests__/tileset-asset-validate.test.ts +638 -0
  428. package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
  429. package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +36 -28
  430. package/src/__tests__/transient-fields-collect.test.ts +28 -21
  431. package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
  432. package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +4 -4
  433. package/src/__tests__/variant-selection.unit.test.ts +1 -1
  434. package/src/__tests__/video-extract-bindgroup.dawn.test.ts +89 -136
  435. package/src/__tests__/video-loader-consumption.test.ts +86 -0
  436. package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
  437. package/src/__tests__/view-ubo-layout.browser.test.ts +0 -22
  438. package/src/__tests__/world-entity-key.test.ts +1 -1
  439. package/src/__tests__/world-scene-despawn.test.ts +1 -1
  440. package/src/__tests__/world-scene-instantiate.test.ts +2 -36
  441. package/src/__tests__/world-scene-nested.test.ts +1 -1
  442. package/src/__tests__/world-scene-override.test.ts +1 -1
  443. package/src/backend-selection.ts +69 -0
  444. package/src/collect-scene-asset.ts +28 -23
  445. package/src/components/__tests__/camera.test-d.ts +1 -1
  446. package/src/components/__tests__/camera.test.ts +1 -1
  447. package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
  448. package/src/components/__tests__/tile-layer.test-d.ts +1 -1
  449. package/src/components/__tests__/tile-layer.unit.test.ts +2 -2
  450. package/src/createRenderer.ts +24 -36
  451. package/src/errors/environment.ts +1 -1
  452. package/src/index.ts +47 -113
  453. package/src/renderer-host.ts +33 -0
  454. package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +1 -1
  455. package/src/scene-instances/index.ts +4 -0
  456. package/src/scene-utils/mount-override-fold.ts +3 -7
  457. package/src/systems/__tests__/transparent-sort.bench.ts +3 -3
  458. package/src/systems/sprite-animation-tick.ts +1 -1
  459. package/src/systems/transparent-sort.ts +38 -38
  460. package/src/tilemap-register-validate.ts +4 -4
  461. package/dist/__tests__/bind-group-cache-binding.test.d.ts +0 -2
  462. package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +0 -1
  463. package/dist/__tests__/bind-group-cache-frame.test.d.ts +0 -2
  464. package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +0 -1
  465. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +0 -2
  466. package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +0 -1
  467. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +0 -2
  468. package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +0 -1
  469. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +0 -2
  470. package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +0 -1
  471. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +0 -2
  472. package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +0 -1
  473. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +0 -2
  474. package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +0 -1
  475. package/dist/__tests__/fog-producer-manifest.d.ts +0 -131
  476. package/dist/__tests__/fog-producer-manifest.d.ts.map +0 -1
  477. package/dist/__tests__/fog-producer-pixel-probe.d.ts +0 -42
  478. package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +0 -1
  479. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +0 -2
  480. package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +0 -1
  481. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +0 -2
  482. package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +0 -1
  483. package/dist/__tests__/fog-producer-real-fixture.d.ts +0 -5
  484. package/dist/__tests__/fog-producer-real-fixture.d.ts.map +0 -1
  485. package/dist/__tests__/fog-producer-vfx-effect.d.ts +0 -3
  486. package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +0 -1
  487. package/dist/__tests__/fog-scene-asset.integration.test.d.ts +0 -2
  488. package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +0 -1
  489. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +0 -2
  490. package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +0 -1
  491. package/dist/__tests__/gpu-resource.test.d.ts +0 -2
  492. package/dist/__tests__/gpu-resource.test.d.ts.map +0 -1
  493. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +0 -2
  494. package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +0 -1
  495. package/dist/__tests__/hdrp-buffers.unit.test.d.ts +0 -2
  496. package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +0 -1
  497. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +0 -2
  498. package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +0 -1
  499. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +0 -2
  500. package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +0 -1
  501. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +0 -2
  502. package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +0 -1
  503. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +0 -2
  504. package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +0 -1
  505. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +0 -2
  506. package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +0 -1
  507. package/dist/__tests__/helpers/primitive-world.d.ts +0 -8
  508. package/dist/__tests__/helpers/primitive-world.d.ts.map +0 -1
  509. package/dist/__tests__/helpers/render-asset-port.d.ts +0 -15
  510. package/dist/__tests__/helpers/render-asset-port.d.ts.map +0 -1
  511. package/dist/__tests__/helpers/scene-asset-port.d.ts +0 -9
  512. package/dist/__tests__/helpers/scene-asset-port.d.ts.map +0 -1
  513. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +0 -2
  514. package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +0 -1
  515. package/dist/__tests__/pipeline-layout-selection.test.d.ts +0 -2
  516. package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +0 -1
  517. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +0 -2
  518. package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +0 -1
  519. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +0 -2
  520. package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +0 -1
  521. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +0 -2
  522. package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +0 -1
  523. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +0 -2
  524. package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +0 -1
  525. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +0 -2
  526. package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +0 -1
  527. package/dist/__tests__/shadow-csm-pssm.test.d.ts +0 -2
  528. package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +0 -1
  529. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +0 -2
  530. package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +0 -1
  531. package/dist/__tests__/shadow-csm-viewport.test.d.ts +0 -2
  532. package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +0 -1
  533. package/dist/__tests__/shadow-m2.dawn.test.d.ts +0 -2
  534. package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +0 -1
  535. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +0 -2
  536. package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +0 -1
  537. package/dist/__tests__/shadow-m3-calibrate.d.ts +0 -83
  538. package/dist/__tests__/shadow-m3-calibrate.d.ts.map +0 -1
  539. package/dist/__tests__/shadow-m3.dawn.test.d.ts +0 -2
  540. package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +0 -1
  541. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +0 -2
  542. package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +0 -1
  543. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +0 -2
  544. package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +0 -1
  545. package/dist/__tests__/temporal-off-path.unit.test.d.ts +0 -2
  546. package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +0 -1
  547. package/dist/__tests__/video-cache-regression.unit.test.d.ts +0 -2
  548. package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +0 -1
  549. package/dist/asset-kind.d.ts +0 -4
  550. package/dist/asset-kind.d.ts.map +0 -1
  551. package/dist/errors/sprite-animation.d.ts +0 -3
  552. package/dist/errors/sprite-animation.d.ts.map +0 -1
  553. package/dist/scene-asset-port.d.ts +0 -17
  554. package/dist/scene-asset-port.d.ts.map +0 -1
  555. package/dist/scene-collect-errors.d.ts +0 -22
  556. package/dist/scene-collect-errors.d.ts.map +0 -1
  557. package/dist/shadow-m3-calibrate.d.ts +0 -40
  558. package/dist/shadow-m3-calibrate.d.ts.map +0 -1
  559. package/src/__tests__/bind-group-cache-binding.test.ts +0 -2513
  560. package/src/__tests__/bind-group-cache-frame.test.ts +0 -1511
  561. package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +0 -204
  562. package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +0 -297
  563. package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +0 -271
  564. package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +0 -321
  565. package/src/__tests__/fog-producer-manifest.ts +0 -162
  566. package/src/__tests__/fog-producer-pixel-probe.ts +0 -263
  567. package/src/__tests__/fog-producer-pixel.browser.test.ts +0 -26
  568. package/src/__tests__/fog-producer-pixel.dawn.test.ts +0 -55
  569. package/src/__tests__/fog-producer-real-fixture.ts +0 -805
  570. package/src/__tests__/fog-producer-vfx-effect.ts +0 -272
  571. package/src/__tests__/fog-scene-asset.integration.test.ts +0 -123
  572. package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +0 -207
  573. package/src/__tests__/gpu-resource.test.ts +0 -1206
  574. package/src/__tests__/hdrp-bgl-slots.browser.test.ts +0 -50
  575. package/src/__tests__/hdrp-buffers.unit.test.ts +0 -70
  576. package/src/__tests__/hdrp-execute-filter.unit.test.ts +0 -200
  577. package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +0 -64
  578. package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +0 -139
  579. package/src/__tests__/hdrp-ssao-boundary.test.ts +0 -237
  580. package/src/__tests__/hdrp-ssao-falsification.test.ts +0 -289
  581. package/src/__tests__/helpers/primitive-world.ts +0 -91
  582. package/src/__tests__/helpers/render-asset-port.ts +0 -65
  583. package/src/__tests__/helpers/scene-asset-port.ts +0 -23
  584. package/src/__tests__/material-derived-coordinates.integration.test.ts +0 -100
  585. package/src/__tests__/pipeline-layout-selection.test.ts +0 -298
  586. package/src/__tests__/post-process-reads-narrowing.test-d.ts +0 -52
  587. package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +0 -230
  588. package/src/__tests__/render-feature-zero-feature.browser.test.ts +0 -152
  589. package/src/__tests__/render-pipeline-trivial.dawn.test.ts +0 -525
  590. package/src/__tests__/shadow-csm-caster-membership.test.ts +0 -232
  591. package/src/__tests__/shadow-csm-pssm.test.ts +0 -142
  592. package/src/__tests__/shadow-csm-temporal.browser.test.ts +0 -145
  593. package/src/__tests__/shadow-csm-viewport.test.ts +0 -74
  594. package/src/__tests__/shadow-m2.dawn.test.ts +0 -394
  595. package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +0 -248
  596. package/src/__tests__/shadow-m3-calibrate.ts +0 -203
  597. package/src/__tests__/shadow-m3.dawn.test.ts +0 -288
  598. package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +0 -264
  599. package/src/__tests__/shadow-quality-metrics.dawn.test.ts +0 -324
  600. package/src/__tests__/temporal-off-path.unit.test.ts +0 -69
  601. package/src/__tests__/video-cache-regression.unit.test.ts +0 -186
  602. package/src/asset-kind.ts +0 -7
  603. package/src/errors/sprite-animation.ts +0 -5
  604. package/src/scene-asset-port.ts +0 -32
  605. package/src/scene-collect-errors.ts +0 -30
  606. package/src/shadow-m3-calibrate.ts +0 -171
@@ -21,15 +21,11 @@
21
21
  // requirements AC-09
22
22
 
23
23
  import { World } from '@forgeax/engine-ecs';
24
- import type { ExtractedFrame } from '@forgeax/engine-render/internal';
25
- import {
26
- Camera,
27
- DirectionalLight,
28
- extractFrame,
29
- prepareExtractContext,
30
- } from '@forgeax/engine-render/internal';
24
+ import { Camera, DirectionalLight } from '@forgeax/engine-render';
31
25
  import { Transform } from '@forgeax/engine-scene';
32
26
  import { describe, expect, it } from 'vitest';
27
+ import type { ExtractedFrame } from '../../../render/src/render-system-extract';
28
+ import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
33
29
 
34
30
  // ── Helpers ─────────────────────────────────────────────────────────────────
35
31
 
@@ -17,29 +17,33 @@
17
17
  // requirements AC-04/AC-05/AC-06
18
18
 
19
19
  import { World } from '@forgeax/engine-ecs';
20
+ import { Transform } from '@forgeax/engine-scene';
21
+ import { describe, expect, it } from 'vitest';
22
+ import {
23
+ Camera,
24
+ DirectionalLight,
25
+ PostProcessParams,
26
+ SkyboxBackground,
27
+ Skylight,
28
+ SpotLight,
29
+ } from '../../../render/src/components';
30
+ import type { CameraSnapshot } from '../../../render/src/render-contract';
20
31
  import type {
21
- CameraSnapshot,
22
32
  DirectionalLightSnapshot,
23
33
  DispatchEntry,
24
34
  ExtractedFrame,
25
35
  ExtractedLights,
26
36
  PointLightSnapshot,
27
37
  RenderableSnapshot,
38
+ SkyboxSnapshot,
39
+ SkylightSnapshot,
28
40
  SpotLightSnapshot,
29
- } from '@forgeax/engine-render/internal';
41
+ } from '../../../render/src/render-system-extract';
30
42
  import {
31
- Camera,
32
- DirectionalLight,
33
43
  extractFrame,
34
44
  extractFrames,
35
- PostProcessParams,
36
45
  prepareExtractContext,
37
- SkyboxBackground,
38
- Skylight,
39
- SpotLight,
40
- } from '@forgeax/engine-render/internal';
41
- import { Transform } from '@forgeax/engine-scene';
42
- import { describe, expect, it } from 'vitest';
46
+ } from '../../../render/src/render-system-extract';
43
47
 
44
48
  // ── Helpers ─────────────────────────────────────────────────────────────────
45
49
 
@@ -135,7 +139,10 @@ function simulateMerge(
135
139
  lights: ExtractedLights;
136
140
  renderables: RenderableSnapshot[];
137
141
  dispatch: DispatchEntry[];
138
- environment: ExtractedFrame['environment'];
142
+ skylight: SkylightSnapshot | undefined;
143
+ skylightCount: number;
144
+ skybox: SkyboxSnapshot | undefined;
145
+ skyboxCount: number;
139
146
  frustumStats: { culled: number; total: number };
140
147
  postProcessParams: Map<string, Uint8Array>;
141
148
  } {
@@ -215,7 +222,10 @@ function simulateMerge(
215
222
  // AC-05: singletons from owner world only
216
223
  // biome-ignore lint/style/noNonNullAssertion: ownerIndex is validated, frames is dense
217
224
  const ownerFrame = frames[ownerIndex]!;
218
- const environment = ownerFrame.environment;
225
+ const skylight = ownerFrame.skylight;
226
+ const skylightCount = ownerFrame.skylightCount;
227
+ const skybox = ownerFrame.skybox;
228
+ const skyboxCount = ownerFrame.skyboxCount;
219
229
 
220
230
  // AC-06: cameras only from owner world
221
231
  const cameras = [...ownerFrame.cameras];
@@ -247,7 +257,10 @@ function simulateMerge(
247
257
  lights,
248
258
  renderables,
249
259
  dispatch,
250
- environment,
260
+ skylight,
261
+ skylightCount,
262
+ skybox,
263
+ skyboxCount,
251
264
  frustumStats,
252
265
  postProcessParams,
253
266
  };
@@ -431,13 +444,13 @@ describe('extractFrames merge semantics (m2-t1, AC-04/05/06)', () => {
431
444
 
432
445
  // owner=0 (worldA)
433
446
  const merged = simulateMerge([frameA, frameB], 0);
434
- expect(merged.environment.kind).toBe('none');
435
- expect(merged.environment.skylightCount).toBe(1);
447
+ expect(merged.skylight).toBeDefined();
448
+ expect(merged.skylightCount).toBe(1);
436
449
 
437
450
  // owner=1 (worldB) — worldB has no skylight
438
451
  const merged2 = simulateMerge([frameA, frameB], 1);
439
- expect(merged2.environment.kind).toBe('none');
440
- expect(merged2.environment.skylightCount).toBe(0);
452
+ expect(merged2.skylight).toBeUndefined();
453
+ expect(merged2.skylightCount).toBe(0);
441
454
  });
442
455
 
443
456
  it('AC-05: skybox is taken from owner world only, non-owner ignored', () => {
@@ -448,12 +461,12 @@ describe('extractFrames merge semantics (m2-t1, AC-04/05/06)', () => {
448
461
  const frameB = extractFrame(worldB as World, prepareExtractContext(worldB as World));
449
462
 
450
463
  const merged = simulateMerge([frameA, frameB], 0);
451
- expect(merged.environment.kind).toBe('none');
452
- expect(merged.environment.skyboxCount).toBe(1);
464
+ expect(merged.skybox).toBeDefined();
465
+ expect(merged.skyboxCount).toBe(1);
453
466
 
454
467
  const merged2 = simulateMerge([frameA, frameB], 1);
455
- expect(merged2.environment.kind).toBe('none');
456
- expect(merged2.environment.skyboxCount).toBe(0);
468
+ expect(merged2.skybox).toBeUndefined();
469
+ expect(merged2.skyboxCount).toBe(0);
457
470
  });
458
471
 
459
472
  it('AC-05: postProcessParams from non-owner world are ignored', () => {
@@ -13,14 +13,15 @@
13
13
  // through.
14
14
  //
15
15
  // Scope of the gate — the three USER-REGION texture fields only:
16
- // baseColorTexture / metallicRoughnessTexture / normalTexture /
17
- // specularTintTexture / emissiveTexture / occlusionTexture
16
+ // baseColorTexture / metallicRoughnessTexture / normalTexture
18
17
  // These are the fields `derive(default-standard-pbr).textureFieldNames`
19
18
  // produces and that w7/w8 route through iteration.
20
19
  //
21
20
  // Deliberately NOT gated (legitimate residual naming):
22
- // - engine-owned IBL bindings: these remain outside the material schema and
23
- // are assembled by the injection path; material textures are not exempt.
21
+ // - emissiveTexture / occlusionTexture: these live in the engine-injection
22
+ // LIGHTMAP region (appendInjection 'lightmap'), are NOT in any paramSchema
23
+ // textureFieldNames set, and are assembled by the injection path — naming
24
+ // them there is the engine-managed region, not user-region hardcoding.
24
25
  // - USER_REGION_TEXTURE_FIELDS in derive-paramschema.ts: the 3-field
25
26
  // register-time under-declaration validator (charter P3 safety net from
26
27
  // the 4.3 blending regression). Orthogonal to binding; lives in a
@@ -44,9 +45,6 @@ const USER_REGION_FIELDS = [
44
45
  'baseColorTexture',
45
46
  'metallicRoughnessTexture',
46
47
  'normalTexture',
47
- 'specularTintTexture',
48
- 'emissiveTexture',
49
- 'occlusionTexture',
50
48
  ] as const;
51
49
 
52
50
  /** Strip `//` line comments and block comments so commented prose never trips the gate. */
@@ -70,15 +68,6 @@ describe('extract/record have no per-field hardcoding of the user-region texture
70
68
  }
71
69
  });
72
70
 
73
- it('extract derives coordinate fields from the effective schema', () => {
74
- const src = stripComments(readFileSync(EXTRACT_SRC, 'utf8'));
75
- // The runtime owner may expose the effective schema through either the
76
- // admitted projection or the compatibility-derived interface. Keep the
77
- // gate about the contract (iterate the projection's texture set), not an
78
- // implementation spelling that would reject the owner path.
79
- expect(src).toMatch(/(?:derivedMaterialInterface|derivedInterface)\.textureFieldNames/);
80
- });
81
-
82
71
  it('record does not bind user-region textures via per-field `submeshMaterial.<field>` reads', () => {
83
72
  const src = stripComments(readFileSync(RECORD_SRC, 'utf8'));
84
73
  for (const field of USER_REGION_FIELDS) {
@@ -0,0 +1,322 @@
1
+ // feat-20260611-fox-skinning-vertex-attribute-chain M4 / w19 (AC-07).
2
+ //
3
+ // Asserts the bidirectional Skin <-> pbr-skin material fail-fast added to
4
+ // `render-system-extract.ts` (w17 / D-5):
5
+ //
6
+ // (a) Skin component on entity + first-pass shader != forgeax::pbr-skin
7
+ // -> _routeError fires `SkinMaterialMismatchError` (.code
8
+ // === 'skin-material-mismatch') and the entity is skipped (continue),
9
+ // leaving sibling entities in the same frame to render normally.
10
+ //
11
+ // (b) First-pass shader === forgeax::pbr-skin + mesh.attributes missing
12
+ // skinIndex / skinWeight -> _routeError fires
13
+ // `MaterialSkinAttrMissingError` (.code === 'material-skin-attr-missing')
14
+ // and the entity is skipped.
15
+ //
16
+ // (c) Skin + pbr-skin material + 6-attribute mesh -> NO error routed
17
+ // (positive control).
18
+ //
19
+ // Plan-strategy D-5: extract uses `_routeError` + `continue` (one entity's
20
+ // misconfiguration must NOT abort the whole frame's draw list); this test
21
+ // also asserts that a sibling unlit entity in the same frame still extracts
22
+ // to a renderable entry alongside the bad-skin one.
23
+
24
+ import { AssetRegistry } from '@forgeax/engine-assets-runtime';
25
+ import { World } from '@forgeax/engine-ecs';
26
+ import { Camera, MeshFilter, MeshRenderer } from '@forgeax/engine-render';
27
+ import { propagateTransforms, Transform } from '@forgeax/engine-scene';
28
+ import type { ShaderRegistry } from '@forgeax/engine-shader';
29
+ import { Skin } from '@forgeax/engine-skinning';
30
+ import type { Handle, MaterialAsset, MeshAsset, SkeletonAsset } from '@forgeax/engine-types';
31
+ import { afterEach, describe, expect, it, vi } from 'vitest';
32
+ import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
33
+ import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
34
+
35
+ afterEach(() => {
36
+ vi.restoreAllMocks();
37
+ });
38
+
39
+ // ── helpers ──────────────────────────────────────────────────────────────
40
+
41
+ const UNIT_AABB = new Float32Array([-1, -1, -1, 1, 1, 1]);
42
+ // Unskinned: 12 floats / vertex × 3 vertices = 36 (position vec3 + normal vec3 + uv vec2 + tangent vec4).
43
+ const TRIANGLE_VERTICES = new Float32Array([
44
+ 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, 1, 0,
45
+ 0, 0, 0,
46
+ ]);
47
+ // Skinned: 18 floats / vertex × 3 vertices = 54 (12 base + skinIndex u16x4 packed in 2 floats at slots 12-13 + skinWeight vec4 at slots 14-17).
48
+ // validateMeshPayload (asset-registry feat: validateMeshPayload skin-aware stride) rejects skin meshes at the 12F stride.
49
+ // Trailing 6 floats per vertex are placeholder (extract path reads attributes.skinIndex/Weight directly, not from interleaved buffer).
50
+ const TRIANGLE_VERTICES_SKINNED = new Float32Array([
51
+ // v0: pos (0,0,0) | normal (0,0,1) | uv (0,0) | tangent (0,0,0,1) | skin (0,0) | weight (0,0,0,0)
52
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
53
+ // v1: pos (1,0,0) | normal (0,0,1) | uv (1,0) | tangent (0,0,0,1) | skin (0,0) | weight (0,0,0,0)
54
+ 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
55
+ // v2: pos (0,1,0) | normal (0,0,1) | uv (0,1) | tangent (0,0,0,1) | skin (0,0) | weight (0,0,0,0)
56
+ 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
57
+ ]);
58
+ const TRIANGLE_POSITIONS = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
59
+
60
+ function makeAssetRegistry(): AssetRegistry {
61
+ const shaderRegistry: ShaderRegistry = makeMockShaderRegistry();
62
+ // The shared mock registry omits forgeax::pbr-skin (it is the
63
+ // engine-shipped skin shader registered at boot time elsewhere). The
64
+ // mismatch path under test needs MaterialAsset register-time validation
65
+ // to accept first-pass shader === 'forgeax::pbr-skin', so we register a
66
+ // minimal entry here. paramSchema mirrors the standard PBR family head
67
+ // (baseColor / metallic / roughness) since this test does not exercise
68
+ // skin-specific param overlay.
69
+ shaderRegistry.installMaterialArtifact('forgeax::pbr-skin', {
70
+ source: 'fn main() {}',
71
+ paramSchema: [
72
+ { name: 'baseColor', type: 'color', default: [1.0, 1.0, 1.0, 1.0] },
73
+ { name: 'metallic', type: 'f32', default: 0.0 },
74
+ { name: 'roughness', type: 'f32', default: 0.5 },
75
+ ],
76
+ });
77
+ return new AssetRegistry(shaderRegistry);
78
+ }
79
+
80
+ function registerSkinnedMesh(world: World): Handle<'MeshAsset', 'shared'> {
81
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', {
82
+ kind: 'mesh',
83
+ vertices: TRIANGLE_VERTICES_SKINNED,
84
+ indices: new Uint16Array([0, 1, 2]),
85
+ attributes: {
86
+ position: TRIANGLE_POSITIONS,
87
+ // pbr-skin requires skinIndex + skinWeight in attributes; values are
88
+ // irrelevant here -- key presence is what extract reads.
89
+ skinIndex: new Uint16Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
90
+ skinWeight: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]),
91
+ },
92
+ aabb: UNIT_AABB,
93
+ submeshes: [
94
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list', materialSlot: 0 },
95
+ ],
96
+
97
+ materialSlots: [{ slotName: 'Default' }],
98
+ });
99
+ }
100
+
101
+ function registerUnskinnedMesh(world: World): Handle<'MeshAsset', 'shared'> {
102
+ return world.allocSharedRef<'MeshAsset', MeshAsset>('MeshAsset', {
103
+ kind: 'mesh',
104
+ vertices: TRIANGLE_VERTICES,
105
+ indices: new Uint16Array([0, 1, 2]),
106
+ attributes: { position: TRIANGLE_POSITIONS },
107
+ aabb: UNIT_AABB,
108
+ submeshes: [
109
+ { indexOffset: 0, indexCount: 3, vertexCount: 3, topology: 'triangle-list', materialSlot: 0 },
110
+ ],
111
+
112
+ materialSlots: [{ slotName: 'Default' }],
113
+ });
114
+ }
115
+
116
+ function registerPbrSkinMaterial(world: World): Handle<'MaterialAsset', 'shared'> {
117
+ return world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
118
+ kind: 'material',
119
+ passes: [
120
+ {
121
+ name: 'Forward',
122
+ program: { module: 'forgeax::pbr-skin' },
123
+ renderState: { tags: { LightMode: 'Forward' }, queue: 2000 },
124
+ },
125
+ ],
126
+ values: { baseColor: [1, 1, 1] },
127
+ });
128
+ }
129
+
130
+ function registerUnlitMaterial(world: World): Handle<'MaterialAsset', 'shared'> {
131
+ return world.allocSharedRef<'MaterialAsset', MaterialAsset>('MaterialAsset', {
132
+ kind: 'material',
133
+ passes: [
134
+ {
135
+ name: 'Forward',
136
+ program: { module: 'forgeax::default-unlit' },
137
+ renderState: { tags: { LightMode: 'Forward' }, queue: 2000 },
138
+ },
139
+ ],
140
+ values: { baseColor: [1, 1, 1] },
141
+ });
142
+ }
143
+
144
+ function registerSkeleton(world: World): Handle<'SkeletonAsset', 'shared'> {
145
+ return world.allocSharedRef<'SkeletonAsset', SkeletonAsset>('SkeletonAsset', {
146
+ kind: 'skeleton',
147
+ inverseBindMatrices: new Float32Array(16),
148
+ jointCount: 1,
149
+ });
150
+ }
151
+
152
+ function spawnCamera(world: World): void {
153
+ world
154
+ .spawn(
155
+ {
156
+ component: Transform,
157
+ data: {
158
+ pos: [0, 0, 5],
159
+ quat: [0, 0, 0, 1],
160
+ scale: [1, 1, 1],
161
+ },
162
+ },
163
+ {
164
+ component: Camera,
165
+ data: {
166
+ fov: Math.PI / 4,
167
+ aspect: 1,
168
+ near: 0.1,
169
+ far: 100,
170
+ projection: 0,
171
+ left: -1,
172
+ right: 1,
173
+ bottom: -1,
174
+ top: 1,
175
+ },
176
+ },
177
+ )
178
+ .unwrap();
179
+ }
180
+
181
+ const IDENTITY_TRANSFORM = {
182
+ pos: [0, 0, 0],
183
+ quat: [0, 0, 0, 1],
184
+ scale: [1, 1, 1],
185
+ } as const;
186
+
187
+ function spawnRenderable(
188
+ world: World,
189
+ meshHandle: Handle<'MeshAsset', 'shared'>,
190
+ matHandle: Handle<'MaterialAsset', 'shared'>,
191
+ ): void {
192
+ world
193
+ .spawn(
194
+ { component: Transform, data: IDENTITY_TRANSFORM },
195
+ { component: MeshFilter, data: { assetHandle: meshHandle } },
196
+ { component: MeshRenderer, data: { materials: [matHandle] } },
197
+ )
198
+ .unwrap();
199
+ }
200
+
201
+ function spawnSkinnedRenderable(
202
+ world: World,
203
+ meshHandle: Handle<'MeshAsset', 'shared'>,
204
+ matHandle: Handle<'MaterialAsset', 'shared'>,
205
+ skeletonHandle: Handle<'SkeletonAsset', 'shared'>,
206
+ ): void {
207
+ // feat-20260612 M2 / m2-6: Skin.joints[] now validated against
208
+ // SkeletonAsset.jointCount (=1 here) at extract time; spawn one joint
209
+ // Entity bearing Transform so the count matches and the new
210
+ // `joint-count-mismatch` / `joint-entity-dangling` checks pass for the
211
+ // bidirectional Skin <-> pbr-skin mismatch happy path (test (c)).
212
+ const jointEntity = world.spawn({ component: Transform, data: IDENTITY_TRANSFORM }).unwrap();
213
+ world
214
+ .spawn(
215
+ { component: Transform, data: IDENTITY_TRANSFORM },
216
+ { component: MeshFilter, data: { assetHandle: meshHandle } },
217
+ { component: MeshRenderer, data: { materials: [matHandle] } },
218
+ {
219
+ component: Skin,
220
+ data: {
221
+ skeleton: skeletonHandle,
222
+ joints: new Uint32Array([jointEntity as unknown as number]),
223
+ },
224
+ },
225
+ )
226
+ .unwrap();
227
+ }
228
+
229
+ // ── tests ────────────────────────────────────────────────────────────────
230
+
231
+ describe('render-system-extract Skin / pbr-skin mismatch (AC-07 / w19)', () => {
232
+ it('(a) Skin + non-pbr-skin material -> SkinMaterialMismatchError routed + entity skipped', () => {
233
+ const world = new World();
234
+ const assets = makeAssetRegistry();
235
+ const meshHandle = registerSkinnedMesh(world);
236
+ const unlitMatHandle = registerUnlitMaterial(world);
237
+ const skeletonHandle = registerSkeleton(world);
238
+ spawnCamera(world);
239
+ spawnSkinnedRenderable(world, meshHandle, unlitMatHandle, skeletonHandle);
240
+ propagateTransforms(world);
241
+
242
+ const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
243
+
244
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
245
+
246
+ expect(errorSpy).toHaveBeenCalledTimes(1);
247
+ const [, errArg] = errorSpy.mock.calls[0] ?? [];
248
+ expect((errArg as { code: string }).code).toBe('skin-material-mismatch');
249
+ expect((errArg as { detail: { actualShader: string | undefined } }).detail.actualShader).toBe(
250
+ 'forgeax::default-unlit',
251
+ );
252
+ // entity skipped -> no renderable entry
253
+ expect(frame.renderables).toHaveLength(0);
254
+ });
255
+
256
+ it('(b) pbr-skin material + non-skin mesh -> MaterialSkinAttrMissingError routed + entity skipped', () => {
257
+ const world = new World();
258
+ const assets = makeAssetRegistry();
259
+ const meshHandle = registerUnskinnedMesh(world);
260
+ const skinMatHandle = registerPbrSkinMaterial(world);
261
+ spawnCamera(world);
262
+ spawnRenderable(world, meshHandle, skinMatHandle);
263
+ propagateTransforms(world);
264
+
265
+ const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
266
+
267
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
268
+
269
+ expect(errorSpy).toHaveBeenCalledTimes(1);
270
+ const [, errArg] = errorSpy.mock.calls[0] ?? [];
271
+ expect((errArg as { code: string }).code).toBe('material-skin-attr-missing');
272
+ expect(
273
+ (errArg as { detail: { missing: 'skinIndex' | 'skinWeight' | 'both' } }).detail.missing,
274
+ ).toBe('both');
275
+
276
+ expect(frame.renderables).toHaveLength(0);
277
+ });
278
+
279
+ it('(c) Skin + pbr-skin material + skinned mesh -> no error routed', () => {
280
+ const world = new World();
281
+ const assets = makeAssetRegistry();
282
+ const meshHandle = registerSkinnedMesh(world);
283
+ const skinMatHandle = registerPbrSkinMaterial(world);
284
+ const skeletonHandle = registerSkeleton(world);
285
+ spawnCamera(world);
286
+ spawnSkinnedRenderable(world, meshHandle, skinMatHandle, skeletonHandle);
287
+ propagateTransforms(world);
288
+
289
+ const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
290
+
291
+ extractFrame(world, prepareExtractContext(world, { assets }));
292
+
293
+ expect(errorSpy).not.toHaveBeenCalled();
294
+ });
295
+
296
+ it('(d) D-5 continue semantics: bad-skin entity skipped does NOT abort sibling extract', () => {
297
+ const world = new World();
298
+ const assets = makeAssetRegistry();
299
+ const skinnedMesh = registerSkinnedMesh(world);
300
+ const unskinnedMesh = registerUnskinnedMesh(world);
301
+ const unlitMat = registerUnlitMaterial(world);
302
+ const skeletonHandle = registerSkeleton(world);
303
+ spawnCamera(world);
304
+ // bad-skin entity (Skin + unlit material) -> mismatch -> skipped
305
+ spawnSkinnedRenderable(world, skinnedMesh, unlitMat, skeletonHandle);
306
+ // sibling well-formed entity (no Skin, unlit material, unskinned mesh)
307
+ spawnRenderable(world, unskinnedMesh, unlitMat);
308
+ propagateTransforms(world);
309
+
310
+ const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
311
+
312
+ const frame = extractFrame(world, prepareExtractContext(world, { assets }));
313
+
314
+ // exactly one mismatch error (the bad-skin entity), and the sibling
315
+ // emerges as a renderable -- proving `continue` did not turn into
316
+ // `return Result.err` for the whole frame.
317
+ expect(errorSpy).toHaveBeenCalledTimes(1);
318
+ const [, errArg] = errorSpy.mock.calls[0] ?? [];
319
+ expect((errArg as { code: string }).code).toBe('skin-material-mismatch');
320
+ expect(frame.renderables.length).toBeGreaterThanOrEqual(1);
321
+ });
322
+ });